1

I have a PHP command line utility that is executed like below:

tool plugin command [options]...

The idea is that 3rd party plugins can be used, thus the main tool has no idea what they are. It can find them through an environment variable just like PATH.

The main tool application has a composition root that contains dependencies used by all plugins (shared). However, each plugin has its own dependencies and as such, the plugin's constructor is where I have a second composition root.

Does this sound like a legitimate case for multiple composition roots?

$c = new DIContainer();
$c->bind(...); // whatever is needed
$loader = new PluginLoader($c);

// argv[1] is the plugin name. the loader will inject the Container
// into the plugin's constructor. This is the 2nd composition root
$plugin = $loader->get($argv[1]);// locates and constructs

// the plugin populates its commands as plugin.command
$cmd = $c[ $argv[1] . '.' . $argv[2] ];

$cmd->execute(array_splice($argv, 3));

second question

Each command has an array of Option objects and I am not sure if the Command should have this array pre-composed and injected or if an OptionFactory should be injected into the command's constructor. The latter is nice as it keeps options encapsulated within the command, vs the plugin's constructor having to build an option list for every command it supports. Note these are not the command line options ($argv), its just the list of options supported by the command and includes a validator.

// Plugin class, 2nd composition root, called by PluginLoader
class MyPlugin{
  public function __construct(Container $c){
    $c->bind('myplugin.command', function(Container $c){
      return new Command([ ... create option objects here ...]);
      // or
      return new Command($c['option-factory']); // let cmd build option[]
    });
  }
}
  • 1
    Is this a second composition root? Are you not configuring all of your app + plugins in the same startup portion of your app? Ok, some of the container configuration is done in different classes, but it all still happens at the same time during the application lifecycle and is invoked during the app start. – Sam Holder Jul 08 '15 at 21:52
  • Yes, it all happens at the same time. In my first example, everything prior to `$cmd->execute` is the bootstrap/composition step. The main app and the plugin configure the container back to back. I am treating the Plugin constructor as a runtime extension of the composition root. So maybe calling it a second root is incorrect. – Andrew Chernow Jul 08 '15 at 22:58

0 Answers0