CHAPTER 13 ■ DATABASE PATTERNS
Consequences
The use of a generic identity object implementation makes it easier to use a single parameterized
SelectionFactory class. If you opt for hard-coded identity objects—that is, identity objects which consist
of a list of getter and setter methods—you are more likely to have to build an individual
SelectionFactory per domain object.
One of the great benefits of query factories combined with identity objects is the range of queries
you can generate. This can also cause caching headaches. These methods generate queries on the fly,
and it’s difficult to know when you’re duplicating effort. It may be worth building a means of comparing
identity objects so that you can return a cached string without all that work. A similar kind of database
statement pooling might be considered at a higher level too.
Another issue with the combination of patterns I have presented in the latter part of this chapter is
the fact that they’re flexible, but they’re not that flexible. By this, I mean they are designed to be
extremely adaptable within limits. There is not much room for exceptional cases here, though. Mapper
classes, while more cumbersome to create and maintain, are very accommodating of any kind of
performance kludge or data juggling you might need to perform behind their clean APIs. These more
elegant patterns suffer from the problem that, with their focused responsibilities and emphasis on
composition, it can be hard to cut across the cleverness and do something dumb but powerful.
Luckily, I have not lost my higher level interface—there’s still a controller level where I can head
cleverness off at the pass if necessary.
What’s Left of Data Mapper Now?
So, I have stripped object, query, and collection generation from Data Mapper, to say nothing of the
management of conditionals. What could possibly be left of it? Well, something that is very much like a
mapper is needed in vestigial form. I still need an object that sits above the others I have created and
coordinates their activities. It can help with caching duties and handle database connectivity (although
the database-facing work could be delegated still further). Clifton Nock calls these data layer controllers
domain object assemblers.
Here is an example:
namespace woo\mapper;
//...
class DomainObjectAssembler {
protected static $PDO;
function __construct( PersistenceFactory $factory ) {
$this->factory = $factory;
if (! isset(self::$PDO) ) {
$dsn = \woo\base\ApplicationRegistry::getDSN( );
if ( is_null( $dsn ) ) {
throw new \woo\base\AppException( "No DSN" );
}
self::$PDO = new \PDO( $dsn );
self::$PDO->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
}
function getStatement( $str ) {
if (! isset( $this->statements[$str] ) ) {
$this->statements[$str] = self::$PDO->prepare( $str );