开发者

Pagination with hasMany association cakePHP

I have two tables:

Contestant and Votes Contestant hasMany Votes

I've tried doing a count(Vo开发者_高级运维te.id) as Votes so I can place it on the recordset and just paginate them but I have no idea where to place it. I did it on the fields array but it gave me the total count of votes regardless of the contestant they belong to.

The votes are linked together in the Contestant recordset so what I did was on my view I did a count($contestant[Vote]) but this can't be paginated and my client wants to be able to sort the contestants by votes.

Is there a way I can do something like this on my view?:

sort('Votes', 'count(Vote)'); ?>

Or do I have to create a query which does a count for all the votes where Contestant.id = Votes.contestant_id ?

Controller Contestant:

function index() {
            $page = 'Contestants';
            $this->set('page', $page);
            $this->paginate =
            array(
                    'order' => 'id ASC',
                    'contain' => array(
                            'Vote' => array(
                                    'fields' => array("Vote.contestant_id",'Vote.id')
                            )
                    )
            $conditions ["Contestant.active"] = 1;
            $this->set('contestants', $this->paginate('Contestant',

$conditions)); }


Check out deceze's response in this question: CakePHP mathematic-calculation field?

Essentially you want to do something like this I'm guessing:

'contain' => array(
    'Vote' => array(
        'fields' => array('SUM(Vote.id) AS Contestant__votes'),
        'group'  => array('Vote.contestant_id'),
    )
)


Since cakephp doesn't support group by in containable behavior I tried a different approach. Create the paginate var for the vote model instead (All of this is done in the Contestants Controller):

var $paginate = array(
    'Vote'=>array(
        'limit'=>5,
        'fields' => array(
        'Contestant.*, count(Vote.contestant_id) as Contestant_votes, Vote.id'
        ),
        'group' => array(
        'Vote.contestant_id'
        ),
        'order' => array(
        'Contestant_votes Desc'
        )
    ),
    'Contestant'=>array(
        'limit'=>5,
        'order' => array(
        'Contestant.id Desc'
        )
    )
);

And now in my controller I do the following:

function index() {
    $page = 'Contestants';
    $this->set('page', $page);  
    $conditions ["Contestant.active"] = 1;
    $this->set('contestants', $this->paginate($this->Contestant->Vote,$conditions));
}

Now the contestants are ordered by their total vote tally, although I still can't figure how to place the Contestant_votes as a paginator variable since in the record set it's in a array of it's own and not in any of the model arrays used to paginate.

Thanks Matt Huggins your approach was the one that led me to this solution.


Addition: Do you also want to sort by Votes (total votes) ascending or descending? If yes, you can not do it easily by the default pagination method of cakephp.

For that you need a little tweak. Here is the details about this trick: CakePHP Advanced Pagination – sort by derived field

Hope you'd find it helpful.

Thanks Adnan


For the specific relationship you define, your needs are well-served by counter-caching.

You will need to define a new field in your contestants table: vote_count. Then, in your Votes model, you'll need to update the $belongsTo definition slightly:

class Votes extends AppModel
{
    var $belongsTo = array(
        'Contestant' => array( 'counterCache' => true )
    );
}

Now, anytime a Vote record is saved, the vote_count field of the parent Contestant will be updated. Now you can simply sort by Contestant.vote_count as you would any other Contestant field:

class ContestantsController extends AppController
{
    // Controller stuff that comes before...

    function index()
    {
        $this->paginate = array( 'Contestant' => array(
            'conditions' => array( 'Contestant.active' => 1 ),
            'order' => array( 'Contestant.vote_count' => 'DESC' ),
        ));

        $contestants = $this->paginate('Contestants');

        $this->set( compact('contestants'));
    }

    // Controller stuff that comes after...
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