I have the following relationships set up:
Teacher:
var $hasAndBelongsToMany = array(
'Classroom' => array(
'className' => 'Classroom',
'joinTable' => 'classrooms_teachers',
'foreignKey' => 'teacher_id',
'associationForeignKey' => 'classroom_id',
'unique' => true,
)
);
Classroom:
var $hasAndBelongsToMany = array(
'Teacher' => array(
'className' => 'Teacher',
'joinTable' => 'classrooms_teachers',
'foreignKey' => 'classroom_id',
'associationForeignKey' => 'teacher_id',
'unique' => true,
)
);
var $hasMany = array(
'Student' => array(
'className' => 'Student',
'foreignKey' => 'classroom_id',
'dependent' => false,
),
);
Student:
var $belongsTo = array(
'Classroom' => array(
'className' => 'Classroom',
'foreignKey' => 'classroom_id',
),
);
I am trying to create a dashboard for the teachers, where all students associated with the teacher through the classroom are displayed.
I am using the following find operation:
$students = $this->Teacher->Classroom->find('all', array(
'conditions' => array('Classroom.teacher_id' => $this->Access->getTeacherId()),
));
However, I am getting an error: Unknown column 'Classroom.teacher_id' in 'where clause'
I must be doing something wrong because cake is not doing the associations.
Any ideas?
This is the correct way of achieving this:
$this->Teacher->bindModel(array('hasOne' => array('ClassroomsTeachers')));
$students = $this->Teacher->find('all', array(
'conditions' => array('ClassroomsTeachers.teacher_id' => $this->Access->getTeacherId()),
'recursive' => 2
));
I hope it helps someone!
That's not the best way. Just use containable and find('first'), you don't need find all:
$students = $this->Teacher->find('first', array(
'conditions' => array('Teacher.id' => $this->Access->getTeacherId()),
'contain' => array('Classroom'=>array('Student'))
));
That will get you all the classrooms associated with the teacher, and all students in those classrooms.
I made a behavior to solve the HABTM problem.
Posted my answer here:
HABTM Find with CakePHP 2.0
Related
My Cakephp Application Has the following models with relations ships
class Category extends AppModel {
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'products_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'product_id',
'unique' => 'keepExisting',
),
);
}
class Product extends AppModel {
public $primaryKey = 'id';
public $hasMany = array(
'ProductSwatch' => array(
'className' => 'ProductSwatch',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductDimension' => array(
'className' => 'ProductDimension',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductCare' => array(
'className' => 'ProductCare',
'foreignKey' => 'product_id',
'dependent' => true
),
'ProductDimension' => array(
'className' => 'ProductDimension',
'foreignKey' => 'product_id',
'dependent' => false,
),
'ProductCare' => array(
'className' => 'ProductCare',
'foreignKey' => 'product_id',
'dependent' => false,
),
'Review' => array(
'className' => 'Review',
'foreignKey' => 'product_id',
'dependent' => true,
)
);
}
When i am finding all the Category elements only Product Model contents are coming is there any way to get the Products associations(ProductDimension, ProductSwatches, etc) when we fetch the Categories model?
By default CakePHP 2 recursion level is 1st level association only.
You can use recursive option of find (or model property) to fetch deep associations.
For more information about model recursive property, see: http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive
For example:
$this->Category->find('all', array(
'recursive' => 2,
'conditions' => array(), // Your conditions, etc.
));
Another (and better way) is using Containable behaviour.
add
public $actsAs = array('Containable');
to your model(s) to enable Containable behaviour. Then you can use:
$this->Category->find('all', array(
'contain' => array(
'Product' => array(
'ProductSwatch',
'ProductDimension',
'ProductCare',
'Review',
),
),
'conditions' => array(), // Your conditions, etc.
));
to fetch deeper associations.
For more information about Containable behaviour and deeper associations, see http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#containing-deeper-associations
// in Person
public $hasMany = array(
'PersonRecommendation' => array(
'className' => 'PersonRecommendation',
'foreignKey' => false,
'dependent' => true,
),
)
// in PersonRecommendation
public $belongsTo = array(
'Person' => array(
'className' => 'Person',
'foreignKey' => false,
'conditions' => array('Person.email = PersonRecommendation.email'),
),
);
When I query these out with find() the Person returns ALL recommendations. Not just those associated by email. I've tried a variety of different things, and I'm stumped. Can someone help?
Using cake 2.4.5.
You need to change the Person model
public $hasMany = array(
'PersonRecommendation' => array(
'className' => 'PersonRecommendation',
'foreignKey' => false,
'dependent' => true,
'conditions' => array('Person.email = PersonRecommendation.email')
)
)
Try the following:
'conditions' => array($Person->email => $PersonRecommendation->email)
I have the following code that gives an error from the moment I do a find condition on the associated Model (HABTM):
class Users extends Model{
public $useTable = 'users';
public $hasAndBelongsToMany = array(
'UserCategories' => array(
'className' => 'UserCategories',
'joinTable' => 'user_categories_link',
'foreignKey' => 'user_id',
'associationForeignKey' => 'category_id',
'unique' => false,
)
);
public function getData($page = 0, $category = '', $subcategory = ''){
return $this->find('all', array(
'limit' => 6,
'page' => $page,
'conditions'=> array(
'active'=> 1,
'UserCategories.category_name' => $category, // THIS GIVES ERROR
'UserCategories.category_subcategory' => $subcategory, // THIS GIVES ERROR
)
));
}
In my Controller:
$this->Users->getData(0, 'somemaincategory', 'somesubcategory');
I can't seem to do conditions on the related HABTM-Model (UserCategories in this case). I also tried to use 'contain' (with $actsAs), but then he stills gives me all the User data even if there is no Category linked with it. The Category array is in that case just blank.
Hope someone can help me.
Thanks in advance,
AƤron
Do a manual join. You can use this to do an actual inner join (contain will act as a left join). http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
$this->find('all',
array(
'conditions' => array(
'active' => 1,
),
'joins' => array(
array(
'table' => 'user_categories_link',
'alias' => 'UserCategoriesLink',
'type' => 'inner',
'conditions' => array(
'UserCategoriesLink.user_id = User.id'
),
),
array(
'table' => 'user_categories',
'alias' => 'UserCategories',
'type' => 'inner',
'conditions' => array(
'UserCategories.id = UserCategoriesLink.category_id',
'UserCategories.category_name' => $category,
'UserCategories.category_subcategory' => $subcategory,
),
)
),
)
);
I have an article model with Tags and MenuItems associated with it.
I want to show Articles with a certain MenuItem id.
When a preform a find operation on the model it return an (Unknown column 'MenuItem.id' in 'field list') error.
I have know idea what i'm doing wrong.
Article Model:
public $hasAndBelongsToMany = array(
'Tag' => array(
'className' => 'Tag',
'joinTable' => 'articles_tags',
'foreignKey' => 'article_id',
'associationForeignKey' => 'tag_id'
),
'MenuItem' => array(
'className' => 'MenuItem',
'joinTable' => 'menu_items_articles',
'foreignKey' => 'article_id',
'associationForeignKey' => 'menu_item_id',
'unique' => 'keepExisting'
)
);
Article Controller:
$allArticles = $this->Article->find('all',
array(
'fields' => array('MenuItem.id','Article.id','Article.name'),
'conditions'=>array('Article.content_type'=>'blog','MenuItem.id'=>7),
'recursive'=>2
)
);
debug($allArticles);
Try this :
$this->Article->Behaviors->attach('Containable');
$allArticles = $this->Article->find('all',
array('contain' => 'MenuItem.id'),
'fields' => array('Article.id','Article.name'),
'conditions'=>array('Article.id'=>4),
)
);
debug($allArticles);
Is there a way in cakephp using ORM to get the item that belongs to a specific child item. For example I was to get the related Post record for a specific Comment records.
This is my Comment model:
var $belongsTo = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'post_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
I was trying this but it's pull back every post, even those that don't have the comment I'm querying against:
$this->Post->contain('Comment');
$results = $this->Post->find('all', array(
'contain' => array(
'Comment' => array(
'conditions' => array(
'id' => 15
)
)
)));
Any other way to do this?
Are you sure you don't have to specify the model in your conditions?
For example:
$this->Post->contain('Comment');
$results = $this->Post->find('all', array(
'contain' => array(
'Comment' => array(
'conditions' => array(
'Comment.id' => 15
)
)
)));
my research led me to this post regarding the issue with contains:
http://nuts-and-bolts-of-cakephp.com/2008/07/17/forcing-an-sql-join-in-cakephp/
so my final solution was as follows:
$this->Post->unbindModel(array('hasMany' => array('Comment')));
$results = $this->Post->bindModel(array('hasOne' => array(
'Comment' => array(
'foreignKey' => false,
'conditions' => array('Comment.post_id = Post.id'))
)));
$results = $this->Post->find('all', array(
'conditions' => array(
'Comment.id' => 10
)));
not pretty but gets the job done :)