Tag: updateAll

Make updateAll() fire behavior callbacks

For a while now updateAll() would not trigger any of the model’s behavior callbacks.

This presents a problem for a couple of reasons:

  1. The updateAll() method allows to easily do things like field_value = field_value + 1, because unlike other similar methods it does not escape fields/values
  2. Secondly we cannot rely on proper Behavior execution, which can lead to some unexpected results

What we have below is a simple override (and a very rough patch at this point) that will trigger afterSave() of the attached behavior as expected.

Take the code below and place into the model, which uses updateAll() at some point.

public function updateAll($fields, $conditions = true) {
    $db =& ConnectionManager::getDataSource($this->useDbConfig);
    $created = FALSE;
    $options = array();
    if($db->update($this, $fields, null, $conditions)) {
      $created = TRUE;
      $this->Behaviors->trigger($this, 'afterSave', array($created, $options));
      $this->afterSave($created);
      $this->_clearCache();
      $this->id = false;
      return true;
    }
  return FALSE;
 }

Again, this works for my immediate needs and doesn’t break any tests. However there are a few things that can be improved to make it more consistent with other methods like save(), for example.

Well, either way I am hoping that this will help someone.

Incrementing a field in CakePHP

Let’s say you have an application, where users can place votes for their favorite products and you’d like to increment the current number of votes by one.

It’s very easy by using updateAll:

$this->Product->updateAll(array('Product.vote'=>'Product.vote+1'), array('Product.id'=>40));

You may want to restrict Product model by using unbindModel, containable, etc.

Also, you don’t have to pass in the second argument to updateAll, if you wish to update all records in your table.