Using counters with ActiveRecord

You are viewing revision #4 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.

« previous (#3)next (#5) »

Let's say, for example, that you are developing a blog or some kind of CMS and you want to track the number of times each post was viewed (maybe to show a list of the most viewed ones).

The easier way to do that is by adding a column to the post table, which will be used to store the number of visits of that item. Each time the post is displayed the value of this column will be increased by 1. The code for this would be something like:

public function actionView($id) {
    $post = Post::model()->findByPk($id);
    $post->visits += 1;
    $post->save();
    $this->render('view', array('post' => $post));
}

We have three problems with this approach. All we want is to update the visits column, but the entire record will be updated. Also, if we didn't pass the false argument to the save method, all the validation process will be executed. Also if someone in parallel will update record from 4 to 5, we still save it as 5, as our version of post record have 4.

Since 1.1.8, the CActiveRecord class has a method that can help us with this task. It's the [CActiveRecord::saveCounters()] method and its usage is pretty simple:

public function actionView($id) {
    $post = Post::model()->findByPk($id);
    $post->saveCounters(array('visits'=>1));
    $this->render('view', array('post' => $post));
}

With this, only the visits column will be updated and the validation will not be triggered.

If you're not using the 1.1.8 yet, there's the [CActiveRecord::updateCounters()] method:

public function actionView($id) {
    $post = Post::model()->findByPk($id);
    $post->updateCounters(
        array('visits'=>1),
        array('condition' => "id = :id"),
        array(':id' => $this->id),
    );
    $this->render('view', array('post' => $post));
}

The piece of code above does exactly the same that saveCounters does. Note that updateCounters has two additional parameters. After the column used to count, we pass a condition to tell which record(s) should be updated. If you used any paramater in this condition (like the ":id"), you should pass the parameter value in the third argument of the method.

Important: If you do not pass a condition, all records will be updated.

11 1
17 followers
Viewed: 45 561 times
Version: Unknown (update)
Category: Tips
Written by: davi_alexandre
Last updated by: marcovtwout
Created on: Dec 2, 2011
Last updated: 9 years ago
Update Article

Revisions

View all history

Related Articles