NamedScope for CakePHP
Article posted by Joel Moss on 20 Nov 2008   |  

I discovered the joys of NamedScope for Ruby on Rails quite a while ago now, and have always been an admirer. Its makes performing finds on models very elegant and convenient, by automagically creating model methods based on your pased scope params. Just like this:

class User < ActiveRecord::Base
  named_scope :active, :conditions => {:active => true}
  named_scope :inactive, :conditions => {:active => false}
end

# Standard usage
User.active    # same as User.find(:all, :conditions => {:active => true})
User.inactive # same as User.find(:all, :conditions => {:active => false})

Then a few months ago I read this blog post and discovered that someone had created similar functionality for CakePHP, in the form of a model behavior. Although it's not quite as powerful as it's Rails cousin, it does let you define named scopes for any model quite easily. However, I wasn't crazy about a few things.

Named Scopes are defined like this:

class User extends AppModel {
  var $actsAs = array(
    'NamedScope' => array(
      'activated' => array('User.activated in not null'),
      'online' => array('date_add(User.last_activity, interval 5 minute) > now()')
    )
  );
}

The above format means we can only pass find conditions to a named scope, and cannot pass any other params, such as ORDER and FIELDS.

Then a named scope is then called like this:

$this->User->find('all', array('scope' => 'activated'));
$this->User->find('all',
  array('conditions' => 'points > 10', 'scope' => array('activated', 'online')))

I have to pass enough params to a find call as it is, so I don't want anymore.

What I want to do is this:

class User extends AppModel {
  var $actsAs = array(
    'NamedScope' => array(
      'active' => array(
        'conditions' => array(
          'User.is_active' => true
        ),
        'order' => 'User.name ASC'
      )
    )
  );
};

and this

$active_users = $this->User->active('all');

I can even do this:

$active_users = $this->User->active('all', array(
    'conditions' => array(
        'User.created' => '2008-01-01'
    ),
    'order' => 'User.name ASC'
));

Much improved I think, and so much more powerful. So I've only gone and coded the damn thing! You can find my version of Named Scope for Cake on Codaset at http://codaset.com/joelmoss/cakephp-named-scope.

And you know what? Thanks to the power of CakePHP, the actual code is seven lines shorter than the aforementioned version.

This site contains the musings of Joel Moss, and is powered by Codaset pages; a simple, yet powerful way to host your static site. Just commit and push your site to your free Git repository at Codaset, and that's it!