CakePHP Custom Find Types

Posted by Matt on Fri, Oct 24 2008


The latest version of this code can be found at http://github.com/mcurry/find

A couple months ago Nate Abele wrote an article for C7Y which talked about the new find syntax in CakePHP 1.2.

CakePHP 1.2 beta introduced a new custom find syntax, where instead of calling methods like findAll(), you call methods like find(“all”). This allows for a great deal more flexibility and code reuse.

Nate further shows how you can make your own find types such as "find('popular')." Ever since I read the article I've been using this practice extensively. I would often times find myself copy and pasting the same find code in each model:

public function find($type, $options = array()) {
  switch ($type) {
    case "custom":
      return $this->__findCustom($options);
    default:
      return parent::find($type, $options);
  }
}

I was able to move this block to my AppModel and make it work for all my models:

httpc://github.com/mcurry/cakephp/raw/8f4cd9833824b80573e0de00cd69db37c87e1464/snippets/app_model_find/app_model.php

How It Works

Let's say want a custom find type which returns the latest 10 comments in your blog. Normally you might do something like this in your controller:

$comments = $this->Comment->find('all', array('conditions' => array('spam' => false),
                                              'order' => array('created' => 'desc'),
                                              'limit' => 10));

If you make a custom find type, your controller code becomes:

$comments = $this->Comment->find('latest);

Then in your Comment Model:

function __findLatest($options) {
  return  $this->find('all', array('conditions' => array('spam' => false),
                                   'order' => array('created' => 'desc'),
                                   'limit' => 10));
}

The new find method in AppModel automatically looks for a method "__findLatest" in your model. If the method exists it is called and the results returned, otherwise the parent find is called, which handles all the core find types (all, first, count...).

As always this code is available in GitHub.

Posted in CakePHP, Code

5 Comments

Fran Iglesias said on Oct 24, 2008
Hi, I really like your idea. I was wondering how to better organize the code within the find('type') method and your post give me a good start point. Thanks.
Matt said on Oct 24, 2008
Fran - Thanks. I'm glad this will help.

Dardo - I'm sure I read that post, but for some reason it felt completely new to me. Anyway, the two things I don't like about that method are having keep a list of find methods and dealing with the before/after logic. Even Daniel concludes "I'm not sure whether this approach should be really used, as the approach with overriding the find() method seems to be easier." Thanks for pointing it out.
Dardo Sordi said on Oct 25, 2008
Matt, in the comments of that article Taylor posted ( and Rafael fixed ) a snippet for AppModel that finds the defined _findMethods and adds them to $this->_findMethods making them directly accesible via the buil-in Model::find()
Matt said on Oct 27, 2008
Dardo,
Thanks. I missed the comments. It looks like another good solution. Either one works. It really depends on preference and if you need the before/after calls.