Design Patterns – Dependency Injection in Chain of Command Pattern

dependency-injectiondesign-patternsPHP

I have a Chain of Command pattern implemented, with modules that implement an interface:

interface IRequestHandler
{
    public function handle(&$offset, &$tripData, $request = null);
    public function setSuccessor(OffsetRequestHandler $handler);
}

I set up a chain of modules that modify the $offset and $tripData objects if necessary (I guess that it is not exactly a chain of command pattern, but it gets the job done 🙂

I would like to start using dependency injection whenever it is possible to ease the process of writing unit tests. My question is: how to handle it, if each module may need different set of services? I can go with Auryn, and let it automatically instantiate all dependencies for each module (at least I hope that I can), but that shouldn't be necessary in theory…

Update:

To build the chain I take names of classes from the config file, I instantiate them, and I arrange them in a queue. The controller is not aware of the dependencies that each module needs. Right now, there are none, because each module creates needed objects by itself (and this is what I want to change). I don't want to inject each module with the container, because this will turn into a Service locator pattern.

Update 2:

The need:

I get a set of data from external resources, and I need to process it to get some metrics. However, the data may be corrupted, sent in batches, or whatever, and my script needs to fix it (as much as possible). The types of problems may depend on the external resource the data comes from. And the situation is dynamic, meaning that new types of problems, and new external resources may appear in the future.

My idea:

Create modules. Each module will address specific problem. Arrange the modules in a queue (as the order of the modules may be important), and execute them injecting the incoming data as a parameter.

The solution is heavily inspired by this article on SitePoint.

But instead of creating the instances one by one like in the example:

$firstHandler = new FirstHandler();
$secondHandler = new SecondHandler();
$thirdHandler = new ThirdHandler();

//the code below sets all successors through the first handler
$firstHandler->setSuccessor($secondHandler);
$secondHandler->setSuccessor($thirdHandler);

$result = $firstHandler->handle($request);

I pull the names of the classes from the config file, and I create them with a foreach loop:

$modulesQueue = $config->get("extensions");

foreach ( $modulesQueue as $moduleName ) {
    $moduleName = "extensions\\".$moduleName;
    $startModule->setSuccessor(new $moduleName());
}
// Starting the chain:
$ret = $startModule->handle($offset, $tripDataObject, $requestData);

The problem:

If I create instance of the classes like that, I don't see what each module needs to have injected (at this moment nothing, as there is no DI applied – each module instantiate services it needs). So I see two options here: either I switch to manual creation of the modules (which is not flexible at all), or I start using Reflection to find out what each module needs, and provide it.

Best Answer

Ok, so the core problem is to create create command handler objects generically, but constructor injection enforces individual parameters for each command handler.

This can be easily solved by separating the construction process for the chain from the actual constructor call utilizing a corresponding factory class for each of your handler classes. Each factory constructor stays parameterless, but inside each factory the handler objects will be constructed with the required services injected.

By using using a strict naming scheme like FirstHandlerFactory for FirstHandler, SecondHandlerFactory for SecondHandler etc, the resulting code will then look like

foreach ( $modulesQueue as $moduleName ) {
    $factoryName = "extensions\\".$moduleName."Factory";
    $startModule->setSuccessor((new $factoryName())->buildModule());
}

(Note I did not fix that this code does not set up a chain of command, to keep things simple, but I am sure you get the idea.)

The buildModule function then may look like this

 class FirstHandlerFactory
 { 
     function buildModule()
     {
        return new FirstHandler(/* provide the individual services here */);
     }
 }

In your unit tests, you will be able to create your handler objects just with mock services injected, as required for the specific test, without using the factories.

This solution does neither require a DI framework, nor some reflection mechanism.