As i’ve seen a few questions about the countercache behavior in the irc channel (irc://irc.freenode.net/#cakephp) i’ve decided to make a quick tutorial.

What is countercache

CounterCache is used in Ruby on Rails to count the number of children a model has. Say we have a model called Project and this model hasMany Documents. It would be nice to know the number of Documents for a Project without doing a Count. Well countercache does exactly this.

The database

Lets use this table for projects:

-- 
-- Table structure for table `projects`
-- 

CREATE TABLE `projects` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL default '',
  `description` text NOT NULL,
  `created` datetime default NULL,
  `updated` datetime default NULL,
  `documents_count` int(11) NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Note the documents_count column in the table Projects, this is where the behavior saves the count of the current number of documents.

The models

Project.php (/app/models/)

<?php
// Project model
class Project extends AppModel
{

 var $name = 'Project';
 var $hasMany = array('Document'=>array('dependent'=>true));
}
?>

and the document:

document.php (/app/models/)

// Docment model
<?php
class Document extends AppModel
{

 var $name = 'Document';
 var $belongsTo = array('Project');
 var $actsAs = array('CounterCache');
}

?>

How it works

Note that the $actsAs is in the child model (in this case documents). This is because the behavior basically does a count on each beforeSave and beforeDelete and stores it in the parent’s model as _count, in this case documents_count. Note that the model name is pluralized, so it becomes documents_count instead of document_count.

Where can i find the behavior?

Since this feature is not implemented yet (note this post was written on december 15, 2007). You can get the behavior at the bakery on: http://bakery.cakephp.org/articles/view/countercache-or-counter_cache-behavior.

When the feature does get implemented, you could just use it like this:

var $belongsTo = array(
                        'Project' =>
                            array('className'   => 'Project',
                                'conditions'        => '',
                                'order'             => '',
                                'foreignKey'        => 'project_id',
                                'counterCache'      => 'projects_count' 
                                )
                        );