[EXTENSION] remember-filters-gridview

The ERememberFiltersBehavior extension adds up some functionality to the default possibilites of CActiveRecord/Model implementation.

It will detect the search scenario and it will save the filters from the GridView during navigation. This comes handy when you need to store them for later use. For heavy navigation and heavy filtering, this functionality can be activated by just a couple of lines.

1217

remember_filters_10.png

Requirements

  • Yii 1.1

Download

Donate

Click here to donate

Resources

Remember-filters-extension

Report a bug

Usage

To use this extension, just copy this file to your components/ directory, add ‘import’ => ‘application.components.ERememberFiltersBehavior’, […] to your config/main.php and paste the following code to your behaviors() method of your CActiveRecord/Model




public function behaviors() {

   	return array(

   		'ERememberFiltersBehavior' => array(

       		'class' => 'application.components.ERememberFiltersBehavior',

   		),

   	);

}



For up to date documentation see: Remember-filters-extension

This extension has also a pair Clear Filters Gridview

Thanks for you Behavior.

Ah!!! how to use? no how to install if not how to use?, in a session i know, but i feel something missing?

thanks.

it is very easy, you use like any other behavior you bind at the behaviors() method

  1. download the zip file

  2. put the php file from the zip in the protected/c[color="#1C2837"]omponents folder[/color]

[color="#1C2837"]3. edit your protected/config/main.php configuration file and add to [/color][color="#1C2837"]‘import’ => ‘application.components.ERememberFiltersBehavior’[/color]

[color="#1C2837"]4. go to the model/CActiveRecord you are using for your search display and add to behaviors(), this method might not exists, so in that case just add this method[/color]




class MyClassName extends CActiveRecord {


......


// add or extend the below function

public function behaviors() {

   	return array(

       	'ERememberFiltersBehavior' => array(

           	'class' => 'application.components.ERememberFiltersBehavior',

       	),

   	);

}


public function search() {

// your existing search method that will filter the grid, no need to touch it here

}

.....

}

Hi,

I have a problem, my code is below:




        $model=new Product('search');

        $model->unsetAttributes();  // clear any default values

      

        if (intval(Yii::app()->request->getParam('clearFilters'))==1) {

            EButtonColumnWithClearFilters::clearFilters($this,$model);//where $this is the controller

        }


        if (isset($_GET['pageSize'])) {

            Yii::app()->user->setState('Product_pageSize',(int)$_GET['pageSize']);

            unset($_GET['pageSize']);

        }


        if(isset($_GET['Product']))

        {

            $model->attributes=$_GET['Product'];

        }

        else

        {

            $model->status = Product::ACTIVE;

        }


        $merge = new CDbCriteria;

        $merge->order = '`name` ASC';


        $this->render('admin',array(

                'model'=>$model, 'merge'=>$merge,

        ));



I need to put the else clause because I want by default it is display only active product. If I implement the remember filter extension, my code become




        $model=new Product('search');

      

        if (intval(Yii::app()->request->getParam('clearFilters'))==1) {

            EButtonColumnWithClearFilters::clearFilters($this,$model);//where $this is the controller

        }


        if (isset($_GET['pageSize'])) {

            Yii::app()->user->setState('Product_pageSize',(int)$_GET['pageSize']);

            unset($_GET['pageSize']);

        }


        $merge = new CDbCriteria;

        $merge->order = '`name` ASC';


        $this->render('admin',array(

                'model'=>$model, 'merge'=>$merge,

        ));



Where can I put the else clause if the filter is not set?

Cheers,

Daniel

@Daniel

