Cakephp - joining tables, NOT in - cakephp

I'm a newbie and I'm trying to make a Query but don't get it how to do the Query in cake-style. I want to do a query that Selects all respondents thats not in a particular transformational. Examples at the bottom. Cakephp v 2.4.5
I have to three tables/models:
Resondents: id, name
public $hasAndBelongsToMany = array(
'Transformational' => array(
'className' => 'Transformational',
'joinTable' => 'transformationals_respondents',
'foreignKey' => 'respondent_id',
'associationForeignKey' => 'transformational_id',
'unique' => true
)
);
Transformationals: id, name
public $hasAndBelongsToMany = array(
'Respondent' => array(
'className' => 'Respondent',
'joinTable' => 'transformationals_respondents',
'foreignKey' => 'transformational_id',
'associationForeignKey' => 'respondent_id',
'unique' => true
),
};
TransformationasRespondent: id, transformational_id, respondent_id
This is a join table
Example tables:
respondent: id, name
1, Abc
2, Def
3, Ghi
4, Jkl
transformationals: id, name
1, Macrosoft
2, Eddy
3, Wag
transformationals_respondents: id, respondent_id, transformational_id
1, 1, 7
2, 2, 7
THen I need Query to SELECT respondents thats NOT in transformationals_respondents and has transformational_id 7. Ie. respondent Ghi and Jkl
I would really appreciate a hand here.

Create one function in Respondent model as
function getSomeSome(){
$options = array(
'conditions' => array('Transformational.id'=>7,'TransformationasRespondent.id IS NULL'),
'joins' => array(
array(
'alias' => 'TransformationasRespondent',
'table' => 'transformationals_respondents',
'type' => 'LEFT',
'conditions' => array(
'TransformationasRespondent.respondent_id = Respondent.id',
),
),
array(
'alias' => 'Transformational',
'table' => 'transformationals',
'type' => 'LEFT',
'conditions' => array(
'TransformationasRespondent.transformational_id = Transformational.id',
),
),
)
);
$returnData = $this->find('all',$options);
# returnData contains all the records having transformational_id equals to 7 and
# does nt have any recors in TransformationasRespondent table
}

Related

Cakephp 2 retrieve data where condition depends on child table

