views:

1542

answers:

4

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)); }

A: 

Check out deceze's response in this question: http://stackoverflow.com/questions/1592391/cakephp-mathematic-calculation-field/1592550#1592550

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'),
    )
)
Matt Huggins
Weird when I try your suggestion this is the query it builds. ::Query: SELECT SUM(`Vote`.`id`) AS Contestant__votes, `Vote`.`group`, `Vote`.`contestant_id` FROM `votes` AS `Vote` WHERE `Vote`.`contestant_id` IN (1, 2)
Fabian Brenes
And it shows this error: Model "Vote" is not associated with model "Vote". Is this a bug? Why would a need to associate a model with it's self?
Fabian Brenes
Ok it seems that cakephp doesn't support group by on containable behavior so I did something like this:'conditions' => "1 = 1 GROUP BY Vote.contestant_id"And generates this SQL query:SELECT Sum(`Vote`.`id`) AS Contestant__votes, `Vote`.`contestant_id` FROM `votes` AS `Vote` WHERE 1 = 1 GROUP BY `Vote`.`contestant_id` AND `Vote`.`contestant_id` IN (1, 2)
Fabian Brenes
But the weird part is that there's only 7 votes and the sum is 28 and if I use count it will return 7, but I just want the votes for that contestant and not the total vote number.
Fabian Brenes
Is there a way to remove this from the query? :AND Vote.contestant_id IN (1, 2) or do I have to unbind the model to achieve this?
Fabian Brenes
A: 

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.

Fabian Brenes
A: 

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

adnan
A: 

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...
}
Daniel Wright