[ Team LiB ] Previous Section Next Section

The CommandFactory Class

An instance of the CommandFactory class is provided for the Controller class by the ApplicationResources object in Listing 24.1 on line 19. The Controller could instantiate its own CommandFactory, but by delegating object creation to the ApplicationResources object, we provide it the opportunity to configure the CommandFactory for us.

You can see the CommandFactory class in Listing 24.4.

Listing 24.4 The CommandFactory Class
 1: <?
 2: // command/CommandFactory.php
 3: // qframe license: http://resources.corrosive.co.uk/pkg/qframe/license.txt
 4:
 5: require_once 'controller/ApplicationResources.php';
 6:
 7:
 8: abstract class CommandFactory {
 9:   abstract function setDefaultCommand ( $str );
10:   abstract function getDefaultCommand ();
11:   abstract function getCommand( RequestHelper $helper );
12: }

The CommandFactory class is abstract; it defines the interface that CommandFactory implementations must follow. Most importantly, we ensure that all CommandFactory classes implement a getCommand() method. Why did we define an abstract class instead of simply providing an implementation? You will see the concrete class that we use in a moment, but we also want to ensure that future applications could provide alternative or improved implementations within our framework. By defining an abstract base class, we are building flexibility into our system.

In Listing 24.5, you can see SimpleCommandFactory, our CommandFactory implementation.

Listing 24.5 The SimpleCommandFactory Class
 1: <?
 2: // command/SimpleCommandFactory.php
 3: // qframe license: http://resources.corrosive.co.uk/pkg/qframe/license.txt
 4:
 5: require_once 'command/CommandFactory.php';
 6: require_once 'controller/ApplicationResources.php';
 7:
 8: class SimpleCommandFactory extends CommandFactory {
 9:   private $packages = array();
10:   private $defaultCmd = "DefaultCommand";
11:
12:   function __construct() {
13:     array_push ( $this->packages, "command" );
14:   }
15:
16:   function addPackage( $package_str ) {
17:     array_push( $this->packages, $package_str );
18:   }
19:
20:   function setDefaultCommand( $str ) {
21:     $this->defaultCommand = $str;
22:   }
23:
24:   function getDefaultCommand() {
25:     return $this->defaultCommand;
26:   }
27:
28:   function getCommand( RequestHelper $helper ) {
29:     $cmd = $helper->getCommand();
30:     if ( empty( $cmd ) ) {
31:       $cmd = $this->getDefaultCommand();
32:     }
33:     return $this->getCommandByName( $cmd );
34:   }
35:
36:   private function getCommandByName( $cmd ) {
37:     foreach ( $this->packages as $package ) {
38:       $cmdpath = "$package/$cmd.php";
39:       if ( file_exists( $cmdpath ) ) {
40:         require_once $cmdpath;
41:         $cmd_obj = new $cmd();
42:         if ( $cmd_obj instanceof command ) {
43:           return $cmd_obj;
44:       }
45:     }
46:   }
47:   throw new CommandNotFoundException( "Command: $cmd not found" );
48:  }
49: }

The SimpleCommandFactory class maintains a private array called $packages, which contains a list of directories that can be searched for Command classes. We populate it with a single default in the constructor on line 13, but we allow the client coder to add new packages to search with the addPackage() method on line 16. We also manage a $defaultCommand string property, which is settable and gettable using the setDefaultCommand() method on line 20 and the getDefaultCommand() method on line 24.

The heart of the class is the getCommand() method on line 28. On line 29 we call a RequestHelper method—getCommand()—which extracts a cmd request parameter. So, if the GET request to our framework included the name/value pair cmd=AddTask, we would end up with a $cmd value containing the string AddTask here. If no command was provided, we use the default command instead, storing it in the temporary $cmd variable.

We pass our $cmd variable to the private getCommandByName() method, which is on line 36. This loops through the SimpleCommandFactory::$packages array, searching in each directory for a file with the same name as the $cmd string. If such a file is located, we use require_once() on line 40 to access it and then instantiate an object of the command's name. We check that the object is of the type Command before returning it on line 43.

So, for a command to be run, it must exist in one of the packages known by the SimpleCommandFactory object. The filename and the Command object must share exactly the same name. If we were given an "AddTask" command, the SimpleCommandFactory object would look in the command directory for a file called AddTask.php. It would then use require_once() to include the file and attempt to instantiate a class called AddTask.

If no AddTask.php file were found, or if such a file were found but it did not contain an AddTask class derived from Command, we would eventually return a CommandNotFoundException on line 47. This an empty class derived from the built-in Exception class, and it serves as a flag for the Controller class.

At heart, the SimpleCommandFactory class is very simple—it translates strings into Command objects.

Now that you know how to find acquire Command objects, we should spend some time discussing the Command class.

    [ Team LiB ] Previous Section Next Section