Searching data from associated models in CakePHP - 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';
}

Related

How to get rid of null associated model in cakephp 2.x

I am trying to get the item types that Order.Item.ItemType.show_type = 1. I have written the query but I want to show only Items that their ItemType.show_type = 1 not all items.
$brief = $this->Order->find('first', array(
'fields' => array(
'Order.*'
),
'conditions' => array(
'Order.order_id' => $orderId,
),
'contain' => array(
'Item' => array(
'fields' => array(
'Item.*', 'CHAR(64 + Item.num) AS letter'
),
'conditions' => array(
'Item.deleted' => 0,
),
'ItemType' => array(
'conditions' => array(
'ItemType.show_type' => 1
),
)
),
)
));
The query shouldn't show Item id = 25741
Associations:
// Order
public $hasMany = array(
'BriefInstalment' => array(
'foreignKey' => 'order_id'
)
);
// Item Model
public $belongsTo = array(
'Order',
'ItemType' => array(
'type' => 'inner'
)
);
// ItemType Model
public $hasMany = array('Item');
Print:
array(
'Order' => array(
'order_id' => '67817',
'service' => '',
),
'Item' => array(
(int) 0 => array(
'id' => '25741',
'order_id' => '67817',
'num' => '2',
'item_type_id' => '8',
'name' => '3-5 titles active',
'deleted' => false,
'ItemType' => array(), // <= how to remove this empty model
'Item' => array(
(int) 0 => array(
'letter' => 'B'
)
)
),
(int) 1 => array(
'id' => '25742',
'order_id' => '67817',
'num' => '3',
'item_type_id' => '2',
'name' => '1,000 pro active',
'deleted' => false,
'ItemType' => array(
'id' => '2',
'name' => 'Part Instalment',
'show_type' => true,
'deleted' => false
),
'Item' => array(
(int) 0 => array(
'letter' => 'C'
)
)
)
)
)
This could not be done using Countaible behaviour, but iwth the joins method, set the recursive to -1
$brief = $this->Order->find('first', array(
'recursive' => -1,
'fields' => array(
'Order.*'
),
'conditions' => array(
'Order.order_id' => $orderId,
),
'joins' => array(
array(
'table' => 'items',
'alias' => 'Item',
'type' => 'inner',
'conditions' => array(
'Order.id = Item.order_id'
)
),
array(
'table' => 'item_types',
'alias' => 'ItemType',
'type' => 'inner',
'conditions' => array(
'ItemType.id = Item.item_type_id'
)
),
)
));
You have to check if the table names are correct and also the foreign keys names.
Another solution would be to go through your results, and unset the empty ones
foreach($brief as $k => $v){
foreach($v['Item'] as $kk => $vv){
if(empty($vv['ItemType'])){
unset($brief[$k]['Item'][$kk];
}
}
}
debug($brief);

CakePHP 2.x retriving data with i18n in a loop

I'm looping trough Features (belongTo FeatureType) and find() FeatureType.name for each Feature.feature_type_id.
I'm getting first record correct (with i18n translation) but in all the rest the i18n translation is not in place, but given as separate record.
What I am doing wrong?
this is the debug of my result table:
array(
'FeatureType' => array(
'id' => '28',
'name' => 'kolor suwaka',
'comment' => 'kolor suwaka etui notebook',
'locale' => 'pol'
)
)
array(
'FeatureType' => array(
'id' => '7',
'name' => '',
'comment' => '',
'locale' => 'pol'
),
(int) 0 => array(
'FeatureType__i18n_name' => 'kolor materiału',
'FeatureType__i18n_comment' => 'gra w klasy'
)
)
array(
'FeatureType' => array(
'id' => '11',
'name' => '',
'comment' => '',
'locale' => 'pol'
),
(int) 0 => array(
'FeatureType__i18n_name' => 'kolor',
'FeatureType__i18n_comment' => 'kółko i krzyżyk (jasnoszare i ciemnoszare)'
)
)
array(
'FeatureType' => array(
'id' => '27',
'name' => '',
'comment' => '',
'locale' => 'pol'
),
(int) 0 => array(
'FeatureType__i18n_name' => 'obwód głowy',
'FeatureType__i18n_comment' => 'rozmiar kapelusza czarownicy'
)
)
This is the code:
$features_str = "";
if (!empty($product['Features'])) {
foreach ($product['Features'] as $featureIndex => $feature) {
$featureTypeModel = new FeatureType();
$feature_type = $featureTypeModel->find("first", array("conditions" => array("FeatureType.id" => $feature['feature_type_id'])));
if (strlen($features_str) > 0) $features_str .= ", ";
$features_str .= $feature_type['FeatureType']['name'] . ': ' . $feature['name'];
unset($featureTypeModel);
}
}

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 2.0 Associated models data not being retrieved

I have 2 tables, Militia and Injunctions. Militia can have many injunctions and injunctions only belong to one militia. I set those up in the models but when i call a find all for militia the injunctions aren't pulled out.
Militia model
class Militia extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
public $hasMany = array(
'Injunction' => array(
'className' => 'Injunction',
'foreignKey' => 'militia_id'
//'conditions' => array("not" => array('Injunction.removed' => null))
)
);
}
Injunctions model
class Injunction extends AppModel {
public $belongsTo = array(
'Militia' => array(
'className' => 'Militia',
'foreignKey' => 'militia_id'
)
);
}
and the query getting the militia members
$user = $this->Session->read("User");
$militias = $this->Militia->find('all',
array(
'conditions'=>array(
"Militia.user_id" => $user['User']['id'],
"Militia.deleted" => 0
)
)
);
output
/app/Controller/UsersController.php (line 41)
array(
(int) 0 => array(
'Militia' => array(
'id' => '26',
'first_name' => 'Chris',
'last_name' => 'Morris',
'created' => '2013-02-11 13:45:24',
'user_id' => '2',
'status' => '1',
'deleted' => '0'
)
),
(int) 1 => array(
'Militia' => array(
'id' => '31',
'first_name' => 'John',
'last_name' => 'Smith',
'created' => '2013-02-11 14:03:50',
'user_id' => '2',
'status' => '0',
'deleted' => '0'
)
),
(int) 2 => array(
'Militia' => array(
'id' => '32',
'first_name' => 'test',
'last_name' => 'user',
'created' => '2013-02-11 14:21:38',
'user_id' => '2',
'status' => '0',
'deleted' => '0'
)
),
(int) 3 => array(
'Militia' => array(
'id' => '33',
'first_name' => 'test',
'last_name' => 'user',
'created' => '2013-02-11 14:24:02',
'user_id' => '2',
'status' => '1',
'deleted' => '0'
)
)
)
I've done the same thing before on other projects but for some reason this one time it's not pulling out the associated data. It's probably something stupid like a typo but I've been looking and testing and can't find anything wrong.
Check ORM (hasOne, hasMany, belongsTo, hasAndBelongsToMany) definition,
Check if foreign key ids are set right
Check if there are data's in the table and its related table.
Check the results of find without condition
Check to see if recursive level is greater than 0
To rule out your old cached query issue, set debug level higher to 0
Look out in the bottom section of sql dump to see what query is being fired, if it feels ok try same query with SQL away from Cake/Php.

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