Question

I have two tables:

Contestant and Votes Contestant hasMany Votes

I've tried doing a count(Vote.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)); }

Was it helpful?

Solution 2

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.

OTHER TIPS

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'),
    )
)

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...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top