Creating and Destroying Associations on the Fly
For the past few days I have been playing mental games with a particular find() in CakePHP. Basically I wanted to be able to get ALL of some data (Category), and the associated data (Credit) – if the Credits existed. My queries were returning ALL of the Categories in one query. But when I added in the Credit association, it only returned the Categories where the Credits existed.
This was proving to be difficult, so after a lot of stuffing about my @ghostpsalm came to the rescue. Well, he started me on the right path.
[php]$cat = $this->Category->read(array(‘lft’,’rght’), $parent_id);[/php]
This found the lft and rght figures for a particular Category. This was important because it meant the following find() had no association layers – basically that the next find() would not be influenced by outside persuasions (Cake Model Setups).
[php]$subCat = $this->Category->find(‘all’, array(
‘conditions’ => array(
‘Category.lft >’ => $cat[‘Category’][‘lft’],
‘Category.rght <‘ => $cat[‘Category’][‘rght’],
‘contain’ => array(‘Credit’),
This above find found everything we were looking for. All the Categories and All the Credits associated with them. So I could have used a php loop to find the One Credit we needed for the view – but that seems like a waste of retreived data to me. So I needed a way to be satisified, a way that the data being retreved would be the data that was used.
First step was to put in an extra condition. That the Credit.parent_id is that of the Users Site – with this join we would have All the Categories with ONLY the Credits that had been made. But, it wouldn’t work – that simple condition failed because the Category hasMany Credits, and the hasMany association does not LEFT JOIN in MySQL – therefore Credit.parent_id is an Unknown Column.
So what do you do when the associations fail? Break them of course. And how do you break Associations? By Creating and Destroying Associations on the Fly. It sounded like what I was looking for, and it also sounds like a cool name of a song. So I stuck with it, so thanks to ProLoser on the #cakephp irc channel.
So between the two queries above I added a simple bindModel:
‘hasMany’ => array(
‘Credit’ => array(
‘conditions’ => array(‘Credit.parent_id’ => $link[‘Link’][‘id’])
So what is really happening here is to ‘change the way an association is defined in order to sort or filter associated data’. I basically restate the hasMany association with a more exact conditions, and it applies it to the next find() – which my query with the lft and rght data in it.
It was the query I was looking for. This gives me every Category, with the related Credits by that user – weather the Credits exist or not, I still get the Categories.
So cake’s bindModel to the rescue. It was a function of cake I hadn’t used before, and quiet frankly one I never thought I’d have the use for. Truthfully, I was a little scared of it.
Finding data by the bindModel is not so hard, in fact it was rather easy. I was finding it a difficult problem to explain, and it was only after @ghostpsalm gave me a great start that I could see the forrest through the trees, as it were. It once again shows to me how cool CakePHP can be, once you get deep enough in that it needs to give you the only way out.