MongoDB and CakePHP Model associations - cakephp

I'm trying to make a Match model which includes the players lined up during that match. So each Match hasMany Players and each Player hasmany Matches.
match = {
'_id' : ObjectID('978tqwbi9873gofiu'),
'home' : 'Argentina',
'away' : 'Brazil',
'lineup-home' : [
{'name' : 'Lionel Messi',
'goals' : '2',
'timeon' : 30
},
{'name' : 'Diego Maradonna',
'goals' : '0',
'timeon' : 0
},
{'name' : 'Sergio Aguero',
'goals' : '0',
'timeon' : 0
}
]
}
How do I add these 'lineup-home' relations in my CakePHP model to work with my mongoDB? This is how my model looks like...
class Match extends AppModel {
//var $useDbConfig = 'mongo';
var $mongoSchema = array(
'home' => array('type' => 'string'),
'away' => array('type' => 'string'),
'lineup-home' => ???
);
}
Thank you.

I think that using 'lineup-home' => 'array' will do the trick..

And how about
var $mongoSchema = array(
'home' => array('type' => 'string'),
'away' => array('type' => 'string'),
'lineup-home' => array(
'name' => array('type' => 'string'),
'goals' => array('type' => 'string'),
'timeon' => array('type' => 'integer'),
)
);

You can use this schema:
var $mongoSchema = array(
'home' => array('type' => 'string'),
'away' => array('type' => 'string'),
'lineup-home' => array(
array(
'name' => array('type' => 'string'),
'goals' => array('type' => 'string'),
'timeon' => array('type' => 'integer'),
)
)
);

Related

need to change field value before insert it into database using helper form