[color=#222222][font=Arial, sans-serif][size=2]I’ve updated the extension to include support for defaults. Please setup the behavior in your model file, and there you can now set defaults. Donation is welcome for implementing this functionality in for you.[/size][/font][/color]

Hi Pentium10,

Little surprise for you…hope you like it, although it is very small.

Actually, later that night, I got the workaround like this:

ProductController.php :




    public function actionAdmin()

    {

        $model=new Product('search');

      

        if (intval(Yii::app()->request->getParam('clearFilters'))==1) {

            EButtonColumnWithClearFilters::clearFilters($this,$model);//where $this is the controller

        }


        if (isset($_GET['pageSize'])) {

            Yii::app()->user->setState('Product_pageSize',(int)$_GET['pageSize']);

            unset($_GET['pageSize']);

        }


        if(!isset($_GET['Product']))

        {

            $model->status = Product::ACTIVE;

        }


        $merge = new CDbCriteria;

        $merge->order = '`name` ASC';


        $this->render('admin',array(

                'model'=>$model, 'merge'=>$merge,

        ));

    }



But, I am not sure whether this portion of code will give me a trouble in the future…




        if(!isset($_GET['Product']))

        {

            $model->status = Product::ACTIVE;

        }



your solution is much better. Especially, I like the ‘defaultStickOnClear’.

Thx a lot.

Hi Pentium10,

Just wondering, does remember-filters-gridview can also remember the sort attributes?

Cheers,

Daniel

Not yet. It is work in progress, but stuck on the way how we can create behaviors for [color=#454545][font=arial, helvetica, sans-serif][size=2]CActiveDataProvider. Refer to this ticket for the problem I encountered. [/size][/font][/color]

I am using remember-filters-gridview and like it very much. I also want to remember sort order; but see the problem of not being able to attach a behavior to CActiveDataProvider.

Why not extend CActiveDataProvider and implement the necessary functionality there? I have already extended CActiveDataProvider as MyActiveDataProvider, which I use in all my model.search() methods. You can override CActiveDataProvider__construct() to do the same things as you would have done in onAfterConstruct. Of course make sure to call the parent __construct() before or after your code as appropriate.

I’d do this myself but I’m not yet clear what needs to be added to CActiveDataProvider to remember the sorting. The fetchData() method does the real work; it calls applyOrder() to add the ordering. Looks like maybe the answer is to override CActiveDataProvider.fetchData(). Instead of calling $sort->applyOrder(), it would retrieve and re-apply the saved sort criteria. But I’m not too clear on the implementation.

Thoughts?

  • Jeremy

It is definitely a good a idea to consider.

This week I won’t have time, but I will try to schedule in the upcoming period.

I was able to add this function without modifying CActiveDataProvider at all. Just put this code into actionAdmin() of your controller. In my case I put it in the class which is the parent of all my controllers, so it’s inherited.

in MyParentController.php / actionAdmin() :




    	$sortCacheID = $this->id . '_sort';

    	$sorts = array();

    	foreach ($_GET as $g=>$gval) {

        	if (strpos($g, '_sort'))  {

       			$sorts[$g]=$gval;

        	}

    	}

    	if ($sorts != array()) {

        	// user requested sort(s); overrides anything set previously and cache the sorts

        	Yii::app()->user->setState($sortCacheID, $sorts);

    	} else {

        	// no sorts in get; use cached values if present

        	$sorts = Yii::app()->user->getState($sortCacheID, array());

        	foreach ($sorts as $s=>$sval) {

                  	$_GET[$s] = $sval; // as if they were requested; will be consumed by grid widget in admin view

        	}

	}



what about remembering the page? is that future feature?

Do you mean the page number from pagination?

yes, click page number 7, go to edit one of the items and when go back to the the list. the filter option was saved but it is back on page 1 instead of 7

It would be a good feature indeed. Thanks for the suggestion.

First I have to figure out how to read out the page number, as that is not posted with the search keywords

And second I need to find the free time, or the budget to implement it. I’ve got only 1 donation for this great extension. And donations are welcomed.

Probably it will be offered as a paid version of the plugin, (I am considering this).

The methods setCurrentPage() and getCurrentPage() of CPagination should give you thos values…

Cool, thanks for the suggestion.

Here’s my solution, which does not use the CPagination methods as mentioned. It’s a bit long, but works. (Part of the reason for extending the framework classes is I’ve removed another part of my solution which includes a drop-down control in each admin view to select the pageSize for this model and remember it in persistent storage, which is outside the scope of this thread.)

This solution would be trivial (just part [4]) except for the fact that CPagination omits the pageNo on the first page. This causes problems. In order to fix this you must extend CPagination, extend CActiveDataProvider to use it, and extend all your models to use the new ActiveDataProvider class.

  1. extend CPagination as MyPagination and override createPageUrl to always include the pageNo in the URL.



class MyPagination extends CPagination

{

	// always put the page number in.  See MyController.actionAdmin() for usage

	public function createPageUrl($controller,$page)

	{

		$params=$this->params===null ? $_GET : $this->params;

	//	if($page>0) // page 0 is the default

			$params[$this->pageVar]=$page+1;

	//	else

	//		unset($params[$this->pageVar]);

		return $controller->createUrl($this->route,$params);

	}

} 



  1. extend CActiveDataProvider as MyActiveDataProvider. override getPagination to use MyPagination



class MyActiveDataProvider extends CActiveDataProvider {

private $_pagination;


    // override to create instance of MyPagination

    public function getPagination() {

        if ($this->_pagination === null) {

            //$this->_pagination=new CPagination;

            $this->_pagination = new MyPagination;

            if (($id = $this->getId()) != '')

                $this->_pagination->pageVar = $id . '_page';

        }

        return $this->_pagination;

    }

}



  1. in all your models, change search() to use MyActiveDataProvider instead of CActiveDataProvider



	public function search() {

  	$criteria = new CDbCriteria;  

....

    	return new MyActiveDataProvider(get_class($this), array(

        	'criteria' => $criteria,

    	));



  1. (either) extend CController as MyController. Make all your controllers extend from MyController. Each controller must define $modelClass. In this case, the child controllers don’t have an actionAdmin. (or) simply put the code fragment into the actionAdmin() of each controller.



public $modelClass = ''; // child must define actual Model name

...

actionAdmin()

...

    	// persist page number

    	$pageParam = ucfirst($this->modelClass) . '_page';

    	if (isset($_GET[$pageParam])) {

        	$page = $_GET[$pageParam];

        	Yii::app()->user->setState($this->id . '-page', (int) $page);

    	} else {

        	$page = Yii::app()->user->getState($this->id . '-page', 1);

        	$_GET[$pageParam] = $page;

    	}

...



it’s not working for me, after comming back it’s on page 1, while i left the page on page 7…


public $modelClass = '';

	/**

	 * Manages all models.

	 */

	public function actionAdmin()

	{

		$model=new Daytrip('search');

		//$model->unsetAttributes();  // clear any default values

		//if(isset($_GET['Daytrip']))

			//$model->attributes=$_GET['Daytrip'];


        $pageParam = ucfirst($this->modelClass) . '_page';

        if (isset($_GET[$pageParam])) {

                $page = $_GET[$pageParam];

                Yii::app()->user->setState($this->id . '-page', (int) $page);

        } else {

                $page = Yii::app()->user->getState($this->id . '-page', 1);

                $_GET[$pageParam] = $page;

        }




		$this->render('admin',array(

			'model'=>$model,

		));

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

	 */

	public function search()

	{

		// Warning: Please modify the following code to remove attributes that

		// should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id_daytrip',$this->id_daytrip);


		$criteria->compare('daytrip',$this->daytrip,true);


		$criteria->compare('city_id',$this->city_id);


		$criteria->compare('active',$this->active);


		return new MyActiveDataProvider('Daytrip', array(

			'criteria'=>$criteria,

		));

	}