Search code examples
mysqlcakephpcakephp-1.3rating-system

Calculate new average afterSave (or something better?) in CakePHP


I'm building a rating system where a user can rate something from 1-5 stars.

I was wondering if there's a way to automatically calculate all of a specific item's ratings (from the ratings table where model='x' and foreign_key='y') on afterSave or something similar.

I can do it in the ratings_controller just fine... just thought it might be more ideal to be done automatically in the model. Can anyone point me in the right direction for this?

I would LOVE to hear that there's some kind of association setting in CakePHP that allows it to do this for you - something like:

//Rating model
var $belongsTo = array(
    'Restaurant' => array(
        'averageValue' => 'rating
    )
);

But - I'm sure that's asking to much :)


Solution

  • if you want to save the average into a field in items table then afterSave would probably be the best solution right now.

    The only thing cake can automatically do for you is keeping track of how many ratings an item has (counterCache), but not other aggregate functions.

    virtualField may be good, but I have never used that for aggregate functions, so I'm not sure. Besides, if your ratings don't change often, it would put unnecessary work on the system.

    In Rating model:

    function afterSave($created){
       $avgValue = $this->Query('SELECT AVG(rating) as rating FROM ratings WHERE ratings.restaurant_id = '.$this->restaurant_id);
       $this->Restaurant->updateRatingAverage($this->restaurant_id,$avgValue[0][0]['rating']);
    }
    

    In Restaurant model

    function updateRatingAverage($id,$avg){  
       $this->id = $id;
       $this->field('your_average_field_here',$avg);
    }
    

    you might want to log the $avgValue to see how it's structured, but I think I got that right.