[ Team LiB ] Previous Section Next Section

The Command Class

Command objects enable your framework to grow flexibly. You can simply drop a class that derives from the Command parent class into a command directory and it automatically becomes available to the system. Listing 24.6 demonstrates the Command class.

Listing 24.6 The Command Class
 1: <?
 2: // command/Command.php
 3: // qframe license: http://resources.corrosive.co.uk/pkg/qframe/license.txt
 5: abstract class Command {
 6:   const CMD_SUCCESS = 200;
 7:   const CMD_UNPROCESSED = 400;
 8:   const CMD_ERROR = 500;
10:   final function execute( RequestHelper $requestHelper ) {
11:     $status = $this->doExecute( $requestHelper );
12:     $requestHelper->registerCommand( get_class( $this ), $status );
13:     return $status;
14:   }
16:   abstract protected function doExecute( RequestHelper $requestHelper );
17: }

The Command class is abstract, and a system will likely define many concrete classes that implement it. On lines 68 we define three constants. CMD_SUCCESS, CMD_UNPROCESSED, and CMD_ERROR are flags that can be used to signify the execution status of a command.

The execute() method on line 10 is declared final. It contains functionality that all Command classes should have, so we do not want child classes overriding this and providing their own implementation.

execute() requires a RequestHelper object, which we pass on in a call to the abstract doExecute() method. This practice of calling an abstract method from a concrete one is known as the template method pattern. We force all Command child classes to implement a doExecute() method (by declaring doExecute() abstract). We then call the method from execute() and work with the return value, even though doExecute() exists only as a declaration. We expect doExecute() to return an integer (usually one of the constant flags we declared at the start of the class), and we pass this return value and the name of the class to RequestHelper::registerCommand() on line 12.

So, when the execute() method of a Command child class is called, its doExecute() method is invoked and RequestHelper is automatically updated. The child class need only implement doExecute() and return a sensible value for all this to happen.

We want to ensure that the only route to doExecute() is via the execute() method, so we declare doExecute() protected. This means that only other commands can invoke doExecute().

Let's return to our Controller class in Listing 24.1 for a recap. The controller instantiates a RequestHelper object and passes it to a CommandFactory object's getCommand() method. The CommandFactory object uses the RequestHelper object to return a Command object, and the Controller object calls the Command object's execute() method, passing it the RequestHelper object. The Command object then invokes its doExecute() method and registers its own name and the doExecute() method's value with RequestHelper.

At this stage, we have processed the user's request, decided which command should take on the job, and invoked the command. The command should have completed its work and registered a status. Incidentally, it probably has used the DataStore object to save data the presentation layer might use later.

So, how are we going to translate all this processing into an interface for our user?

    [ Team LiB ] Previous Section Next Section