I create a Helper list with my database, to pu content in field "cont" i use TinyMCE, but whene i write value into db html element not stores, how i can write my field with html code?
if i use db class of prestashop i can use htmlentities function to store my data, but I dont understand how to use this in my fields_form array
Db::getInstance()->autoExecute(_DB_PREFIX_.'pdf_files', array(
'content' => pSQL(htmlentities($content))
),
'INSERT');
this code works just like i want, in my code, I don't realy know where i can use
htmlentities($content)
here is my object model and my controller
<?php
class PdfData extends ObjectModel{
public $id;
public $name;
public $cont;
public $head_1;
public $head_2;
public $head_3;
public $head_4;
public $head_5;
public $inst;
public $facebook;
/**
* #see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'pdf_files',
'primary' => 'id',
'fields' => array(
'name' => array(
'type' => 'varchar',
'validate' => 'isGenericName',
'required' => true,
'class' => 'lg'
),
'head_1' => array(
'type' => 'varchar',
'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'head_2' => array(
'type' => 'varchar',
'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'head_3' => array(
'type' => 'varchar',
'value' => 'lal',
'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'head_4' => array(
'type' => 'varchar',
'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'head_5' => array(
'type' => 'varchar',
'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'inst' => array(
'type' => 'bool',
//'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'facebook' => array(
'type' => 'bool',
//'validate' => 'isGenericName',
'required' => false,
'class' => 'lg'
),
'cont' => array(
'type' => 'text',
'validate' => 'isString',
'required' => false,
'class' => 'lg'
),
),
);
}
class PdfListController extends ModuleAdminController{
const CONTROLLER_NAME = 'PdfList';
public $displayName = 'PDFer';
public function __construct(){
$this->bootstrap = true;
$this->className = 'PdfData';
$this->table = 'pdf_files';
//Tools::getValue('id_product');
$this->fields_list = array(
'id' => array(
'title' => 'ID',
'width' => 'auto',
'type' => 'int'
),
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'type' => 'varchar'
),
'cont'=>array(
'title' => $this->l('content'),
'width' => 'auto',
'type' => 'varchar'
)
);
$this->identifier = 'id';
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'confirm' => $this->l('Delete selected items?')
)
);
parent::__construct();
$this->callAction();
}
private function callAction() {
$actionName = 'process' . ucfirst(trim($_GET['action']));
if(method_exists($this, $actionName)) {
$this->$actionName();
}
}
public function renderList()
{
$this->addRowAction('download');
$this->addRowAction('delete');
$this->addRowAction('edit');
return parent::renderList();
}
public function processDelete()
{
$sql= "DELETE FROM `"._DB_PREFIX_."pdf_files` WHERE `ps_pdf_files`.`id` = ". Tools::getValue('id');
$return = Db::getInstance()->execute($sql);
return $return;
}
public function processDownload()
{
//var_dump(Configuration::get(pdfer::HEAD_3));die;
require_once _PS_MODULE_DIR_ . 'pdfer/classes/pdf/HTMLTemplatePdf.php';
$sql = "SELECT * FROM "._DB_PREFIX_."pdf_files WHERE id = " . Tools::getValue('id');
$pdf = new stdClass();
$pdfData = Db::getInstance()->getRow($sql);
$pdf->cont = html_entity_decode($pdfData["cont"]);
$pdf->name = $pdfData["name"];
$pdf->head_1 = $pdfData["head_1"];
$pdf->head_2 = $pdfData["head_2"];
$pdf->head_3 = $pdfData["head_3"];
$pdf->head_4 = $pdfData["head_4"];
$pdf->head_5 = $pdfData["head_5"];
//$pdf->header = html_entity_decode($pdfData["head"]);
$pdf->path_logo = _PS_MODULE_DIR_.'pdfer/views/templates/images/header_logo.jpg';
$pdf->path_footer = _PS_MODULE_DIR_.'pdfer/views/templates/images/footer_signature.jpg';
$pdf->path_facebook = _PS_MODULE_DIR_.'pdfer/views/templates/images/facebook.jpg';
$pdf->path_inst = _PS_MODULE_DIR_.'pdfer/views/templates/images/inst.jpg';
$pdf->include_inst = (string)Configuration::get(pdfer::CHECK_IMAGE_INST);
$pdf->include_facebook = (string)Configuration::get(pdfer::CHECK_IMAGE_FACEBOOK);
$pdfGen = new PDF($pdf, 'Pdf', $this->context->smarty);
$content = $pdfGen->render(false);
header("ContentType: application/pdf");
header("Content-disposition: attachment; filename=\"$pdf->name.pdf\"");
header("Content-Length: " . strlen($content));
echo $content;
exit;
}
public function displayDownloadLink($token = null, $id, $name = null)
{
$tpl = $this->createTemplate('helpers/list/list_action_view.tpl');
if (!array_key_exists('Download', self::$cache_lang))
self::$cache_lang['Download'] = $this->l('Download');
$tpl->assign(array(
'href' => static::$currentIndex .'&'.$this->identifier.'='.$id.'&action=download&'.$this->table.'&token='.($token != null ? $token : $this->token),
'action' => self::$cache_lang['Download'],
'id' => $id
));
return $tpl->fetch();
}
/**
* #return string
*/
public function renderForm() {
// Building the Add/Edit form
$this->fields_value['head_1'] = (string)Configuration::get(pdfer::HEAD_1);
$this->fields_value['head_2'] = (string)Configuration::get(pdfer::HEAD_2);
$this->fields_value['head_3'] = (string)Configuration::get(pdfer::HEAD_3);
$this->fields_value['head_4'] = (string)Configuration::get(pdfer::HEAD_4);
$this->fields_value['head_5'] = (string)Configuration::get(pdfer::HEAD_5);
$this->fields_form = array(
'tinymce' => true,
'legend' => array(
'title' => $this->l('New Pdf')
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'class' => 'lg',
'required' => true,
'desc' => $this->l('adadada'),
),
array(
'type' => 'textarea',
'label' => $this->l('Content'),
'name' => 'cont',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'head_1',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'head_2',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'head_3',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'head_4',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'head_5',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'inst',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
array(
'type' => 'hidden',
'label' => $this->l('Content'),
'name' => 'facebook',
//'class' => 'lg',
'required' => false,
'autoload_rte' => true,
),
),
'submit' => array(
'title' => $this->l('Save'),
//'class' => 'button'
)
);
return parent::renderForm();
}
}
here's picture, in first i enter some text, 2 i edit, but there is text only
You should not be using pSQL(htmlentities($content)) to insert content to the database table.
Tye replacing it with Tools::htmlentitiesUTF8($content) while saving HTML content and use Tools::htmlentitiesDecodeUTF8($content) when you extract data from the database.

