diff --git a/core/core.services.yml b/core/core.services.yml index 73de3f3..b54ff69 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -88,6 +88,7 @@ services: class: Drupal\Core\Config\ConfigFactory tags: - { name: event_subscriber } + - { name: compiler_pass, tag: 'config.factory.override', method: addOverride, require: Drupal\Core\Config\ConfigFactoryOverrideInterface } arguments: ['@config.storage', '@event_dispatcher', '@config.typed'] config.installer: class: Drupal\Core\Config\ConfigInstaller @@ -163,7 +164,7 @@ services: class: Drupal\Core\Theme\ThemeNegotiator arguments: ['@access_check.theme', '@request_stack'] tags: - - { name: compiler_pass, tag: theme_negotiator, method: addNegotiator } + - { name: compiler_pass, tag: theme_negotiator, method: addNegotiator, require: Drupal\Core\Theme\ThemeNegotiatorInterface } theme.negotiator.default: class: Drupal\Core\Theme\DefaultNegotiator arguments: ['@config.factory'] @@ -258,6 +259,8 @@ services: arguments: ['@language_manager'] calls: - [initLanguageManager] + tags: + - { name: compiler_pass, tag: string_translator, method: addTranslator, require: Drupal\Core\StringTranslation\Translator\TranslatorInterface } database.slave: class: Drupal\Core\Database\Connection factory_class: Drupal\Core\Database\Database @@ -304,7 +307,7 @@ services: calls: - [setFinalMatcher, ['@router.matcher.final_matcher']] tags: - - { name: compiler_pass, tag: route_filter, method: addRouteFilter } + - { name: compiler_pass, tag: route_filter, method: addRouteFilter, require: Symfony\Cmf\Component\Routing\NestedMatcher\RouteFilterInterface } url_generator: class: Drupal\Core\Routing\UrlGenerator arguments: ['@router.route_provider', '@path_processor_manager', '@route_processor_manager', '@config.factory', '@settings'] @@ -317,6 +320,8 @@ services: router.dynamic: class: Symfony\Cmf\Component\Routing\DynamicRouter arguments: ['@router.request_context', '@router.matcher', '@url_generator'] + tags: + - { name: compiler_pass, tag: route_enhancer, method: addRouteEnhancer, require: Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface } router: class: Symfony\Cmf\Component\Routing\ChainRouter calls: @@ -580,8 +585,13 @@ services: arguments: [['@exception_controller', execute]] route_processor_manager: class: Drupal\Core\RouteProcessor\RouteProcessorManager + tags: + - { name: compiler_pass, tag: route_processor_outbound, method: addOutbound, require: Drupal\Core\RouteProcessor\OutboundRouteProcessorInterface } path_processor_manager: class: Drupal\Core\PathProcessor\PathProcessorManager + tags: + - { name: compiler_pass, tag: path_processor_inbound, method: addInbound, require: Drupal\Core\PathProcessor\InboundPathProcessorInterface } + - { name: compiler_pass, tag: path_processor_outbound, method: addOutbound, require: Drupal\Core\PathProcessor\OutboundPathProcessorInterface } path_processor_decode: class: Drupal\Core\PathProcessor\PathProcessorDecode tags: @@ -634,7 +644,7 @@ services: class: Drupal\Core\Breadcrumb\BreadcrumbManager arguments: ['@module_handler'] tags: - - { name: compiler_pass, tag: breadcrumb_builder, method: addBuilder } + - { name: compiler_pass, tag: breadcrumb_builder, method: addBuilder, require: Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface } token: class: Drupal\Core\Utility\Token arguments: ['@module_handler'] diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php b/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php deleted file mode 100644 index d270688..0000000 --- a/core/lib/Drupal/Core/Config/ConfigFactoryOverridePass.php +++ /dev/null @@ -1,57 +0,0 @@ -getDefinition('config.factory'); - $services = array(); - foreach ($container->findTaggedServiceIds('config.factory.override') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $services[] = array('id' => $id, 'priority' => $priority); - } - usort($services, array($this, 'compareServicePriorities')); - foreach ($services as $service) { - $manager->addMethodCall('addOverride', array(new Reference($service['id']))); - } - } - - /** - * Compares services by priority for ordering. - * - * @param array $a - * Service to compare. - * @param array $b - * Service to compare. - * - * @return int - * Relative order of services to be used with usort. Higher priorities come - * first. - */ - private function compareServicePriorities($a, $b) { - if ($a['priority'] == $b['priority']) { - return 0; - } - return ($a['priority'] > $b['priority']) ? -1 : 1; - } - -} diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index 2faca69..7586120 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -10,21 +10,15 @@ use Drupal\Core\Cache\CacheContextsPass; use Drupal\Component\Utility\Settings; use Drupal\Core\Cache\ListCacheBinsPass; -use Drupal\Core\Config\ConfigFactoryOverridePass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; use Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass; -use Drupal\Core\DependencyInjection\Compiler\RegisterPathProcessorsPass; -use Drupal\Core\DependencyInjection\Compiler\RegisterRouteProcessorsPass; -use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; -use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass; -use Drupal\Core\DependencyInjection\Compiler\RegisterTwigExtensionsPass; use Drupal\Core\Plugin\PluginManagerPass; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -68,25 +62,16 @@ public function register(ContainerBuilder $container) { // Add a compiler pass for registering event subscribers. $container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new RegisterAccessChecksPass()); - // Add a compiler pass for upcasting route parameters. - $container->addCompilerPass(new RegisterParamConvertersPass()); - $container->addCompilerPass(new RegisterRouteEnhancersPass()); // Add a compiler pass for registering services needing destruction. $container->addCompilerPass(new RegisterServicesForDestructionPass()); // Add the compiler pass that will process the tagged services. - $container->addCompilerPass(new RegisterPathProcessorsPass()); - $container->addCompilerPass(new RegisterRouteProcessorsPass()); $container->addCompilerPass(new ListCacheBinsPass()); $container->addCompilerPass(new CacheContextsPass()); - // Add the compiler pass for appending string translators. - $container->addCompilerPass(new RegisterStringTranslatorsPass()); - // Add the compiler pass that will process the tagged config factory - // override services. - $container->addCompilerPass(new ConfigFactoryOverridePass()); - // Add the compiler pass that will process tagged authentication services. + + // @todo Remove needless dependency on entire service container. + $container->addCompilerPass(new RegisterParamConvertersPass()); $container->addCompilerPass(new RegisterAuthenticationPass()); - // Register Twig extensions. - $container->addCompilerPass(new RegisterTwigExtensionsPass()); + // Register plugin managers. $container->addCompilerPass(new PluginManagerPass()); } @@ -121,7 +106,12 @@ public static function registerTwig(ContainerBuilder $container) { ->addMethodCall('addExtension', array(new Definition('Drupal\Core\Template\TwigExtension'))) // @todo Figure out what to do about debugging functions. // @see http://drupal.org/node/1804998 - ->addMethodCall('addExtension', array(new Definition('Twig_Extension_Debug'))); + ->addMethodCall('addExtension', array(new Definition('Twig_Extension_Debug'))) + ->addTag('compiler_pass', array( + 'tag' => 'twig.extension', + 'method' => 'addExtension', + 'require' => 'Twig_ExtensionInterface', + )); } /** diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php deleted file mode 100644 index 70de42d..0000000 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterPathProcessorsPass.php +++ /dev/null @@ -1,41 +0,0 @@ -hasDefinition('path_processor_manager')) { - return; - } - $manager = $container->getDefinition('path_processor_manager'); - // Add inbound path processors. - foreach ($container->findTaggedServiceIds('path_processor_inbound') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $manager->addMethodCall('addInbound', array(new Reference($id), $priority)); - } - // Add outbound path processors. - foreach ($container->findTaggedServiceIds('path_processor_outbound') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $manager->addMethodCall('addOutbound', array(new Reference($id), $priority)); - } - } -} diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php deleted file mode 100644 index 927c6dc..0000000 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteEnhancersPass.php +++ /dev/null @@ -1,36 +0,0 @@ -hasDefinition('router.dynamic')) { - return; - } - - $router = $container->getDefinition('router.dynamic'); - foreach ($container->findTaggedServiceIds('route_enhancer') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $router->addMethodCall('addRouteEnhancer', array(new Reference($id), $priority)); - } - } -} diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteProcessorsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteProcessorsPass.php deleted file mode 100644 index dd95869..0000000 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterRouteProcessorsPass.php +++ /dev/null @@ -1,34 +0,0 @@ -hasDefinition('route_processor_manager')) { - return; - } - $manager = $container->getDefinition('route_processor_manager'); - // Add outbound route processors. - foreach ($container->findTaggedServiceIds('route_processor_outbound') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $manager->addMethodCall('addOutbound', array(new Reference($id), $priority)); - } - } - -} diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php deleted file mode 100644 index 39a0764..0000000 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php +++ /dev/null @@ -1,33 +0,0 @@ -hasDefinition('string_translation')) { - return; - } - $access_manager = $container->getDefinition('string_translation'); - foreach ($container->findTaggedServiceIds('string_translator') as $id => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $access_manager->addMethodCall('addTranslator', array(new Reference($id), $priority)); - } - } - -} diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterTwigExtensionsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterTwigExtensionsPass.php deleted file mode 100644 index 3df9b87..0000000 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterTwigExtensionsPass.php +++ /dev/null @@ -1,46 +0,0 @@ -hasDefinition('twig')) { - return; - } - - $definition = $container->getDefinition('twig'); - - foreach ($container->findTaggedServiceIds('twig.extension') as $id => $attributes) { - // We must assume that the class value has been correcly filled, - // even if the service is created by a factory. - $class = $container->getDefinition($id)->getClass(); - - $refClass = new \ReflectionClass($class); - $interface = 'Twig_ExtensionInterface'; - if (!$refClass->implementsInterface($interface)) { - throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); - } - $definition->addMethodCall('addExtension', array(new Reference($id))); - } - } - -} diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php index 6aac0ef..43b3cb5 100644 --- a/core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/TaggedHandlersPass.php @@ -9,6 +9,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\BadMethodCallException; use Symfony\Component\DependencyInjection\Reference; /** @@ -23,50 +24,72 @@ class TaggedHandlersPass implements CompilerPassInterface { * all tagged handlers/providers for it to its definition. * * Supported compiler_pass tag attributes: - * - tag: (optional) The tag name used by handler services to collect. - * Defaults to the service ID of the consumer. - * - method: (optional) The method name to call on the consumer service. - * Defaults to 'addHandler'. This method gets the handler instance as first - * argument and the handler's priority as second, whereas all handlers - * discovered at compile time are sorted already. - * - require: (optional) A fully qualified interface name to validate before - * adding handlers. + * - tag: The tag name used by handler services to collect. Defaults to the + * service ID of the consumer. + * - method: The method name to call on the consumer service. Defaults to + * 'addHandler'. This method gets the handler instance as first argument and + * the handler's priority as second, whereas all handlers discovered at + * compile time are sorted already. + * - require: A fully qualified interface name to validate before adding + * handlers. None by default. + * + * Example (YAML): + * @code + * tags: + * - name: compiler_pass + * tag: breadcrumb_builder + * method: addBuilder + * require: Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface + * @encode * * Supported handler tag attributes: - * - priority: (optional) An integer denoting the priority of the handler. - * Defaults to 0. + * - priority: An integer denoting the priority of the handler. Defaults to 0. + * + * Example (YAML): + * @code + * tags: + * - name: breadcrumb_builder + * priority: 100 + * @endcode + * + * @throws \Symfony\Component\DependencyInjection\Exception\BadMethodCallException + * If a tagged handler does not implement the required interface. */ public function process(ContainerBuilder $container) { - foreach ($container->findTaggedServiceIds('compiler_pass') as $consumer_id => $consumer_attributes) { - $consumer_attributes = $consumer_attributes[0]; - // Ensure defaults. - $consumer_attributes += array( - 'tag' => $consumer_id, - 'method' => 'addHandler', - ); - // Find all tagged handlers. - $handlers = array(); - foreach ($container->findTaggedServiceIds($consumer_attributes['tag']) as $id => $attributes) { - // If an interface constraint exists, ensure that every handler meets it. - if (isset($consumer_attributes['require'])) { - $handler = $container->getDefinition($id); - // @todo Shouldn't this rather blow up with an exception? - if (!is_subclass_of($handler->getClass(), $consumer_attributes['require'])) { - continue; + foreach ($container->findTaggedServiceIds('compiler_pass') as $consumer_id => $passes) { + foreach ($passes as $pass) { + $consumer_attributes = $pass; + // Ensure defaults. + $consumer_attributes += array( + 'tag' => $consumer_id, + 'method' => 'addHandler', + ); + // Find all tagged handlers. + $handlers = array(); + foreach ($container->findTaggedServiceIds($consumer_attributes['tag']) as $id => $attributes) { + // If an interface constraint exists, ensure that every handler meets it. + if (isset($consumer_attributes['require'])) { + $handler = $container->getDefinition($id); + if (!is_subclass_of($handler->getClass(), $consumer_attributes['require'])) { + if ($container->getParameter('kernel.environment') === 'prod') { + continue; + } + throw new BadMethodCallException("Handler service '$id' for consumer '$consumer_id' does not implement {$consumer_attributes['require']}."); + } } + $handlers[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; } - $handlers[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - } - if (empty($handlers)) { - continue; - } - // Sort all handlers by priority. - arsort($handlers, SORT_NUMERIC); + if (empty($handlers)) { + continue; + } + // Sort all handlers by priority. + arsort($handlers, SORT_NUMERIC); - // Add a method call for each handler to the consumer service definition. - $consumer = $container->getDefinition($consumer_id); - foreach ($handlers as $id => $priority) { - $consumer->addMethodCall($consumer_attributes['method'], array(new Reference($id), $priority)); + // Add a method call for each handler to the consumer service definition. + $consumer = $container->getDefinition($consumer_id); + foreach ($handlers as $id => $priority) { + $consumer->addMethodCall($consumer_attributes['method'], array(new Reference($id), $priority)); + } } } }