Saturday, July 12, 2008

Merging ContainableBehavior and PaginatorHelper

This is an update to another article, Taming Containables in CakePHP 1.2. You might want to read it first.


Paginator and Containable are both great, but the documentation is wholly inadequate in discussing how to combine their functionality. After scouring the Cake libraries and existing documentation, however, I have found The Way:

var $paginate = array(
    'limit' => 10,
    'order' => array(
      'Segment.name' => 'asc',
      'Unit.label' => 'asc'
    ),
    'recursive' => 2,
    'conditions' => null,
    'contain' => array(
          'Rental' => array(
            'conditions' => array('Rental.active' => 1),
            'fields' => array('Rental.active', 'Rental.expires'),
            'Contact' => array (
              'fields' => array('Contact.id', 'Contact.forename', 'Contact.surname')
            )
          ),
          'Control',
          'Segment'
        )
  );


This code now appears in my UnitsController. You'll note a few differences from the previous version, however.

I have consolidated Rental using standard Model::find('all') syntax and I can now select my fields and conditions without worrying about order precedence.

More interesting still, ContainableBehavior seems to implicitly extend to all sub-arrays, allowing me to provide still more conditions and fields to those aspects.

The inherent possibilities for creating complex multi-model AJAX filters are very promising.

You may also be wondering why I set $paginate['conditions'] to null. I want to be able to programmatically add dynamic filters to the Units model, so this provides an easy way in. It also seems to make PHP happier at runtime if I don't attempt to add that array element. Since the conditions aren't applied until the Model::paginate function is actually called, there is no significant performance or capability hit.

Hint: This also means that we can very heavily alter our paginate variable within functions, for those not uncommon cases where you'll be paginating very different lists within the same controller.

1 comment:

Silver Knight said...

Thank you for this informative and educational post. Only one little detail I thought I'd point out:

From the article: "but the documentation is wholly inadequate"

You are probably already aware of this, but in case anyone else is not yet aware of it, the most recent CakePHP documentation supports direct user contributions, so anyone can go ahead and freely submit improvements in those places where they think it might help. ;)