I have read numerous posts, spent hours going over the documents at cakephp.org and even tried various practical examples and I cannot seem to get this right. What I have are 3 tables as follows:
- projects
- project_tags
- tags
When someone adds a new project, they choose their tags, which are selected from a predefined list in the tags table. This tag they entered is then stored in project_tags using the project_id and tag_id fields.
Model relations are as follows:
- Project hasMany projectTag
- projectTag belongsTo Project
- ProjectTag belongsTo Tag
Whether or not I have the correct relations is still trivial to me, but I have tried numerous possibilities here.
What I am trying to do is perform a find on all projects of a specific tag. I have done this by doing the following:
$this->Project->contain(array('ProjectTag' => 'Tag', 'User' => array('id')));
$projects = $this->Project->find('all', array('conditions' => array('ProjectTag.tag_id' => '6')));
The result is an SQL error that column ProjectTag.tag_id does not exist. This tells me that there is an error in the association, but where?
Is this because I cannot use a 2nd level deep associated hasMany model in my fond condition when using containable? If so, how can I correct this?
I know it’s long, sorry. Can anyone shed some light on this bizarre situation?
Another approach I tried was using the unbindModel() on Project, removing all the bindings to ProjectTag, and then adding a hasOne using bindModel() and a condition of ProjectTag.project_id = Project.id but this resulted on 4 records of the same project being returned, one for each ProjectTag, which does not seem right.
I am using the containable behavior and have set recursive = -1 in the AppModel.
Any help is greatly appreciated.
Thanks
To all who may stumble across this post, trying to include models that are 2+ levels deep in association within your find or paginate query is not a trivial task to say the least.
The number one point that kept being raised was that CakePHP performs seperate queries for each hasMany and hasAndBelongsToMany associations, making it near impossible to include them in your find conditions.
I was presented with 2x solutions:
1) Build a custom query type
2) Use the unbindModel and bindModel functions and re-create the associations as hasOne
I opted for point 2 because point 1 seemed questionable when I read the docs (and was only recommended as a last resort) and it allowed me to change the association on the fly, and reset it afterwards, continuing merrily with the associations as I intended.
For those who are interested, I had a model Project that hasMany ProjectTag that belongsTo Tag. It was not possible to use Tag or ProjectTag in my find types, so I did the following:
I used the unbindModel() method on Project, ProjectTag and Tag, removing all their associations, essentially unlinking all relationships.
I then applied the bindModel() to Project, ProjectTag and Tag. Most importantly was the order (hierarchy) I applied these nindings, because I made use of the ‘condition’ property which allowed me to link model ‘A’ to model ‘B’ using SQL WHERE conditions. For example:
We can now make use of Tag.id as if it has a hasOne relationship to Project, essentially allowing us to apply find conditions directly on the Tag while returning related Projects.
It is ESSENTIAL that you unbind all relationships that are used by the models in question, or it will break.
I hope this helps those who stumble across the same issue.