CHAPTER 13 ■ DATABASE PATTERNS
The Problem
One day, I echoed my SQL statements to the browser window to track down a problem and had a shock.
I found that I was saving the same data over and over again in the same request. I had a neat system of
composite commands, which meant that one command might trigger several others, and each one was
cleaning up after itself.
Not only was I saving the same object twice, I was saving objects that didn’t need saving.
This problem then is similar in some ways to that addressed by Identity Map. That problem
involved unnecessary object loading; this problem lies at the other end of the process. Just as these
issues are complementary, so are the solutions.
Implementation
To determine what database operations are required, you need to keep track of various events that befall
your objects. Probably the best place to do that is in the objects themselves.
You also need to maintain a list of objects scheduled for each database operation (insert, update,
delete). I am only going to cover insert and update operations here. Where might be a good place to
store a list of objects? It just so happens that I already have an ObjectWatcher object, so I can develop
that further:
// ObjectWatcher
// ...
private $all = array();
private $dirty = array();
private $new = array();
private $delete = array(); // unused in this example
private static $instance;
// ...
static function addDelete( DomainObject $obj ) {
$self = self::instance();
$self->delete[$self->globalKey( $obj )] = $obj;
}
static function addDirty( DomainObject $obj ) {
$inst = self::instance();
if (! in_array( $obj, $inst->new, true ) ) {
$inst->dirty[$inst->globalKey( $obj )] = $obj;
}
}
static function addNew( DomainObject $obj ) {
$inst = self::instance();
// we don't yet have an id
$inst->new[] = $obj;
}
static function addClean( DomainObject $obj ) {
$self = self::instance();
unset( $self->delete[$self->globalKey( $obj )] );
unset( $self->dirty[$self->globalKey( $obj )] );