2 namespace Drush\Runtime;
4 use Drush\Command\GlobalOptionsEventListener;
6 use Drush\Cache\CommandCache;
7 use DrupalFinder\DrupalFinder;
8 use Symfony\Component\Console\Input\InputInterface;
9 use Symfony\Component\Console\Output\OutputInterface;
10 use Symfony\Component\Console\Application;
11 use Consolidation\Config\ConfigInterface;
12 use Composer\Autoload\ClassLoader;
13 use League\Container\ContainerInterface;
14 use Drush\SiteAlias\SiteAliasManager;
17 * Prepare our Dependency Injection Container
19 class DependencyInjection
22 * Set up our dependency injection container.
24 public static function initContainer(
25 Application $application,
26 ConfigInterface $config,
27 InputInterface $input,
28 OutputInterface $output,
30 DrupalFinder $drupalFinder,
31 SiteAliasManager $aliasManager
34 // Create default input and output objects if they were not provided
36 $input = new \Symfony\Component\Console\Input\StringInput('');
39 $output = new \Symfony\Component\Console\Output\ConsoleOutput();
41 // Set up our dependency injection container.
42 $container = new \League\Container\Container();
44 \Robo\Robo::configureContainer($container, $application, $config, $input, $output);
45 $container->add('container', $container);
47 static::addDrushServices($container, $loader, $drupalFinder, $aliasManager);
49 // Store the container in the \Drush object
50 Drush::setContainer($container);
51 \Robo\Robo::setContainer($container);
53 // Change service definitions as needed for our application.
54 static::alterServicesForDrush($container, $application);
56 // Inject needed services into our application object.
57 static::injectApplicationServices($container, $application);
62 protected static function addDrushServices(ContainerInterface $container, ClassLoader $loader, DrupalFinder $drupalFinder, SiteAliasManager $aliasManager)
64 // Override Robo's logger with our own
65 $container->share('logger', 'Drush\Log\Logger')
66 ->withArgument('output')
67 ->withMethodCall('setLogOutputStyler', ['logStyler']);
69 $container->share('loader', $loader);
70 $container->share('site.alias.manager', $aliasManager);
72 // Override Robo's formatter manager with our own
73 // @todo not sure that we'll use this. Maybe remove it.
74 $container->share('formatterManager', \Drush\Formatters\DrushFormatterManager::class)
75 ->withMethodCall('addDefaultFormatters', [])
76 ->withMethodCall('addDefaultSimplifiers', []);
78 // Add some of our own objects to the container
79 $container->share('bootstrap.default', 'Drush\Boot\EmptyBoot');
80 $container->share('bootstrap.drupal6', 'Drush\Boot\DrupalBoot6');
81 $container->share('bootstrap.drupal7', 'Drush\Boot\DrupalBoot7');
82 $container->share('bootstrap.drupal8', 'Drush\Boot\DrupalBoot8');
83 $container->share('bootstrap.manager', 'Drush\Boot\BootstrapManager')
84 ->withArgument('bootstrap.default')
85 ->withMethodCall('setDrupalFinder', [$drupalFinder]);
86 // TODO: Can we somehow add these via discovery (e.g. backdrop extension?)
87 $container->extend('bootstrap.manager')
88 ->withMethodCall('add', ['bootstrap.drupal6'])
89 ->withMethodCall('add', ['bootstrap.drupal7'])
90 ->withMethodCall('add', ['bootstrap.drupal8']);
91 $container->share('bootstrap.hook', 'Drush\Boot\BootstrapHook')
92 ->withArgument('bootstrap.manager');
93 $container->share('redispatch.hook', 'Drush\Runtime\RedispatchHook');
94 $container->share('tildeExpansion.hook', 'Drush\Runtime\TildeExpansionHook');
96 // Robo does not manage the command discovery object in the container,
97 // but we will register and configure one for our use.
98 // TODO: Some old adapter code uses this, but the Symfony dispatcher does not.
99 // See Application::commandDiscovery().
100 $container->share('commandDiscovery', 'Consolidation\AnnotatedCommand\CommandFileDiscovery')
101 ->withMethodCall('addSearchLocation', ['CommandFiles'])
102 ->withMethodCall('setSearchPattern', ['#.*(Commands|CommandFile).php$#']);
104 // Add inflectors. @see \Drush\Boot\BaseBoot::inflect
105 $container->inflector(\Drush\Boot\AutoloaderAwareInterface::class)
106 ->invokeMethod('setAutoloader', ['loader']);
107 $container->inflector(\Drush\SiteAlias\SiteAliasManagerAwareInterface::class)
108 ->invokeMethod('setSiteAliasManager', ['site.alias.manager']);
111 protected static function alterServicesForDrush(ContainerInterface $container, Application $application)
113 // Add our own callback to the hook manager
114 $hookManager = $container->get('hookManager');
115 $hookManager->addCommandEvent(new GlobalOptionsEventListener());
116 $hookManager->addInitializeHook($container->get('redispatch.hook'));
117 $hookManager->addInitializeHook($container->get('bootstrap.hook'));
118 $hookManager->addPreValidator($container->get('tildeExpansion.hook'));
119 $hookManager->addOutputExtractor(new \Drush\Backend\BackendResultSetter());
121 // Install our command cache into the command factory
122 // TODO: Create class-based implementation of our cache management functions.
123 $cacheBackend = _drush_cache_get_object('factory');
124 $commandCacheDataStore = new CommandCache($cacheBackend);
126 $factory = $container->get('commandFactory');
127 $factory->setIncludeAllPublicMethods(false);
128 $factory->setDataStore($commandCacheDataStore);
131 protected static function injectApplicationServices(ContainerInterface $container, Application $application)
133 $application->setLogger($container->get('logger'));
134 $application->setBootstrapManager($container->get('bootstrap.manager'));
135 $application->setAliasManager($container->get('site.alias.manager'));
136 $application->setRedispatchHook($container->get('redispatch.hook'));
137 $application->setTildeExpansionHook($container->get('tildeExpansion.hook'));
138 $application->setDispatcher($container->get('eventDispatcher'));
139 $application->setConfig($container->get('config'));