Friday, March 18, 2011

Using Scopes with DataProviders

I used to use an extension called EActiveDataProvider to get this functionality, but that broke with the release of 1.1.2 or 1.1.3, I can't quite recall. Suddenly, today, it dawned on me that I could easily get this functionality once more, by simply calling the scope function of the model and then passing in the particular scope I was looking for as the criteria parameter of the CActiveDataProvider.

For example...

In model Post, I add a scope as follows:
public function scopes()
{
   return array(
      'stats'=>array(
         'select'=>'post_id',
         'condition'=>'post_status=1', 
         'order'=>'post_date DESC',
       ) 
   );
}

Then, in my controller where I want to output just this set of data:
public function actionStats()
{
    $p = new Post();
    $scopes = $p->scopes();
    $criteria = $scopes['stats'];

    // Note: I could probably just Post::model()->stats()  but I haven't 
    // tested that.

    $dataProvider = new CActiveDataProvider( 'Post', array('criteria'=>$criteria));

    ... business as usual
}

Where previously I was doing something like this to be able to take advantage of the scope:
$dataProvider = new CArrayDataProvider( Post::model()->stats()->findAll() );

While the CArrayDataProvider is an acceptable alternative, I find that it does have some peculiarities when used with a CGridView, which the CActiveDataProvider avoids.

(Note: My scope is actually quite different and more complex, but I thought this made a clearer example).

EDIT:

Apparently, I need to read more about active finders, because you can actually do THIS as well:
$dataProvider = new CActiveDataProvider( Post::model()->stats() );