I have no idea how to handle these two separate paginations in the same view. Thanks for helping.
Controller code:
[...]
$this->Post->bindModel(array(
'hasAndBelongsToMany'=>array('Tag'),
'belongsTo'=>array('User')),false);
if($this->Session->check('Auth.User.id'))
$this->Post->bindModel(array(
'hasMany'=>array(
'UserVote'=>array('conditions'=>array('UserVote.user_id'=>$this->Session->read('Auth.User.id') )),
'Favorite'=>array('conditions'=>array('Favorite开发者_JAVA百科.user_id'=>$this->Session->read('Auth.User.id') ))
)), false);
$posts = $this->paginate($this->Post,array('Post.public'=>1,'Post.user_id'=>$uid));
$posts2 = $this->paginate($this->Post,array('Post.public'=>0,'Post.user_id'=>$uid));
$this->set('posts',$posts);
$this->set('posts2',$posts2);
[...]
Even though in most cases a right solution would be to rearchitect your UI to remove the need for double pagination, the following is a working solution:
First, in your controller you override Cake's paginate() function to look for paginator key:
/**
* Handles automatic pagination of model records.
*
* @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
* @param mixed $scope Conditions to use while paginating
* @param array $whitelist List of allowed options for paging
* @return array Model query results
* @access public
* @link http://book.cakephp.org/view/165/Controller-Setup
*/
function paginate($object = null, $scope = array(), $whitelist = array(), $key = null) {
$results = parent::paginate($object, $scope, $whitelist);
if ($key) {
$this->params['paging'][$key] = $this->params['paging'][$object];
unset($this->params['paging'][$object]);
}
return $results;
}
Then
/**
* undocumented function
*
* @param string $key
* @return void
* @access public
*/
function _pageForPagination($by) {
$page = 1;
$samekey = isset($this->params['named']['by']) && $this->params['named']['by'] == $by;
$pageInUrl = isset($this->params['named']['page']);
if ($samekey && $pageInUrl) {
$page = $this->params['named']['page'];
}
$this->passedArgs['page'] = $page;
return $page;
}
/**
* FIXME: Wrapper for Cake's pagination
* Change pagination criteria on the fly (conditions, grouping, order, limit)
*
* @param string $model
* @param string $criteria
* @return void
* @author Andrew
*/
function _paginateBy($key) {
$this->User->unbindModel(array('hasMany' => array('UserImage')), false);
$this->paginate['User'] = am($this->User->getCriteria($key), array('page' => $this->_pageForPagination($key)));
return $this->paginate('User', array(), array(), $key);
}
Then use it like so in the controller: $this->set('byJoinDate', $this->_paginateBy('random'));
In the model: echo $paginator->prev('prev', array('model' => $by, 'class' => 'back'), null, array('model' => $by, 'class' => 'disabled back'));
I recently had to do this very thing because I had a single HTML page that had tabs on it and in each tab was a different paginated table of the same model with different conditions for each.
The way I worked around the problem was to create dummy models that derived from the model I wanted to paginate multiple times. Then I simply referenced those dummy models for my pagination.
Example:
Base Model
class Post extends appmodel { };
Dummy Models - it is important that they use the same table as the base model
class Posts1 extends Post { var $useTable = 'posts'; }
class Posts2 extends Post { var $useTable = 'posts'; }
In your controller
function multiview($id = null) {
$this->paginate['Posts1'] = array(
'conditions'=>array('Posts1.field'=>0),
'limit'=>5
);
$this->set('posts1', $this->paginate('Posts1'));
$this->paginate['Posts2'] = array(
'conditions'=>array('Posts2.field'=>1),
'limit'=>5
);
$this->set('posts2', $this->paginate('Posts2'));
}
Then in your view
Display first paginated data
<?php foreach ($posts1 as $post): ?>
Do Paginated row display here...
<?php endforeach; ?>
<!-- Shows the page numbers -->
<?php echo $this->Paginator->numbers(array('model'=>'Posts1')); ?>
<!-- Shows the next and previous links -->
<?php echo $this->Paginator->prev('« Previous', null, null, array('class' => 'disabled')); ?>
<?php echo $this->Paginator->next('Next »', null, null, array('class' => 'disabled')); ?>
<!-- prints X of Y, where X is current page and Y is number of pages -->
<?php echo $this->Paginator->counter(); ?>
Display second paginated data
<?php foreach ($posts2 as $post): ?>
Do Paginated row display here...
<?php endforeach; ?>
<!-- Shows the page numbers -->
<?php echo $this->Paginator->numbers(array('model'=>'Posts2')); ?>
<!-- Shows the next and previous links -->
<?php echo $this->Paginator->prev('« Previous', null, null, array('class' => 'disabled')); ?>
<?php echo $this->Paginator->next('Next »', null, null, array('class' => 'disabled')); ?>
<!-- prints X of Y, where X is current page and Y is number of pages -->
<?php echo $this->Paginator->counter(); ?>
As the Pagination helper relies on the $controller->pagination field I think this is impossible. A quick hack would be to convert one or both of the paginations to Ajax-based ones. The pagination helper works very well with the Ajax helper.
Is it a good idea to have two separate paginations on a page? It looks like You're trying to paginate through public posts and non-public posts - which surely can't be done at the same time? I.e. the user won't ever be on page 3 of the public posts and page 2 of the non-public posts at the same time. The only case this would really work is via AJAX with the pagination occouring in page as suggested by matiasf.
Would it not be a better solution to just show the first x public and non public posts in the current view and create a new view to show the pagination for each accessed by a link e.g. "view all public posts" and "view all non public posts"?
精彩评论