views:

978

answers:

2

Since there doesn't seem to be any support for optimistic locking in CakePHP, I'm taking a stab at building a behaviour that implements it. After a little research into behaviours, I think I could run a query in the beforeSave event to check that the version field hasn't changed.

However, I'd rather implement the check by changing the update statement's WHERE clause from

WHERE id = ?

to

WHERE id = ? and version = ?

This way I don't have to worry about other requests changing the database record between the time I read the version and the time I execute the update. It also means I can do one database call instead of two.

I can see that the DboSource.update() method supports conditions, but Model.save() never passes any conditions to it.

It seems like I have a couple of options:

  1. Do the check in beforeSave() and live with the fact that it's not bulletproof.
  2. Hack my local copy of CakePHP to check for a conditions key in the options array of Model.save() and pass it along to the DboSource.update() method.

Right now, I'm leaning in favour of the second option, but that means I can't share my behaviour with other users unless they apply my hack to their framework.

Have I missed an easier option?

+1  A: 

When using save() to update a record, Cake expects an id to be present and will update only the record with this id.

What you're looking for is updateAll():

updateAll(array $fields, array $conditions)

Updates many records in a single call. Records to be updated are identified by the $conditions array, and fields to be updated, along with their values, are identified by the $fields array.

For example, to approve all bakers who have been members for over a year, the update call might look something like:

$this_year = date('Y-m-d h:i:s', strtotime('-1 year'));

$this->Baker->updateAll(
    array('Baker.approved' => true),
    array('Baker.created <=' => "$this_year")
);
deceze
Thanks for the suggestion, but I know about updateAll(). I'm trying to write a behaviour that lets you keep using all the standard CakePHP patterns that go through the save() command, and just adds optimistic locking on top.
Don Kirkby
Just to clarify, the save() command currently uses a default condition that just matches the id field. I want to add a second condition that also ensures the version number hasn't changed because of another user updating the same record.
Don Kirkby
A: 

updateAll() is useful, thanks for the tip.

JEFFERY