Jump to content

[CakePHP] Utilize custom or multiple counterCache counts.


JoelLarson

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.

Link to comment
Share on other sites

  • 4 months later...

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..

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • 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.