Published: on 3/7/08 | Comments (7)
The last week or so, I have been taking a good look at the latest release of CakePHP.
CakePHP.1.2.0.7296 RC2 is a great release, so a big pat on the back to the entire development team, and keep up the good work.
One of my favourite features of the this release is the new Containable Behaviour which was introduced back in change set 6918 and is a mixture of two behavoirs, the original Containable behavior by Felix Geisendörfer and the Bindable behavior by Mariano Iglesias.
Basically the behavior allows find operations to define restrictions on what models to get based on the 'contain' parameter, including ability to override binding settings on the fly.
Demogan.com is a site I created a few months ago to provide a service to anyone in the UK buying or selling a business, the idea came from my personal experience of selling a business in the UK last year before moving out here to the Canaries and a personal wish that there had been something like this out there at the time.
The first incarnation of the site went up in about 3 weeks and has already attracted a large membership and has a steady list of new businesses being added, and so I have begun a pretty major re-write from the ground up.
So instead of the obligatory Blog tutorial, I thought I'd show how to apply the Containable behavior to this real world example.
Each business for sale is held in a Listing model, and has amongst others, the following relationships:
Now, whilst this has been cut down from the actual site, you should see by now that a simple find('all') statement on the Listing Model is going to return a huge amount of data, not only from it's own model fields, but also from all the related models.
Using $this->Listing->recursive = -1 helps to get rid of all the sub queries but doesn't leave all the information we need to show a basic listings browser, so in the past it has been overly complicated to get just the information you require without resorting to either custom SQL queries, hash tables or any other number of little tricks, but the new Containable Behavior changes all that.
OK, to start with we'll conect up the containable behavior by the inserting the following line in our Listing Model
var $actsAs = array('Containable');
Incidentally with the lastest release there is now the ability to attach behavior on the fly so instead of inserting the above in the model, I could also do:
$this->Listing->Behaviors->attach('Containable');
With the Containable Behavior in place I can now do something like:
$this->paginate = array(
'conditions'=>array(
'Listing.active'
),
'limit'=>10,
'order'=>'Listing.created DESC',
'fields'=>array('Listing.id','Listing.title','Listing.description','Listing.price'),
'contain'=>array(
'Location.name',
'Category.name',
'Tenure.name',
'Subscription.expires',
'Image'=>array(
'conditions'=>array('Image.is_default'=>1),
'fields'=>array('Image.id','Image.caption')
)
),
);
$this->set('listings',$this->Paginate('Listing'));
Note the Contain array here, in it I can pass just the fields that I want and even another array filtered so that in this example I get just the image information I want for the image that has 'is_default' set to 1.
Of course I have only just started delving into what can be done with the Containable Behavior, for anyone looking to find out what can be done, take a look at the test cases within the new release as there are some great examples in there.
Once again, a huge slap on the back to the core CakePHP development team, 1.2 stable can't be far away now.
Hi, thanks very much for this quick tutorial and example, just what I needed and it got straight to the point. Cheers!
This is the best explaination I could find on the subject of behavior "Containable". I'm new in Cake so I was confused with this because I thought recursive attribute wa just enough. This example really explained the problem and solution. Thanks
The Containable behaviour is not a very smart design at all. It runs a query for each of the tables defined in the contain-array instead of left or inner join them with the first query.
I found a post specifying my concern. Have a look at this post: http://www.endyourif.com/cakephp-containable-statement-pitfalls/
Good observation Frode, I turned on debugging and checked my SQL log to confirm and indeed each contained model is queried independently. This makes it no better than using recursive=-1 and making each model query independently. Not super impressed.
Studio Canaria is the web site of freelance web developer, Peter Butler. Articles on this site relate to designing, developing and marketing modern web applications.
CakePHP Auth Component - Users, Groups & Permissions Revisited
CakePHP Auth Component - Users, Groups & Permissions