Using Model->Search() To Create Dataprovider From Controller

Hi guys

Just like CGridView uses the model’s search function to create its dataprovider, I want to use the model’s search function to create a dataprovider directly from the controller (to use in CListView).

So in the controller I need something like this:

$dataprovider = new CActiveDataProvider(‘model’, ‘search’, ‘parameters’);

The parameters are passed to the search function to incorporate into the filters.

Ps. I know I can add criteria in the controller, but I want to do it in the model, because then I can re-use the model’s code from other controllers as well.

Thanx

Hi Gerhard,

Use the logical structure of gii-generated admin page. It should work with CListView instead of CGridView, just with a little modification in the view script.

Check this wiki article:

http://www.yiiframework.com/wiki/381/cgridview-clistview-and-cactivedataprovider/

Hi softark, thanx for the reply.

I don’t get this.

CGridView uses the search function:

‘dataProvider’=>$model->search(), /* you can pass parameters as well */

But CListView does not use the search function:

$dataprovider=new CActiveDataProvider(‘model’); /* no function; no parameters */

(To test it, you can just change the name of the search() function in the model and then CGridView will not work, but CListView will still work.)

So if you want to incorporate filters into the CListView dataprovider, then you have to do it with criteria in the CONTROLLER. I don’t want to do it in the controller. I want to do it in a function in the model so that I can re-use the dataprovider generation code from other controllers as well.

What am I missing here?

Well, no. What CGridView requires is an instance of CActiveDataProvider.

Model::search() function returns an instance of CActiveDataProvider.

Then, why can’t CListView use Model::search() function to get it?

[P.S.]

As you know, $model in actionAdmin is a container of search parameters. So, the following code should work for CListView.




$model = new Model('search');

$model->unsetAttributes();

$model->xxx = 'yyy';   // any filtering value that you want to apply

$dataProvider = $model->search();

$this->render('index', array('dataProvider' => $dataProvider));



OK, I get this now:

Gii generates the following (where dataprovider is generated in the controller):

Controller:




$dataProvider=new CActiveDataProvider('modelName');

/* Here you add all your filtering criteria and sorting and paging, etc. */

$this->render('index', array('dataProvider'=>$dataProvider));



View:




<?php $this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$dataProvider,

)); ?>



However, this setup is not very good because the dataProvider is generated in the controller (probably just to give us an example). But it means that you have to duplicate your dataProvider-generation-code in every controller or every method where you need it.

To generate the dataprovider in the model, you have to change things like this:

Controller:




$model=new modelName;

$this->render('index', array('model'=>$model));



View:




$this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$model->search(), /* the same as CGridView */

));



Now, all the filtering, sorting and paging is done in the model’s search function.

Example of re-using the search() function for CGridViews and CListViews:

We know that CDetailView is not very powerful if you want to display information from a model with lots of related information that also needs to be displayed.

But now you can replace CDetailView with CListView (which is powerful due to html tables and php forEach() methods) and simply display only one record’s information.

Controller:




$pk = primaryKeyOfRecordToDisplay

$model=new modelName;

$this->render('index', array('model'=>$model, 'pk'=>$pk));



View:




$this->widget('zii.widgets.CListView', array(

	'dataProvider'=>$model->search($pk), /* $pk is passed to search() function */

));



In your model, change the search() function as follows ( or if you want, create a new function to be used by CListView):




Public function search($pk=null) /* If $pk was not passed by CGridView or CListView, it defaults to null. */

{

	$criteria=new CDbCriteria;


	If ($pk !== null) {

		$criteria->compare('t.pk', $pk, false); /* if $pk was passed, then filter on it */

	}

	... more filtering and sorting criteria ...

}



Now, if $pk was passed by any CGridView or CListView, then search() will only return that one record. If $pk was not passed, then search() will return all records.

Obviously you can have CListView now displaying a single record or all the records or whatever you filtered on.

Thanks softark.

As softark has shown:

You don’t even have to pass $pk to the search() function. You can just set the pk on the model you created for filtering purposes.

But I leave the above example in case you want to pass a parameter - that is not part of the model - to search().

Thanx softark.