3 namespace Drupal\DrupalExtension\ServiceContainer;
5 use Behat\Behat\Context\ServiceContainer\ContextExtension;
6 use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface;
7 use Behat\Testwork\ServiceContainer\ExtensionManager;
8 use Behat\Testwork\ServiceContainer\ServiceProcessor;
9 use Drupal\DrupalExtension\Compiler\DriverPass;
10 use Drupal\DrupalExtension\Compiler\EventSubscriberPass;
11 use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
12 use Symfony\Component\Config\FileLocator;
13 use Symfony\Component\DependencyInjection\ContainerBuilder;
14 use Symfony\Component\DependencyInjection\Definition;
15 use Symfony\Component\DependencyInjection\Loader\FileLoader;
16 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
18 class DrupalExtension implements ExtensionInterface {
21 * Extension configuration ID.
23 const DRUPAL_ID = 'drupal';
26 * Selectors handler ID.
28 const SELECTORS_HANDLER_ID = 'drupal.selectors_handler';
31 * @var ServiceProcessor
36 * Initializes compiler pass.
38 * @param null|ServiceProcessor $processor
40 public function __construct(ServiceProcessor $processor = null) {
41 $this->processor = $processor ? : new ServiceProcessor();
47 public function getConfigKey() {
48 return self::DRUPAL_ID;
54 public function initialize(ExtensionManager $extensionManager) {
60 public function load(ContainerBuilder $container, array $config) {
61 $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/config'));
62 $loader->load('services.yml');
63 $container->setParameter('drupal.drupal.default_driver', $config['default_driver']);
65 $this->loadParameters($container, $config);
67 // Setup any drivers if requested.
68 $this->loadBlackbox($loader, $config);
69 $this->loadDrupal($loader, $container, $config);
70 $this->loadDrush($loader, $container, $config);
76 public function process(ContainerBuilder $container) {
77 $this->processDriverPass($container);
78 $this->processEventSubscriberPass($container);
79 $this->processEnvironmentReaderPass($container);
80 $this->processClassGenerator($container);
86 public function configure(ArrayNodeDefinition $builder) {
89 scalarNode('default_driver')->
90 defaultValue('blackbox')->
91 info('Use "blackbox" to test remote site. See "api_driver" for easier integration.')->
93 scalarNode('api_driver')->
94 defaultValue('drush')->
95 info('Bootstraps drupal through "drupal8" or "drush".')->
97 scalarNode('drush_driver')->
98 defaultValue('drush')->
100 arrayNode('region_map')->
101 info("Targeting content in specific regions can be accomplished once those regions have been defined." . PHP_EOL
102 . ' My region: "#css-selector"' . PHP_EOL
103 . ' Content: "#main .region-content"'. PHP_EOL
104 . ' Right sidebar: "#sidebar-second"'. PHP_EOL
106 useAttributeAsKey('key')->
107 prototype('variable')->
112 'Text strings, such as Log out or the Username field can be altered via behat.yml if they vary from the default values.' . PHP_EOL
113 . ' log_out: "Sign out"' . PHP_EOL
114 . ' log_in: "Sign in"' . PHP_EOL
115 . ' password_field: "Enter your password"' . PHP_EOL
116 . ' username_field: "Nickname"'
118 addDefaultsIfNotSet()->
120 scalarNode('log_in')->
121 defaultValue('Log in')->
123 scalarNode('log_out')->
124 defaultValue('Log out')->
126 scalarNode('password_field')->
127 defaultValue('Password')->
129 scalarNode('username_field')->
130 defaultValue('Username')->
134 arrayNode('selectors')->
135 addDefaultsIfNotSet()->
137 scalarNode('message_selector')->end()->
138 scalarNode('error_message_selector')->end()->
139 scalarNode('success_message_selector')->end()->
140 scalarNode('warning_message_selector')->end()->
141 scalarNode('login_form_selector')->
142 defaultValue('form#user-login')->
144 scalarNode('logged_in_selector')->
145 defaultValue('body.logged-in,body.user-logged-in')->
150 arrayNode('blackbox')->
152 arrayNode('drupal')->
154 scalarNode('drupal_root')->end()->
159 scalarNode('alias')->end()->
160 scalarNode('binary')->defaultValue('drush')->end()->
161 scalarNode('root')->end()->
162 scalarNode('global_options')->end()->
166 arrayNode('subcontexts')->
168 'The Drupal Extension is capable of discovering additional step-definitions provided by subcontexts.' . PHP_EOL
169 . 'Module authors can provide these in files following the naming convention of foo.behat.inc. Once that module is enabled, the Drupal Extension will load these.' . PHP_EOL
171 . 'Additional subcontexts can be loaded by either placing them in the bootstrap directory (typically features/bootstrap) or by adding them to behat.yml.'
173 addDefaultsIfNotSet()->
177 '- /path/to/additional/subcontexts' . PHP_EOL
180 useAttributeAsKey('key')->
181 prototype('variable')->end()->
183 scalarNode('autoload')->
193 * Load test parameters.
195 private function loadParameters(ContainerBuilder $container, array $config) {
196 // Store config in parameters array to be passed into the DrupalContext.
197 $drupal_parameters = array();
198 foreach ($config as $key => $value) {
199 $drupal_parameters[$key] = $value;
201 $container->setParameter('drupal.parameters', $drupal_parameters);
203 $container->setParameter('drupal.region_map', $config['region_map']);
207 * Load the blackbox driver.
209 private function loadBlackBox(FileLoader $loader, array $config) {
210 // Always include the blackbox driver.
211 $loader->load('drivers/blackbox.yml');
215 * Load the Drupal driver.
217 private function loadDrupal(FileLoader $loader, ContainerBuilder $container, array $config) {
218 if (isset($config['drupal'])) {
219 $loader->load('drivers/drupal.yml');
220 $container->setParameter('drupal.driver.drupal.drupal_root', $config['drupal']['drupal_root']);
225 * Load the Drush driver.
227 private function loadDrush(FileLoader $loader, ContainerBuilder $container, array $config) {
228 if (isset($config['drush'])) {
229 $loader->load('drivers/drush.yml');
230 if (!isset($config['drush']['alias']) && !isset($config['drush']['root'])) {
231 throw new \RuntimeException('Drush `alias` or `root` path is required for the Drush driver.');
233 $config['drush']['alias'] = isset($config['drush']['alias']) ? $config['drush']['alias'] : FALSE;
234 $container->setParameter('drupal.driver.drush.alias', $config['drush']['alias']);
236 $config['drush']['binary'] = isset($config['drush']['binary']) ? $config['drush']['binary'] : 'drush';
237 $container->setParameter('drupal.driver.drush.binary', $config['drush']['binary']);
239 $config['drush']['root'] = isset($config['drush']['root']) ? $config['drush']['root'] : FALSE;
240 $container->setParameter('drupal.driver.drush.root', $config['drush']['root']);
242 // Set global arguments.
243 $this->setDrushOptions($container, $config);
248 * Set global drush arguments.
250 private function setDrushOptions(ContainerBuilder $container, array $config) {
251 if (isset($config['drush']['global_options'])) {
252 $definition = $container->getDefinition('drupal.driver.drush');
253 $definition->addMethodCall('setArguments', array($config['drush']['global_options']));
258 * Process the Driver Pass.
260 private function processDriverPass(ContainerBuilder $container) {
261 $driverPass = new DriverPass();
262 $driverPass->process($container);
266 * Process the Event Subscriber Pass.
268 private function processEventSubscriberPass(ContainerBuilder $container) {
269 $eventSubscriberPass = new EventSubscriberPass();
270 $eventSubscriberPass->process($container);
274 * Process the Environment Reader pass.
276 private function processEnvironmentReaderPass(ContainerBuilder $container) {
277 // Register Behat context readers.
278 $references = $this->processor->findAndSortTaggedServices($container, ContextExtension::READER_TAG);
279 $definition = $container->getDefinition('drupal.context.environment.reader');
281 foreach ($references as $reference) {
282 $definition->addMethodCall('registerContextReader', array($reference));
287 * Switch to custom class generator.
289 private function processClassGenerator(ContainerBuilder $container) {
290 $definition = new Definition('Drupal\DrupalExtension\Context\ContextClass\ClassGenerator');
291 $container->setDefinition(ContextExtension::CLASS_GENERATOR_TAG . '.simple', $definition);