CakePHP find remove fields or recursive find

I'm trying to slim down my finds queries, by specifying which fields to use. I don't understand how I can specify specific fields for my HABTM fields.
This is my find:
$lastviewed = $this->Lastviewedproduct->find('all', array(
'fields' => array(
'Lastviewedproduct.id', 'Lastviewedproduct.sessionid', 'Lastviewedproduct.product_id',
'Product.id', 'Product.name', 'Product.slug', 'Product.price',
//'Category.id',
//'Mediafile.*',
),
'conditions' => array(
'Lastviewedproduct.status' => 'active',
'Lastviewedproduct.sessionid' => $this->Session->read('Companyname.sessionid'),
'Product.hidden_on_site' => 0,
'Product.visibility' => 1,
'Product.status' => 'active',
),
'order' => 'Lastviewedproduct.modified DESC',
'limit' => 5,
'recursive' => 2,
));
This is what it returns:
(int) 2 => array(
'Lastviewedproduct' => array(
'id' => '97',
'sessionid' => '14035312318244955',
'product_id' => '2'
),
'Product' => array(
'id' => '2',
'name' => 'blokhut 2',
'slug' => 'blokhut-2',
'price' => '200.00',
'Category' => array(
(int) 0 => array(
'id' => '218',
'zosomodule_id' => '25',
'user_add_id' => '0',
'user_update_id' => '0',
'created' => '2013-11-27 10:00:00',
'modified' => '2013-11-27 10:00:00',
'status' => 'active',
'visibility' => true,
'parent_id' => '2',
'shipment_id' => '1',
'name' => 'Metalen Tuinbergingen ',
'slug' => 'metalen-tuinbergingen-',
'pagetitle' => 'Metalen Tuinbergingen ',
'content' => '<p class="p1"><span class="s1">Metalen tuinbergingen zijn een praktische en kwalitatieve oplossing voor meer bergruimte in uw tuin. Wij hebben diverse merken metalen bergingen zoals </span><span class="s2">Biohort</span><span class="s1"> en </span><span class="s2">Yardmaster</span><span class="s1">. Hier hebben wij tevens ook tuinkasten en opbergboxen van.</span></p>
<p class="p1"><span class="s1"><br /></span></p>
<p class="p1"><span class="s1">Mocht u op zoek zijn naar andere varianten tuinbergingen, bekijk dan ons gehele assortiment </span><span class="s2">tuinbergingen.</span></p>',
'metatitle' => 'Metalen tuinbergingen',
'metadescription' => null,
'discountoffer' => false,
'discount_normal' => '0.00',
'discount_max' => '0.00',
'discount_ideal' => '0.00',
'cost_rembours' => '0.00',
'in_mainmenu' => true,
'hide_sidebar' => false,
'show_block' => true,
'sort_order' => '0',
'ProductsCategory' => array(
'id' => '2',
'created' => '2014-01-01 10:00:00',
'modified' => '2014-01-01 10:00:00',
'product_id' => '2',
'category_id' => '218'
)
)
),
'Mediafile' => array()
)
),
I don't want all these Category fields, but only Category.id, Category.name and Category.slug for example. How do i say that in my find? As you can see I tried adding Category.id in my fields array, but then I get an error. I read something about containable, but I didn't get that working and I don't know if that is the solution.
Thanks in advance for your help!
You can use ContainableBehavior for this task. You should write something like this:
1 attach behavior
permanent
class Lastviewedproduct extends AppModel {
public $actsAs = array('Containable');
....
}
on demand
$this->Lastviewedproduct->Behaviors->load('Containable');
2 specify fields
$this->Lastviewedproduct->find('all', array(
'contain' => array(
'Product' => array(
'Category' => array(
'fields' => array('id','name','slug')
),
),
'Mediafile'
)
));
Add field parameter with relation ship where you give relationship to Category MODEL
public $hasMany = array(
'Category' => array(
'className' => 'Category',
'fields' => array('Category.id','Category.name','Category.slug')
)
);
As Dimitry said above - Containable is the way to go with this:
In your Models/AppModel.php (Create it if it doesn't exist) change the call to have the following:
class AppModel extends Model {
public $actsAs = array('Containable');
}
Then you would do as Dimitry said above - this will allow you to only return the fields you want.
'recursive' => 2
will eventually cause you so much slowness that your app will be painful to use, most people set recursive = 1 in their AppModel and use containable the rest of the time.

Searching data from associated models in CakePHP

I am using CakePHP 2.3.6. In my project, I have to search users using some values/data/parameter, which are in several tables, and the tables are associated.
The associations are :
in the model User.php :
public $hasMany=array('Education'=>array(
'className'=>'Education
'foreignKey'=>'user_id'
),
'Experience'=>array(
'className'=>'Experience',
'foreignKey'=>'user_id'
),
'Employment'=>array(
'className'=>'Employment',
'foreignKey'=>'user_id'
),
'ProfessionalQualification'=>array(
'className'=>'ProfessionalQualification',
'foreignKey'=>'user_id'
)
)
in the model Education.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model Experience.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model Employment.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
in the model ProfessionalQualification.php :
public $belongsTo=array('User'=>array(
'className'=>'User',
'foreignKey'=>'user_id'
)
)
Now, in the Search form (View/Users/search.ctp) :
echo $this->Form->create('User');
echo $this->Form->input('name',array('type'=>'text'));
echo $this->Form->input('username',array('type'=>'text'));
echo $this->Form->input('address',array('type'=>'textarea'));
echo $this->Form->input('phone',array('type'=>'tel'));
echo $this->Form->input('degree',array('type'=>'text'));
echo $this->Form->input('passing_year',array('type'=>'text'));
echo $this->Form->input('title',array('type'=>'text'));
echo $this->Form->input('title.description',array('type'=>'textarea'));
echo $this->Form->input('company',array('type'=>'text'));
echo $this->Form->input('company.description',array('type'=>'textarea'));
echo $this->Form->input('certificate',array('type'=>'text'));
echo $this->Form->input('certificate.description',array('type'=>'textarea'));
echo $this->Form->submit('Search');
echo $this->Form->end();
in the UsersController.php controller :
public function search(){
$this->set('title_for_layout','Search User');
if($this->request->is('post')){
$conditions=array();
$data=$this->request->data;
if(!empty($data['name']))
$conditions['name']="%".$data['name']."%";
if(!empty($data['username']))
$conditions['username']=$data['username'];
if(!empty($data['address']))
$conditions['address']='%'.$data['address'].'%';
if(!empty($data['phone']))
$conditions['phone']=$data['phone'];
if(!empty($data['degree']))
$conditions['degree']="%".$data['degree']."%";
.
.
.
if(!empty($data)){
$users=$this->User->find('all',array('conditions'=>$conditions));
if(!empty($users)){
$this->Session->setFlash("Searching Users Successful");
$this->set('users',$users);
}else
$this->Session->setFlash("No user found");
}else
$this->Session->setFlash("You didn't give any info to search for");
}
}
I thought it'd retrieve all data I am looking for, from all the associated tables, in an array. But, it gives an error :
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'degree' in 'where clause'
SQL Query: SELECT `User`.`id`, `User`.`name`, `User`.`username`, `User`.`phone`, `User`.`address`, `User`.`created`, `User`.`modified` FROM `db_name`.`users` AS `User` WHERE `degree` = 'M.Sc.'
Here, "degree" is from the table "Education".
Then, I used ContainableBehavior. In the User.php model :
public $actsAs=array('Containable');
In the UsersController.php :
$this->User->find('all',array('contain'=>array('Education'=>array(
'conditions'=>array('Education.institution ='=>"Institute 1")
),
'Employment'=>array(
'conditions'=>array('Employment.employer ='=>"Employer 1")
),
'ProfessionalQualification'=>array(
'conditions'=>array('ProfessionalQualification.certificate ='=>"Certificate 1")
),
'Experience'=>array(
'conditions'=>array('Experience.title ='=>"Title 1")
)
)
)
);
When I use this, the result array is :
array(
(int) 0 => array(
'User' => array(
'name' => 'Name 3',
'email' => 'user3#email.com',
'mobile' => '9325028505',
'id' => '4'
),
'Education' => array(),
'Employment' => array(),
'ProfessionalQualification' => array(),
'Experience' => array()
),
(int) 1 => array(
'User' => array(
'name' => 'Name 2',
'email' => 'user2#email.com',
'mobile' => '9082730572',
'id' => '3'
),
'Education' => array(),
'Employment' => array(),
'ProfessionalQualification' => array(),
'Experience' => array()
),
(int) 2 => array(
'User' => array(
'name' => 'Name 1',
'email' => 'user1#email.com',
'mobile' => '715414918934',
'id' => '2'
),
'Education' => array(
(int) 0 => array(
'id' => '1',
'applicant_id' => '2',
'level' => 'Secondary',
'degree_title' => 'S.S.C',
'passing_year' => '2009',
'institution' => 'Institute 1',
'result' => '4',
'major' => 'Science',
'created' => '2014-05-18 16:48:08',
'modified' => '2014-05-18 17:20:12'
)
),
'Employment' => array(
(int) 0 => array(
'id' => '1',
'applicant_id' => '2',
'employer' => 'Employer 1',
'position_held' => 'Position 1',
'industry' => 'Industry 1',
'department' => 'Department 1',
'major_responsibilities' => 'Responsibilities 1',
'job_location' => 'Local',
'key_achievement' => 'Achievements 1',
'served_from' => '2005-03-12',
'served_till' => '2007-11-26',
'created' => '2014-05-18 16:48:08',
'modified' => '2014-05-18 17:20:12'
)
),
'ProfessionalQualification' => array(
(int) 0 => array(
'id' => '1',
'applicant_id' => '2',
'name_of_certificate' => 'Certificate 1',
'institute' => 'Institute 1',
'from' => '2011-10-11',
'to' => '2012-09-11',
'location' => 'Local Ins.',
'created' => '2014-05-18 16:48:08',
'modified' => '2014-05-18 17:20:12'
)
),
'Experience' => array(
(int) 0 => array(
'id' => '1',
'applicant_id' => '2',
'title' => 'Title 1',
'institute' => 'Institute 1',
'training_year' => '2013',
'location' => 'Local Ins.',
'created' => '2014-05-18 16:48:08',
'modified' => '2014-05-18 17:20:12'
)
)
),
(int) 3 => array(
'User' => array(
'name' => 'Name 4',
'email' => 'user4#email.com',
'mobile' => '9082730572',
'id' => '5'
),
'Education' => array(),
'Employment' => array(),
'ProfessionalQualification' => array(),
'Experience' => array()
)
)
Here, notice, that I only need the 2 no. array, nothing else, but it gives me all data that are not relevant.
Can you please tell me where is the problem ? What should I do ? I guess, I have to explicitly give the table names in the form, on the specific fields, like : ModelName.0.field. What do you think?
try this
public function global_search() {
$condition = array(
'User.role' => array('U', 'P'),
'User.user_status' => array('active', 'lead', 'inactive')
);
if ($this->request->is('post') || $this->request->is('put')) {
$or = array(
'PersonalInformation.first_name' => $this->request->data['User']['first_name'],
'PersonalInformation.last_name' => $this->request->data['User']['last_name'],
'PersonalInformation.primary_phone' => $this->request->data['User']['primary_phone'],
'PersonalInformation.dob' => $this->request->data['User']['dob'],
'User.email' => $this->request->data['User']['email'],
);
//==========This Function allow remove blank element from array=========//
$or = array_filter($or);
//=====End============//
$condition = array(
'User.role' => array('U', 'P'),
'User.user_status' => array('active', 'lead', 'inactive'),
'OR' => $or
);
$data = $this->User->find('first', array(
'conditions' => $condition)
);
// pr($data); exit;
$this->set('allusers', $data);
}
$data = $this->User->find('all', array(
'conditions' => $condition)
);
//pr($data); exit;
$this->set('allusers', $data);
$this->layout = 'admin';
}

How do I query data in CakePHP using HABTM relationships and translation?

I'm using Cakephp and try to make my model to ActAs 'Translation'. But i have a problem.
My Client model relations are:
public $belongsTo = array("User");
public $hasAndBelongsToMany = array(
'Category' =>
array(
'className' => 'Category',
'joinTable' => 'categories_clients',
'foreignKey' => 'client_id',
'associationForeignKey' => 'category_id',
'unique' => true,
),
);
In Category Model:
public $name = 'Category';
public $hasMany = array(
'Product'
);
public $displayField = 'title';
public $recursive = 1;
public $actsAs = array(
'Tree',
'Translate' => array(
'title',
'alias',
'description',
),
'Containable' => array('CategoryTranslations'),
);
public $translateModel = 'CategoryTranslations';
public $translateTable = 'category_translations';
When i query from Client Controller to get all Client and relative Category, i can't get field "title", "alias" and "description" of Category. Here is my code:
if(isset($this->passedArgs['language_id'])){
$language_id = $this->passedArgs['language_id'];
}
else{
$language_id = Configure::read('Config.language_site');
}
$this->Client->Category->locale = $language_id;
$this->Client->recursive = 1;
$this->paginate = array('limit' => 20,'order' => array('User.id' => 'desc'));
$Clients = $this->paginate();
Here is result:
array(
'Client' => array(
'id' => '1',
'user_id' => '1',
'client_type' => 'tenderer',
'image' => null,
'image_list' => null,
'code' => 'SG0593',
'name' => 'Oorts',
'address' => '1000 Huynh Tan Phat',
'telephone' => '0987654321',
'fax' => '0983213434',
'email' => 'nguyentuandat.vn#gmail.com',
'proxy' => 'Dat Nguyen',
'position' => 'C.E.O',
'mobile' => '0987654321',
'referred_by' => 'noone',
'order' => null,
'status' => true,
'created' => '2014-03-27 00:00:00',
'modified' => '2014-03-27 00:00:00'
),
'User' => array(
'password' => '*****',
'id' => '1',
'username' => 'admin',
'group_id' => '1',
'gender' => 'Male',
'first_name' => 'Nguyễn',
'middle_name' => 'Tuấn',
'last_name' => 'Đạt',
'email' => 'nguyentuandat.vn#gmail.com',
'phone_number' => '(+84) 947235313',
'image' => '/uploads/images/255443_102754699884371_1177788671_n.jpg',
'status' => true,
'created' => '2014-01-16 09:26:09',
'modified' => '2014-01-22 06:47:25',
'full_name' => 'Nguyễn Tuấn Đạt'
),
'Category' => array(
(int) 0 => array(
'id' => '1',
'parent_id' => '0',
'type' => 'product',
'image' => '',
'order' => '0',
'status' => true,
'lft' => '1',
'rght' => '16',
'created' => '2014-01-25 00:00:00',
'modified' => '2014-01-25 00:00:00',
'CategoriesClient' => array(
'id' => '1',
'category_id' => '1',
'client_id' => '1'
)
)
)
)
Can you help me? Thank you!
Restructure the code
Unfortunately because of how behaviors work - that's none-trivial to solve exactly as asked.
You can however do something like this:
$Clients = $this->paginate();
// extract category ids in the results
$categoryIds = array_unique(Hash::extract($Clients, '{n}.Category.{n}.id'));
$categories = $this->Client->Category->find('all', array(
'conditions' => array(
'Category.id' => $categoryIds
)
));
// generate a category-id indexed array of categories
$categories = Hash::combine($categories, '{n}.Category.id', '{n}.Category');
// replace the untranslated category entries with translated category data
foreach($Clients as &$client) {
foreach($client['Category'] as &$cat) {
$id = $cat['id'];
$cat = $categories[$id];
}
}
This example is shown as pseudo controller code - you could also consider putting it in your Client afterFind method or a custom finder.
Thank for help.
I found a solution:
I added bellow code into AppModel->afterFind and it work fine
public function afterFind($results, $primary = false) {
if(!empty($this->hasAndBelongsToMany)) {
foreach($this->hasAndBelongsToMany as $model => $settings) {
if(isset($this->{$model}->actsAs['Translate'])) {
if(!empty($results[0][$model])) {
foreach($results as $k => $v){
foreach($results[$k][$model] as $row => $result) {
$supplement = $this->{$model}->find('first', array(
'conditions' => array(
$model .'.id' => $result['id']),
'fields' => $this->{$model}->actsAs['Translate'],
'recursive' => -1));
if(!empty($supplement)) {
$results[$k][$model][$row] = array_merge($results[$k][$model][$row], array_diff($supplement[$model], $result));
}
}
}// end foreach k=>v
}
}
}
}
return $results;
}

Cakephp find all query on multiple models

I try the following to get al the Articles That belong to MenuItem 6 and have an Article content_type of 'blog'. It does find all the articles with content_type='blog'. But I only want it to return the Article if it belongs to Menuitem 7. And now it return an empty value for MenuItem when not 7.
How can I accomplish that it'll only load the articles from MenuItem 7?
MenuItem has a HABTM relationship with Article
code:
$d=$this->Article->find('all' , array('contain' => array(
'MenuItem' => array(
'conditions' => array(
'MenuItem.id ' => 7,
),
'fields'=>'id'
),
'Tag'=>array(
'conditions'=>array(
'Tag.name'=>'tag1'
),
'fields'=>'name'
)
),
'conditions'=>array('Article.content_type' => 'blog'),
'fields'=>array('id','content_type'),
'recursive'=>1
));
debug($d);
array:
array(
(int) 10 => array(
'Article' => array(
'id' => '15',
'content_type' => 'blog'
),
'Tag' => array(),
'MenuItem' => array()
),
(int) 11 => array(
'Article' => array(
'id' => '16',
'content_type' => 'blog'
),
'Tag' => array(),
'MenuItem' => array(
(int) 0 => array(
'id' => '7',
'MenuItemsArticle' => array(
'id' => '18',
'title' => '',
'article_id' => '16',
'menu_item_id' => '7'
)
)
)
)
)
I think your best bet for this type of find condition is to modify your models to use hasMany through (The Join Model). Here's an example I tested that does what you want:
Article.php
class Article extends AppModel {
public $hasMany = array('ArticleMenuItem');
}
MenuItem.php
class MenuItem extends AppModel {
public $hasMany = array('ArticleMenuItem');
}
ArticleMenuItem.php
class ArticleMenuItem extends AppModel {
public $useTable = 'articles_menu_items';
public $belongsTo = array(
'Article',
'MenuItem'
);
}
The Find Call
$articles = $this->ArticleMenuItem->find('all', array(
'conditions' => array(
'menu_item_id' => 7,
'Article.content_type' => 'blog'
),
'contain' => array(
'Article' => array(
'fields' => array(
'id',
'title'
)
),
'Tag'
)
));
Here's what it produces:
array(
(int) 0 => array(
'ArticleMenuItem' => array(
'article_id' => '1',
'menu_item_id' => '7'
),
'Article' => array(
'id' => '1',
'content_type' => 'blog',
'title' => 'test blog'
)
),
(int) 1 => array(
'ArticleMenuItem' => array(
'article_id' => '4',
'menu_item_id' => '7'
),
'Article' => array(
'id' => '4',
'content_type' => 'blog',
'title' => 'another'
)
)
)
And here's the query it generates:
SELECT `ArticleMenuItem`.`article_id`, `ArticleMenuItem`.`menu_item_id`, `Article`.`id`, `Article`.`content_type`, `Article`.`title` FROM `caketest`.`articles_menu_items` AS `ArticleMenuItem` LEFT JOIN `caketest`.`articles` AS `Article` ON (`ArticleMenuItem`.`article_id` = `Article`.`id`) WHERE `menu_item_id` = 7 AND `Article`.`content_type` = 'blog'
I've set $recursive = -1 in my AppModel as well. I would suggest doing the same since you are using the containable behavior, it's much more efficient because it only pulls back the data that you need. :)
Hope this helps, any questions just let me know.

Resources