Yii 1.1: Quick Tip about Pagination Params

8 followers

Developing custom Grids and ListViews for my new CMS I was facing a small challenge: If I was to update/delete/batch delete items of my Grid, how would I return to the current page view?

I know there a couple of extensions out there, but I do extensive use of AJAX into my applications. Once a user logs in, the rest in my CMSs are pure AJAX, so the extensions where of no HELP in this scenario.

If you check at the parameters of the pagers you see the parameter name to be on the format of: Modelname_page.

In order to solve the issues (I wont expose the solution of the custom widgets and components because they have to do with the CPagination object) of returning back to the current page displayed I did this:

// in my globals.php -this file is imported on index.php
 
/**
 * Returns the named HTTP parameter.
 * This is the shortcut to Yii::app()->request->getParam($name)
 */
function getParam($name, $default=false){
    return Yii::app()->request->getParam($name, $default);
}
 
/**
 * Returns an array of matched Page parameters
 * based on the Model name given
 */
public function getPaginationParam( $modelName ){
    // format name appropiately *no misstyping errors allowed*
    $modelName = ucfirst(strtolower($modelName));
    // return the param
    return getParam($modelName.'_page') ? array($modelName.'_page'=>getParam($modelName.'_page')):array();
}

Once I have that function, I can find out whether a pagination parameter was submitted or not. Let's imagine a user clicks on the delete button and the actionDelete of the Bogus controller is called, I would like after deletion to return to the admin display of Bogus Models and to continue on the same page.

public function actionDelete(){
 if(Yii::app()->request->isPostRequest)
 {
   // we make use of getParam -see above
   // we should check whether the param 
   // returns false or not!!! This is too simple
   $this->loadModel( getParam('id') )->delete();
   //
   // lets get the page params of bogus if any
   $params = getPaginationParam('bogus');
   //
   // create the url appropiately
   $route = $this->createUrl('admin',$params);
   //
   // redirect to admin and finish
   $this->redirect($route,true);
 
 }catch(Exception $e){
   ....

Easy right? Now, what about update? Well, in my case, what I did, is to include a hidden field into the form if there is a page parameter and on submission i do the same on the actionUpdate as I did on the actionDelete of the controller.

Total 2 comments

#6105 report it
jpj at 2011/12/13 07:27am
Modification

I've used the example here without creating MyActiveDataProvider class. I've only modified the actionAdmin method like this, up to now, it works well:

// at the top of every controller
    $this->modelClass = '<modelName>';  // the data model of this controller
 
    public function actionAdmin {
        $pageParam = ucfirst($this->modelClass). '_page';
        if (isset($_GET[$pageParam])) {
            $page = $_GET[$pageParam];
            Yii::app()->user->setState($this->id.'-page',(int)$page);
        } else {
            // If no param for page number but param grid exists
            if(isset($_GET['ajax']) && $_GET['ajax'] == $this->modelClass . '-grid')
            {
                // We're on the first page
                $page = 1;
            } else {
                $page=Yii::app()->user->getState($this->id.'-page',1);
                $_GET[$pageParam] = $page;
            }
        }
        ...
   }
#2801 report it
jeremy at 2011/02/11 11:30pm
put all logic in actionAdmin

A simpler way to set & retain page number is to put all the logic in actionAdmin. Even better, move the actionAdmin to a parent class for all your controllers; or change the Gii generation templates so all controllers get this code:

// at the top of every controller
    $this->modelClass = '<modelName>';  // the data model of this controller
 
    public function actionAdmin {
        $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;
        }
        ...
   }

the only problem is with the First (<<) button, and Previous (<) button on page 2, which do not contain explicit page 1, just the URL for the basic grid view. Without the patches below, these buttons will not work.

Fixing this involves the following:

  • create MyActiveDataProvider and override getPagination() method:
class MyActiveDataProvider extends CActiveDataProvider
{
    private $_pagination;
    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;
    }
}
  • create MyPagination and override createPageUrl() to always include a page number:
class MyPagination extends CPagination
{
    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);
    }
}
  • in each model.Search() method, use MyActiveDataProvider:
public function search()
    {
        $criteria=new CDbCriteria;
        ....
        return new MyActiveDataProvider(get_class($this), array(
            'criteria'=>$criteria,
        ));
    }

Leave a comment

Please to leave your comment.

Write new article
  • Written by: Antonio Ramirez
  • Category: Tips
  • Yii Version: 1.1
  • Votes: +6
  • Viewed: 24,836 times
  • Created on: Dec 17, 2010
  • Last updated: Dec 17, 2010
  • Tags: Pagination