Jump to content

Archived

This topic is now archived and is closed to further replies.

JoelLarson

[CakePHP] Utilize custom or multiple counterCache counts.

Recommended Posts

I ran into an issue where I'm writing an upvote/downvote system in CakePHP and wanted to use a cache for votes so I didn't have to recount every vote for every link (very expensive on db calls). I started looking in the CakePHP docs and found: http://book.cakephp.org/view/1033/counterCache-Cache-your-count

 

It was missing my ability to cache the amount of upvotes and downvotes (named upvote_count and downvote_count) in my database. I figured out a solution with a bit of OOP magic and derping around in the Model.php from Core.

 

The code I have written is definitely not optimized. If you have better alternatives or code to make it perform better, please comment.

 

<?php

class Vote extends AppModel {
    
    $name = 'Vote';

    $belongsTo = array(
        'Item' => array(
    'className' => 'Item',
    'foreignKey' => 'id',
    'counterCache' => true,
),
    );
    
    // Overwrite for recounting up/down votes on counterCache
    public function updateCounterCache($keys = array(), $created = false) {
        $response = parent::updateCounterCache($keys, $created);
        
// Here is the hook for custom recounts.
        $this->recountVotes($this->data['Vote']['item_id']);
        
// Return the parent::updateCounterCache to make it appear like nothing changed.
        return $response;
    }
    
    protected function recountVotes($item_id) {
        
        // So this gets a count of the counterCache columns we'd like to make happen.
        $record = array(
            $this->alias => array(
                // WARNING: Direction is an INT(1) instead of TINYINT(1) to allow for a negative in my case.
                'upvote_count' => $this->field('COUNT(`id`)', array('direction' => 1, 'item_id' => $item_id)), 
                'downvote_count' => $this->field('COUNT(`id`)', array('direction' => -1, 'item_id' => $item_id)),
                'id' => $item_id,
            )
        );

// Then update the table it belongs to.
        $this->query(sprintf('UPDATE `items` as `Item` SET `Item`.`upvote_count` = %d, `Item`.`downvote_count` = %d WHERE `Item`.`id` = %d',
                $record[$this->alias]['upvote_count'],
                $record[$this->alias]['downvote_count'],
                $record[$this->alias]['id']
        ));
        
        return true;
    }
    
}

 

I hope someone finds a use for this ability until CakePHP natively supports it.

Share this post


Link to post
Share on other sites

Not to bring something back from the dead, but for the sake of people (like myself) who stumble on this in google.... This functionality is already built in using counterScope.. not very well documented but there are a couple blog posts out there about it.  Sorry for the zombie thread but..

Share this post


Link to post
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.