Yii Framework Forum: Pagination solution [simple and complex ways] - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Pagination solution [simple and complex ways] Tutorial for BEGINNERS to use the pagination widget Rate Topic: ***** 4 Votes

#1 User is offline   alexFidelis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 34
  • Joined: 17-November 11

Posted 17 November 2011 - 02:08 PM

First, I’m new in Yii, so if I’m not with the framework standards, please notify me!

I had some problem with pagination and searching for it I found a lot of explanations but none worked well. Messing around I made to solutions:
1 – pagination for simple query
2 – Pagination for complex queries (multiple tables etc)


First, define a new param at config/main.php. Find it at last lines

'params'=>array(
        'listPerPage'=> 10, // <-- insert this line with the number you prefer




1. Simple way

CONTROLLER
// just an example to “illustrate” the tutorial, make the proper adaptations

$criteria = new CDbCriteria();
       $criteria->condition = 'collumnName1 = :id';
       $criteria->order = 'id DESC';
       $criteria->params = array (':id'=>$id);
       
        $item_count = ModelNameX::model()->count($criteria);
                
        $pages = new CPagination($item_count);
        $pages->setPageSize(Yii::app()->params['listPerPage']);
        $pages->applyLimit($criteria);  // the trick is here!
        
         $this->render('index',array(
    			'model'=> ModelNameX::model()->findAll($criteria), // must be the same as $item_count
                'item_count'=>$item_count,
                'page_size'=>Yii::app()->params['listPerPage'],
                'items_count'=>$item_count,
                'pages'=>$pages,
	));


VIEW
$data = array();
foreach($model as $m){  // loop to get the data (this is different from the complex way)
$data[] = $m->attributes;
}

// the pagination widget with some options to mess
$this->widget('CLinkPager', array(
	    'currentPage'=>$pages->getCurrentPage(),
	    'itemCount'=>$item_count,
	    'pageSize'=>$page_size,
	    'maxButtonCount'=>5,
	    //'nextPageLabel'=>'My text >',
	    'header'=>'',
        'htmlOptions'=>array('class'=>'pages'),
	));


--------------------------------------------------------------------------------------------------------------

2. Complex Way

CONTROLLER
// just an example to “illustrate” the tutorial, make the proper adaptations

$page = (isset($_GET['page']) ? $_GET['page'] : 1);  // define the variable to “LIMIT” the query
        

        $query1 = Yii::app()->db->createCommand() //this query contains all the data
        ->select(array('t2.*'))
        ->from(array('table1Name t1', 'table2Name t2'))
        ->where('t1.collumName = '.$id.' AND t2. collumName = t1. collumName and t2. collumName > now()')
        ->order('t2. collumName DESC')
        ->limit(Yii::app()->params['listPerPage'], $page-1) // the trick is here!
        ->queryAll();
        
        $item_count = Yii::app()->db->createCommand() // this query get the total number of items,
        ->select('count(*) as count')
        ->from(array('table1Name t1', 'table2Name t2')) // must be the same as $query1 !!!!
        ->where('t1. collumName = '.$id.' AND t2.id = t1. collumName and t2. collumName > now()') // must be the same as $query1 !!!!
        ->queryAll(); // do not LIMIT it, this must count all items!

// the pagination itself
        $pages = new CPagination($item_count);
        $pages->setPageSize(Yii::app()->params['listPerPage']);

// render
        $this->render('view',array(
            'query1'=>$query1,
            'item_count'=>$item_count,
            'page_size'=>Yii::app()->params['listPerPage'],
            'pages'=>$pages,
		));


VIEW

foreach($query1 as $q){} // loop to get data

// the pagination widget with some options to mess
$this->widget('CLinkPager', array(
                            	    'currentPage'=>$pages->getCurrentPage(),
                            	    'itemCount'=>$item_count,
                            	    'pageSize'=>$page_size,
                            	    'maxButtonCount'=>5,
                            	    //'nextPageLabel'=>'My text >',
                            	    'header'=>'',
                                    'htmlOptions'=>array('class'=>'pages'),
                            	));

1

#2 User is offline   phyllus 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 07-October 11
  • Location:Goiânia GO Brazil

Posted 17 November 2011 - 02:24 PM

Nice tutorial. Thanks!
0

#3 User is offline   rgb 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 9
  • Joined: 25-November 11

Posted 05 December 2011 - 03:56 PM

I tried out the complex way and ended up getting the following error: Fatal error: Unsupported operand types in ....\Yii\framework\web\CPagination.php on line 144. Not able to figure out what went wrong. Any help?
0

#4 User is offline   tburandt 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 04-December 11

Posted 08 December 2011 - 02:36 PM

Thank you! Keep em coming.
0

#5 User is offline   alexFidelis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 34
  • Joined: 17-November 11

Posted 10 December 2011 - 12:06 PM

View Postrgb, on 05 December 2011 - 03:56 PM, said:

I tried out the complex way and ended up getting the following error: Fatal error: Unsupported operand types in ....\Yii\framework\web\CPagination.php on line 144. Not able to figure out what went wrong. Any help?



- Are you using Yii 1.1.8? I made this script in it.
- This error is happening in controller or in view?
0

#6 User is offline   switcher 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 03-February 12

Posted 03 February 2012 - 07:03 AM

View PostalexFidelis, on 10 December 2011 - 12:06 PM, said:

- Are you using Yii 1.1.8? I made this script in it.
- This error is happening in controller or in view?


Hi! I have the same issue. It's Yii 1.1.8 and this error is happening in the view.

I've changed queryAll() to queryRow() at $item_count and gave to a widget this 'itemCount'=>$item_count['count'] (instead of 'itemCount'=>$item_count).

It has fixed an error, but only at the first page. When I tried to go to another page the error comes up again.
Also, the first page gives an error if there's "...&page=1" in the address.

PS it's complex way
PPS i'm new to Yii :)

upd Just updated to 1.1.9, now it's the same error at line 152
0

#7 User is offline   alexFidelis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 34
  • Joined: 17-November 11

Posted 04 March 2012 - 08:32 AM

View Postswitcher, on 03 February 2012 - 07:03 AM, said:

Hi! I have the same issue. It's Yii 1.1.8 and this error is happening in the view.

I've changed queryAll() to queryRow() at $item_count and gave to a widget this 'itemCount'=>$item_count['count'] (instead of 'itemCount'=>$item_count).

It has fixed an error, but only at the first page. When I tried to go to another page the error comes up again.
Also, the first page gives an error if there's "...&page=1" in the address.

PS it's complex way
PPS i'm new to Yii :)

upd Just updated to 1.1.9, now it's the same error at line 152



Sorry, just now I saw your reply. Copy/Paste the error line here. This code still working like a charm for me here.
0

#8 User is offline   Backslider 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 358
  • Joined: 23-July 09

Posted 04 June 2012 - 11:53 PM

The "Complex Way" above simply does not work. Try this:

  $sql = 'SELECT t2.* FROM table1Name t1, table2Name t2 WHERE t1.collumName = '.$id.' AND t2. collumName = t1. collumName and t2. collumName > ' . new CDbExpression('now()');

  $count_query = 'select count(*) FROM table1Name t1, table2Name t2 WHERE t1.collumName = '.$id.' AND t2. collumName = t1. collumName and t2. collumName > ' . new CDbExpression('now()');

  $item_count = Yii::app()->db->createCommand($count_query)->queryScalar();

  $dataProvider=new CSqlDataProvider($sql, array(
    'keyField'=>'id',
    'totalItemCount'=>$item_count,
    'pagination'=>array(
      'pageSize'=>Yii::app()->session['pageSize'],
    ),
  ));

  $model = $dataProvider->getData();

  $this->widget('CLinkPager',array(
    'pages'=>$dataProvider->pagination));

  foreach($model as $val) {
    // do stuff
  }



We were all once expert at....... nothing.

yii-language-behavior

My Blog
1

#9 User is offline   natebrp 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 31
  • Joined: 22-May 12

Posted 27 June 2012 - 04:34 PM

This is great thanks!!!

but why did you include $item_count twice in your simple version render parameters?
0

#10 User is offline   dlamichhane 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 05-March 12

Posted 04 July 2012 - 01:14 AM

Great tutorial work, i have implemented the Simple way. I didn't understand why have you used the $item_count twice. I think there is no use of sending the parameter $item_count to the view twice.
0

#11 User is offline   dlamichhane 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 05-March 12

Posted 09 July 2012 - 05:10 AM

I had also followed the complex way for the pagination but it doesn't splits my items into multiple pages, it just puts all the items onto one page, although it gives the Pager link below all the items.

Thanks in advance.
0

#12 User is offline   Abuthakir 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 16-August 12

Posted 02 September 2012 - 02:54 PM

View Postdlamichhane, on 09 July 2012 - 05:10 AM, said:

I had also followed the complex way for the pagination but it doesn't splits my items into multiple pages, it just puts all the items onto one page, although it gives the Pager link below all the items.

Thanks in advance.


The complex way added by alexFidelis is having some issue, but I am unable to found and fix the problem. With the help of solution added by Backslider I achieved the custom pagination with the following code.

public function actionIndex()
{
    $conditions = array();
    $params = array();
    $model=new TransactionCategories();
    if(isset($_GET['TransactionCategories'])){
        $model->attributes = $_GET['TransactionCategories'];
        if (!empty($_GET['TransactionCategories']['name'])){
            $conditions = 'tc.name like "%' . $_GET['TransactionCategories']['name'] . '%"';
            $params = array (':name' => $_GET['TransactionCategories']['name']);
        }
    }
    $transactionCategoriesCount = Yii::app()->db->createCommand()
    ->select('count(*) as count')
    ->from('transaction_categories tc')
    ->where($conditions, $params)
    ->queryScalar();
    $transactionCategoriesSQL = Yii::app()->db->createCommand()
    ->select('tc.id, tc.created, tc.name, tc.transaction_count')
    ->from('transaction_categories tc')
    ->where($conditions, $params);
    $transactionCategoriesDP=new CSqlDataProvider($transactionCategoriesSQL->text, array(
            'totalItemCount'=>$transactionCategoriesCount,
            'sort'=>array(
                    'attributes'=>array(
                            'tc.id', 'tc.created', 'tc.name',
                    ),
            ),
            'pagination'=>array(
                    'pageSize'=> Yii::app()->params['listPerPage'],
            ),
    ));
    $this->render('index',array(
            'transactionCategoriesDP' => $transactionCategoriesDP,
            'transactionCategoriesCount' => $transactionCategoriesCount,
            'model' => $model
    ));
}


View Code

<?php 
$transactionCategories = $transactionCategoriesDP->getData();
$form=$this->beginWidget('CActiveForm', array(
		'action'=>CHtml::normalizeUrl(array('transactionCategories/gupdate')),
		'id'=>'transaction-categories-form',
		'enableAjaxValidation'=>false,
));
?>
<div class="grid-view">
	<table class="items">
		<thead>
			<tr>
				<th>&nbsp;</th>
				<th><?php echo $transactionCategoriesDP->getSort()->link('tc.id', 'ID');?>
				</th>
				<th><?php echo $transactionCategoriesDP->getSort()->link('tc.created', 'Created');?>
				</th>
				<th><?php echo $transactionCategoriesDP->getSort()->link('tc.name', 'Name');?>
				</th>
				<th>Actions</th>
			</tr>
		</thead>
		<tbody>
			<?php 
			if (!empty($transactionCategories)){
	foreach($transactionCategories as $transactionCategorie){
?>
			<tr class="odd">
				<td><?php echo $form->checkBox($model,'id[]', array('value' => $transactionCategorie['id'])); ?>
				</td>
				<td><?php echo $transactionCategorie['id'];?></td>
				<td><?php echo $transactionCategorie['created'];?></td>
				<td><?php echo $transactionCategorie['name'];?></td>
				<td><?php 
				echo CHtml::link('Update', array('/transactionCategories/update/id/' . $transactionCategorie['id']));
				echo CHtml::linkButton('Delete', array(
			         'submit'=>array('transactionCategories/Delete', 'id' =>$transactionCategorie['id']),
			         'params'=>array('id' =>$transactionCategorie['id']),
					'confirm'=>"Are you sure want to delete this data ?"
				));
			?>
				</td>
			</tr>
			<?php	
	}
}else{
?>
			<tr class="">
				<td colspan="100">Sorry no records found</td>
			</tr>
			<?php 
}
?>
		</tbody>
	</table>
</div>
<div class="row buttons">
	<?php echo CHtml::dropDownList('action', null, array('' => 'Select', 'delete' => 'Delete')); ?>
	<?php echo CHtml::submitButton('Update'); ?>
</div>
<?php $this->endWidget(); ?>
<?php
$this->widget('CLinkPager', array(
                                   'itemCount'=> $transactionCategoriesCount,
                                   'pageSize'=> Yii::app()->params['listPerPage'],
                                   'maxButtonCount'=> 10,
                                   'nextPageLabel'=>'Next >>',
                                   'header' => 'Go to page::',
                                    //'htmlOptions'=>array('class'=>'pages'),
                                ));
?>

0

#13 User is offline   Und_rscore 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 18-September 12

Posted 18 September 2012 - 03:06 AM

Just a little improvement about the semantic, what a lot of you call $model should instead be called $objects, unless you really retrieve Models from your DB :D
0

#14 User is offline   swedge218 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 9
  • Joined: 01-January 13

Posted 28 June 2013 - 03:32 AM

backslider's solution is just cool. Straight and sweet. However, I made a variant of it after seeing his. I used CArrayDataProvider instead of the CSqlDataProvider he used. The former lets you use either raw sql or AR objects. This is useful if your query returns AR objects (e.g. from a get method) or if your views, especially the partials are expecting AR objects and not datareader arrays as when using raw sql. See AR example like so

In a contoller method
    $pageSize=5; 
    $products = $this->doSearch($searchterm); //returns AR objects
    $count = count($products);
             

             $dataProvider= new CArrayDataProvider($products, array(
                'sort'=>array('attributes'=>array('product_id')),   //you can sort here if objects not sorted
                'pagination'=>array('pageSize'=>$pageSize),
              ));
            
             $models = $dataProvider->getData();

             
             $this->render('search', array(
                    'models' => $models,
                    'dataProvider' => $dataProvider, 
                    'itemCount' => $count,
             ));


And on the view
  foreach($models as $model){
     ...
     ...
   }

   $this->widget('CLinkPager', array(
                                'pages'=>$dataProvider->pagination,
                    ))


Hope this helps somebody.
Cheers
1

#15 User is offline   Giris 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 45
  • Joined: 12-November 13

Posted 14 November 2013 - 01:48 AM

Great tutorial. Has anyone tried pagination after advanced search. The first page seems to load properly but it doesn't load from the second page onwards.
0

#16 User is offline   danschmidt5189 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 55
  • Joined: 19-February 13

Posted 14 November 2013 - 06:56 PM

You don't have to add a separate application parameter to manage widget settings.

To modify widgets app-wide, use the CWidgetFactory component:

Yii::app()->widgetFactory->widgets["CLinkPager"]["pageSize"] = 42;


You could even extend and override the component to return dynamic configurations, e.g. those specified by the user.
0

#17 User is offline   hajdar 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 16-November 13

Posted 17 November 2013 - 03:27 PM

Thanks, great tutorial
0

#18 User is offline   nkovacs 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 19-August 12

Posted 02 April 2014 - 02:15 AM

View Postswedge218, on 28 June 2013 - 03:32 AM, said:

backslider's solution is just cool. Straight and sweet. However, I made a variant of it after seeing his. I used CArrayDataProvider instead of the CSqlDataProvider he used. The former lets you use either raw sql or AR objects. This is useful if your query returns AR objects (e.g. from a get method) or if your views, especially the partials are expecting AR objects and not datareader arrays as when using raw sql. See AR example like so

In a contoller method
    $pageSize=5; 
    $products = $this->doSearch($searchterm); //returns AR objects
    $count = count($products);
             

             $dataProvider= new CArrayDataProvider($products, array(
                'sort'=>array('attributes'=>array('product_id')),   //you can sort here if objects not sorted
                'pagination'=>array('pageSize'=>$pageSize),
              ));
            
             $models = $dataProvider->getData();

             
             $this->render('search', array(
                    'models' => $models,
                    'dataProvider' => $dataProvider, 
                    'itemCount' => $count,
             ));


And on the view
  foreach($models as $model){
     ...
     ...
   }

   $this->widget('CLinkPager', array(
                                'pages'=>$dataProvider->pagination,
                    ))


Hope this helps somebody.
Cheers


The problem with this solution is that it loads ALL the records in the database into memory (and then sorts them in php, which will likely be slower than sorting in the database). If your table has lots of rows, this can be very slow or might even hit the memory limit. You should use a CActiveDataProvider, so that you only load the current page's worth of data from the database. If you need the flexibility to use either raw sql or AR objects, you can use either CSqlDataProvider or CActiveDataProvider as needed, that's why they're descendants of the same CDataProvider class.
0

#19 User is offline   nawin 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 15-March 14
  • Location:இந்தியா, தமிழ்நாடு (India,TamilNadu)

Posted 02 May 2014 - 04:55 AM

View Postswedge218, on 28 June 2013 - 03:32 AM, said:


$this->widget('CLinkPager', array(
'pages'=>$dataProvider->pagination,
))

Thanks buddy this code saves my job. :D
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

2 User(s) are reading this topic
0 members, 2 guests, 0 anonymous users