An Auditable Behavior for CakePHP
In an effort to clean house, so to speak, before moving on to new project ideas, I finally “certified” an Auditable behavior for CakePHP that I started writing over a year ago. Actually, I’ve written it several times, for several projects, and finally got around to packaging it up with documentation and all the trappings.
Audit logs for tracking changes are nothing new, of course, but when I started this project nothing like this existed for CakePHP—maybe there still isn’t. By way of defining the requirements that this was built against, I’ll define how I wanted to use it:
- I wanted to be able to store all changes to any property of any model in a single table.
- I wanted to be able to access a snapshot of the complete object at the moment of the change.
- I wanted to know exactly which properties were modified and how they were modified (old value/new value) for a given change.
- I wanted to be able to track changes to models associated via a HABTM (Has And Belongs To Many) relationship. For example, a
Personmay have manyAddresses. I don’t want to audit theAddressmodel because it’s meaningless without the context that thePersonprovides, so the key is to track changes to theAddressmodel when thePersonmodel changes. - I wanted to have the option of ignoring certain fields (e.g.
active,created,modified, etc.) whose deltas aren’t important. - I wanted to optionally track the user who made each change.
- Generally speaking, I wanted to be able to access this data directly in the database, but I wanted the option of throwing up an interface to the data.
The details are available in the project’s README file, but here are the highlights of the implementation:
- A SQL script is provided that creates two tables:
auditsandaudit_deltas. Theauditstable stores a full audit record with a complete object snapshot in JSON format and each audithasManyrecords in theaudit_deltastable. - The
auditstable is fully polymorphic and implemented in a manner that is compatible with the Polymorphic Behavior. - The behavior is configurable such that, for any given model, certain fields can be ignored and/or any HABTM associations tracked.
- A user (or anything else, I suppose) can be associated with any change by implementing a custom callback on the model.
- The auditing models are bound to and unbound from the model being audited at runtime, so I’ve never actually created model files for them. There’s no reason it couldn’t be done, though, if there’s a need to write custom methods for them.
I haven’t upgraded my projects to CakePHP 1.3.x, so I can only speak to its functionality against the 1.2.x framework, but I don’t know of any reason that it would work as-is or with trivial modifications. Let’s consider that a verbose way of saying, “YMMV” (Your Mileage May Vary).
If you have problems, find bugs or just want to suggest an improvement, please use the project’s ticket manager.