I am having a strange behavior which I do not understand with my cakephp 2.
In my Model 'Study' I have a has many relation:
class Study extends AppModel {
public $hasOne = array(
'SubjectFilter' => array(
'className' => 'Subject_filter',
'dependent' => true
)
);
public $hasMany = array(
'ExecutedStudyTable' => array(
'className' => 'ExecutedStudyTable',
'foreignKey' =>'study_id',
'dependent' => true,
),
);
The ExecutedtStudyTable Model looks like this:
class ExecutedStudyTable extends AppModel {
public $belongsTo= array(
'Study' => array(
'className' => 'Study',
'foreignKey' => 'study_id'
),
'User' => array(
'className' => 'User',
'foreignKey' => false,
'conditions' => array('ExecutedStudyTable.user_id = User.id')
)
);
}
When retrieving data everything looks good until I try to do this:
$studies = $this -> Study -> find('all',array(
'conditions' => array(
'Study.user_id' => $cId,
'OR'=>array(
array('Study.state'=>'active'),
array('Study.state'=>'rehearsal')
),
'SubjectFilter.studyCode'=>null,
'ExecutedStudyTable.user_id'=>$user
)
));
I get this error: Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'ExecutedStudyTable.user_id' in 'where clause'
Cakephp builds this query like this:
SELECT `Study`.`id`, `Study`.`user_id`, `Study`.`created`, `Study`.`modified`, `Study`.`started`, `Study`.`completed`, `Study`.`title`, `Study`.`description`, `Study`.`numberParticipants`, `Study`.`state`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`role`, `User`.`firstName`, `User`.`familyName`, `User`.`email`, `User`.`addressStreet`, `User`.`addressCity`, `User`.`addressZip`, `User`.`phone1`, `User`.`phone2`, `User`.`created`, `User`.`modified`, `User`.`passwordResetCode`, `User`.`passwordResetDate`, `User`.`sendUsernameDate`, `SubjectFilter`.`id`, `SubjectFilter`.`study_id`, `SubjectFilter`.`m`, `SubjectFilter`.`f`, `SubjectFilter`.`age18_24`, `SubjectFilter`.`age25_34`, `SubjectFilter`.`age35_44`, `SubjectFilter`.`age45_54`, `SubjectFilter`.`age55plus`, `SubjectFilter`.`studyCode` FROM `eyevido`.`studies` AS `Study` LEFT JOIN `eyevido`.`users` AS `User` ON (`Study`.`user_id` = `User`.`id`) LEFT JOIN `eyevido`.`subject_filters` AS `SubjectFilter` ON (`SubjectFilter`.`study_id` = `Study`.`id`) WHERE `Study`.`user_id` = 1402402538 AND ((`Study`.`state` = 'active') OR (`Study`.`state` = 'rehearsal')) AND `SubjectFilter`.`studyCode` IS NULL AND `ExecutedStudyTable`.`user_id` = 1130451831
The ExecutedStudyTable is not joined like the SubjectFilter and no alias is defined for the table. Why is this working correctly on the hasOne relation and not on the hasMany? Where do I make the mistake?
I appreciate your replies
If you want to filter a model by associated model's field, one way is by Joining tables.
Note: Mention proper table name for model ExecutedStudyTable. Also mention the join condition between two tables.
$studies = $this->Study->find('all',array(
'fields' => array('Study.*'),
'joins' => array(
array('table' => 'executed_study_table', // Table name
'alias' => 'ExecutedStudyTable',
'type' => 'INNER',
'conditions' => array(
'ExecutedStudyTable.<field name> = Study.<field>', // Mention join condition here
)
)
),
'conditions' => array(
'Study.user_id' => $cId,
'OR'=>array(
array('Study.state'=>'active'),
array('Study.state'=>'rehearsal')
),
'SubjectFilter.studyCode' => null,
'ExecutedStudyTable.user_id' => $user
),
'recursive' => -1
));

Cakephp find query not working

I am trying to make a query using cakephp model binding. Getting an unexpected result. But whenever I run the query in phpmyadmin it works fine. Getting this error
Column not found: 1054 Unknown column 'Comment.post_id' in 'field list'
Can't figure out what is wrong
PostsController
$posts = $this->Post->find('all', array(
'conditions' => array(
'Post.is_deleted' => 0,
'Post.is_active' => 1,
),
'fields' => array(
'Post.post_id,Post.post_title,Post.post_body,User.username,Post.added_time',
'Product.product_title','COUNT(Comment.post_id) AS total_comment'
),
'GROUP'=>'Post.post_id',
'order' => 'added_time DESC',
));
Post Model
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreign_key' => 'post_id'
),
'Product' => array(
'className' => 'Product',
'foreign_key' => 'post_id'
)
);
public $hasMany = array(
'Comment'=>array(
'className'=>'Comment',
'foreign_key'=>'post_id'
)
);
Comment Model
public $belongsTo = array(
'Post'=>array(
'className'=>'Post',
'foreign_key'=>'post_id'
)
);
My expected query
SELECT posts.`post_title`, users.username,products.product_title, posts.post_body, COUNT(comments.post_id) as total_comments from posts LEFT JOIN comments on comments.post_id = posts.post_id LEFT join users on users.user_id = posts.user_id LEFT JOIN products on products.product_id = posts.product_id WHERE posts.is_active = 1 and posts.is_deleted = 0 GROUP BY posts.post_id
Try by setting the recursive level 1 or 2
$this->Post->find('all', array(
'conditions' => array(
'Post.is_deleted' => 0,
'Post.is_active' => 1,
),
'fields' => array(
'Post.post_id,Post.post_title,Post.post_body,User.username,Post.added_time',
'Product.product_title','COUNT(Comment.post_id) AS total_comment'
),
'GROUP'=>'Post.post_id',
'order' => 'added_time DESC',
'recursive'=>1
));

