PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1
CHAPTER 12 ■ ENTERPRISE PATTERNS

If this is the first run (or if the cache files have been deleted—a crude but effective way of forcing
configuration data to be re-read), then the getOptions() method is invoked.
In real life, this would probably do a lot more work than the example shows. This version satisfies
itself with acquiring a DSN. getOptions() first checks that the configuration file exists (the path is stored
in a property called $config). It then attempts to load XML data from the file and sets the DSN.


■Note In these examples, both ApplicationRegistry and ApplicationHelper use hard-coded paths to work


with files. In a real-world deployment, these file paths would probably be configurable and acquired through a


registry or configuration object. The actual paths could be set at installation time by a build tool such as PEAR or


Phing (see Chapters 15 and 19 for more on these tools).


Notice that the class uses a trick to throw exceptions. Rather than pepper the code with conditionals
and throw statements like this:


if (! file_exists( $this->config ) ) {
throw new \woo\base\AppException(
"Could not find options file" );
}


the class centralizes the test expression and the throw statement in a method called ensure(). You can
confirm that a condition is true (and throw an exception otherwise) in a single (albeit split) line:


$this->ensure( file_exists( $this->config ),
"Could not find options file" );


The cache approach taken here allows for the best of both worlds. The system can maintain an easy-
to-use XML configuration file, but caching means that its values can be accessed at near native speed. Of
course, if your end users are programmers too, or if you don’t intend to change configuration very often,
you could include PHP data structures directly in the helper class (or in a separate file that it then
includes). While risky, this approach is certainly the fastest.


CommandResolver


A controller needs a way of deciding how to interpret an HTTP request so that it can invoke the right
code to fulfill that request. You could easily include this logic within the Controller class itself, but I
prefer to use a specialist class for the purpose. That makes it easy to refactor for polymorphism if
necessary.
A front controller often invokes application logic by running a Command object (I introduced the
Command pattern in Chapter 11). The Command that is chosen is usually selected according to a
parameter in the request or according to the structure of the URL itself (you might, for example, use
Apache configuration to make concrete-seeming URLs yield a key for use in selecting a Command). In
these examples, I will use a simple parameter: cmd.
There is more than one way of using the given parameter to select a command. You can test the
parameter against a configuration file or data structure (a logical strategy). Or you can test it directly
against class files on the file system (a physical strategy).

Free download pdf