cakephp array results [maximum depth reached]

i have two models. Teacher and Subject joined by HABTM defined both ways. A teacher can teach many subjects and a subject can be taught by many teachers.my join table is subjects_teachers and have fields id,teacher_id and subject_id.
Fetching Teacher data from its model, i expect all teachers and their respective subjects ,
Fetching Subject data from its model i expect to also see the teachers teaching that particular subject
problem
on both instances, the associated model returns the correct number of records but the data is absent. i see [maximum depth reached] when i display the respective arrays.
I removed the id field from the join table and that fixed only the Teacher model.The Subject model still has the problem.
i just need to know what [maximum depth reached] means and why removing the id filed from the join table fixed the Teacher problem but not Subject.
also if its important i should mention that my Teacher model primary key field doesnt follow convention
SUBJECT model
public $hasAndBelongsToMany = array(
'Teacher' => array(
'className' => 'Teacher',
'joinTable' => 'subjects_teachers',
'foreignKey' => 'subject_id',
'associationForeignKey' => 'teacher_id',
'unique' => 'keepExisting'
)
);
Teacher Model
public $hasAndBelongsToMany = array(
'Subject' => array(
'className' => 'Subject',
'joinTable' => 'subjects_teachers',
'foreignKey' => 'teacher_id',
'associationForeignKey' => 'subject_id',
'unique' => 'keepExisting'
)
);
Results from subject
array(
(int) 0 => array(
'Subject' => array(
'id' => '1',
'subject_code' => '121',
'subject_name' => 'Mathematics',
'compulsory' => true
),
'Teacher' => array(
(int) 0 => array(
[maximum depth reached]
),
(int) 1 => array(
[maximum depth reached]
),
(int) 2 => array(
[maximum depth reached]
)
)
),
Results from Teacher before removin id field
array(
'Teacher' => array(
'teacher_id' => '6',
'first_name' => 'George',
),
'Subject' => array(
(int) 0 => array(
'id' => '1',
'subject_code' => '121',
'subject_name' => 'Mathematics',
'compulsory' => true,
'SubjectsTeacher' => array(
[maximum depth reached]
)
)
Results after removing id field
'Subject' => array(
(int) 0 => array(
'id' => '1',
'subject_code' => '121',
'subject_name' => 'Mathematics',
'compulsory' => true
),
Your data exists, the debugger just wont display it because the depth option limits it. Use debug() (default depth = 25) or Debugger::dump()/exportVar() with a depth (second argument, defaults to 3) high enough for your deeply nested data.
See also
http://book.cakephp.org/2.0/en/development/debugging.html
http://api.cakephp.org/2.5/class-Debugger.html
It is related to model attribute recursive
http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive

cake 2.5.1 bind 2 models together

I have a model Ranking which holds a contact_id and belongsTo Model Contact.
Model Contact has a costumer_id and belongsTo Model Costumer.
And hasMany Rankings.
There is also a Model Product which hasMany Ranking.
On a statistics page I select
$this->Product->recursive = 1;
$this->set('products', $this->Paginator->paginate())
;
and I get the array of
array(
'Product' => array(
'id' => '69',
),
'Ranking' => array(
(int) 0 => array(
'id' => '29',
'contact_id' => '9',
'product_id' => '69',
'ranking' => '9',
),
I would like to bind now the Contact and Costumer to the ranking based on the contact_id.
Is this manually possible via bindModel?
If yes, how can I do that?
I tried to set $this->Product->recursive = 1; to 2 and 3, but that select so many other things which I would need to clear with unbindModel... So I hope there is a smarter way of bind those model to get to the data...?
What you basically want to use is containable behavior. With this behavior you are able to filter and limit model find operations. You have the possibility to add this behavior on model level or at the controller to avoid side effects if the application has already grown to a complicated level.
Example from Cake-Book:
// Activate Containable Behavior on the fly in a controller
$this->User->Behaviors->load('Containable');
$this->User->contain();
$this->User->find('all', array(
'contain' => array(
'Profile',
'Account' => array(
'AccountSummary'
),
'Post' => array(
'PostAttachment' => array(
'fields' => array('id', 'name'),
'PostAttachmentHistory' => array(
'HistoryNotes' => array(
'fields' => array('id', 'note')
)
)
),
'Tag' => array(
'conditions' => array('Tag.name LIKE' => '%happy%')
)
)
)
));
Hope this gives you a push into the right direction.
using find it will get me the right data with this:
$this->set('products', $this->Product->find('all', array(
'contain' => array(
'Ranking' => array(
'Contact' => array(
'foreignKey' => 'contact_id',
'Customer' => array(
'foreignKey' => 'customer_id',
)
)
)
)
)));
When using the Paginator it looks like
$this->Paginator->settings['contain'] = array(
'Ranking' => array(
'Contact' => array(
'foreignKey' => 'contact_id',
'Customer' => array(
'foreignKey' => 'customer_id',
)
)
)
);
$this->Product->Behaviors->load('Containable');
$this->set('products', $this->Paginator->paginate());
Thanks so much!!

How to find by conditions in two joining tables in CakePHP

In my CakePHP app I have three tables:
Businesses, Towns and Categories.
A business can belong to multiple towns and multiple categories so I have created joining tables and hasMany and belongsTo relationships. Everything works fine when finding businesses by either Town or Category by using the Town or Category model to search, but I am completely stuck when I want to search for businesses in a certain town AND a certain category, eg. Plumbers in London.
The associations just don't seem to work when searching with the Business model and I get column not found errors when trying to use the associated tables. I would think that this would be along the lines of what needs to be done, but I can't get it to work:
$this->set('listings', $this->Business->find('all', array(
'conditions' => array(
'Business.approved' => 1,
'BusinessesCategory.category_id' => $id,
'BusinessesTown.town_id' => $town_id,
'Business.sasite' => 1
)
You need to join the tables to do that.
I will put above a example how has to work with category and you can do the town yourself.
$this->Business->find("all", array(
"joins" => array(
array(
"table" => "businness_categories",
"alias" => "BusinessesCategory",
"type" => "LEFT",
"conditions" => array(
"Businesses.id = BusinessesCategory.business_id"
)
),
array(
"table" => "categories",
"alias" => "Category",
"type" => "LEFT",
"conditions" => array(
"BusinessesCategory.category_id = Category.id"
)
)
),
'conditions' => array(
'Business.approved' => 1,
'Category.id' => $id,
)
));
You also could use a behavior to do that for you:
https://github.com/Scoup/SuperJoin
Hi I had a very similar setup and the same problem. This is how I would solve your problem:
As you dont give away to much of your code I make some assumptions:
- You implemented your search method in the BusinessController
- Your search argument for the town is stored in vaiable $where and the one for Category is stored in $what
Code if you only have conditions for one table
$this->Businesses->Town->recursive = -1;
....
$options['joins'] = array(
array('table' => 'towns',
'alias' => 'Town',
'type' => 'inner',
'conditions' => array(
'Business.town_id = Town.id',
)
)
);
$options['conditions'] = array(
'Town.townName' => $where
);
$result = $this->Business->find('all', $options);
Code if you have conditions for two table
$this->Businesses->Town->recursive = -1;
$this->Businesses->Category->recursive = -1;
....
$options['joins'] = array(
array('table' => 'towns',
'alias' => 'Town',
'type' => 'inner',
'conditions' => array(
'Business.town_id = Town.id',
)
),
array('table' => 'categories',
'alias' => 'Category',
'type' => 'inner',
'conditions' => array(
'Business.category_id = category.id',
)
)
);
$options['conditions'] = array(
'Town.townName' => $where,
'Category.categoryName' => $what
);
$result = $this->Business->find('all', $options);
You can use
$this->Business->find('all', array(
'conditions' => array(
'AND' => array(
'BusinessesTown.town_id' => $town_id,
'BusinessesCategory.category_id' => $id
)
),
'recursive' => 2
));

Resources