Loading core/lib/Drupal/Core/CoreServiceProvider.php +3 −0 Changes for core/lib/Drupal/Core/CoreServiceProvider.php: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheContextsPass; use Drupal\Core\Cache\ListCacheBinsPass; use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; Loading Loading @@ -49,6 +50,8 @@ public function register(ContainerBuilder $container) { // list-building passes are operating on the post-alter services list. $container->addCompilerPass(new ModifyServiceDefinitionsPass()); $container->addCompilerPass(new BackendCompilerPass()); // Collect tagged handler services as method calls on consumer services. $container->addCompilerPass(new TaggedHandlersPass()); Loading core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php 0 → 100644 +63 −0 Changes for core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php: 63 added lines, 0 removed lines. Original line number Diff line number Diff line <?php /** * @file * Contains \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass. */ namespace Drupal\Core\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Defines a compiler pass to allow automatic override per backend. * * A module developer has to tag his backend service with "backend_overridable": * @code * custom_service: * class: ... * tags: * - { name: backend_overridable } * @endcode * * As a site admin you set the 'default_backend' in your services.yml file: * @code * parameters: * default_backend: sqlite * @endcode * * As a developer for alternative storage engines you register a service with * $yourbackend.$original_service: * * @code * sqlite.custom_service: * class: ... * @endcode */ class BackendCompilerPass implements CompilerPassInterface { /** * {@inheritdoc} */ public function process(ContainerBuilder $container) { $default_backend = $container->hasParameter('default_backend') ? $container->getParameter('default_backend') : NULL; // No default backend was configured, so continue as normal. if (!isset($default_backend)) { return; } foreach ($container->findTaggedServiceIds('backend_overridable') as $id => $attributes) { // If the service is already an alias it is not the original backend, so // we don't want to fallback to other storages any longer. if ($container->hasAlias($id)) { continue; } if ($container->hasDefinition("$default_backend.$id") || $container->hasAlias("$default_backend.$id")) { $container->setAlias($id, new Alias("$default_backend.$id")); } } } } core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php 0 → 100644 +93 −0 Changes for core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php: 93 added lines, 0 removed lines. Original line number Diff line number Diff line <?php /** * @file * Contains \Drupal\Tests\Core\DependencyInjection\Compiler\BackendCompilerPassTest. */ namespace Drupal\Tests\Core\DependencyInjection\Compiler; use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass * @group DependencyInjection */ class BackendCompilerPassTest extends UnitTestCase { /** * The tested backend compiler pass. * * @var \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass */ protected $backendPass; /** * {@inheritdoc} */ protected function setUp() { $this->backendPass = new BackendCompilerPass(); } /** * Tests the process method. * * @param string $expected_class * The expected used class. * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container * The container. * * @dataProvider providerTestProcess * * @covers ::process */ public function testProcess($expected_class, ContainerBuilder $container) { $this->backendPass->process($container); $this->assertInstanceOf($expected_class, $container->get('service')); } /** * Provides test data for testProcess(). * * @return array */ public function providerTestProcess() { $data = array(); // Add a container with no set default_backend. $container = new ContainerBuilder(); $prefix = '\\' . __NAMESPACE__ . '\\'; $container->setDefinition('service', (new Definition($prefix . 'ServiceClassDefault'))->addTag('backend_overridable')); $container->setDefinition('mysql.service', new Definition($prefix . 'ServiceClassMysql')); $data[] = array($prefix . 'ServiceClassDefault', $container); // Set the default_backend so the mysql service should be used. $container = clone $container; $container->setParameter('default_backend', 'mysql'); $data[] = array($prefix . 'ServiceClassMysql', $container); // Configure a manual alias for the service, so ensure that it is not // overridden by the default backend. $container = clone $container; $container->setDefinition('mariadb.service', new Definition($prefix . 'ServiceClassMariaDb')); $container->setAlias('service', new Alias('mariadb.service')); $data[] = array($prefix . 'ServiceClassMariaDb', $container); return $data; } } class ServiceClassDefault { } class ServiceClassMysql extends ServiceClassDefault { } class ServiceClassMariaDb extends ServiceClassMysql { } Loading
core/lib/Drupal/Core/CoreServiceProvider.php +3 −0 Changes for core/lib/Drupal/Core/CoreServiceProvider.php: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheContextsPass; use Drupal\Core\Cache\ListCacheBinsPass; use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; Loading Loading @@ -49,6 +50,8 @@ public function register(ContainerBuilder $container) { // list-building passes are operating on the post-alter services list. $container->addCompilerPass(new ModifyServiceDefinitionsPass()); $container->addCompilerPass(new BackendCompilerPass()); // Collect tagged handler services as method calls on consumer services. $container->addCompilerPass(new TaggedHandlersPass()); Loading
core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php 0 → 100644 +63 −0 Changes for core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php: 63 added lines, 0 removed lines. Original line number Diff line number Diff line <?php /** * @file * Contains \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass. */ namespace Drupal\Core\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Defines a compiler pass to allow automatic override per backend. * * A module developer has to tag his backend service with "backend_overridable": * @code * custom_service: * class: ... * tags: * - { name: backend_overridable } * @endcode * * As a site admin you set the 'default_backend' in your services.yml file: * @code * parameters: * default_backend: sqlite * @endcode * * As a developer for alternative storage engines you register a service with * $yourbackend.$original_service: * * @code * sqlite.custom_service: * class: ... * @endcode */ class BackendCompilerPass implements CompilerPassInterface { /** * {@inheritdoc} */ public function process(ContainerBuilder $container) { $default_backend = $container->hasParameter('default_backend') ? $container->getParameter('default_backend') : NULL; // No default backend was configured, so continue as normal. if (!isset($default_backend)) { return; } foreach ($container->findTaggedServiceIds('backend_overridable') as $id => $attributes) { // If the service is already an alias it is not the original backend, so // we don't want to fallback to other storages any longer. if ($container->hasAlias($id)) { continue; } if ($container->hasDefinition("$default_backend.$id") || $container->hasAlias("$default_backend.$id")) { $container->setAlias($id, new Alias("$default_backend.$id")); } } } }
core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php 0 → 100644 +93 −0 Changes for core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php: 93 added lines, 0 removed lines. Original line number Diff line number Diff line <?php /** * @file * Contains \Drupal\Tests\Core\DependencyInjection\Compiler\BackendCompilerPassTest. */ namespace Drupal\Tests\Core\DependencyInjection\Compiler; use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; /** * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass * @group DependencyInjection */ class BackendCompilerPassTest extends UnitTestCase { /** * The tested backend compiler pass. * * @var \Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass */ protected $backendPass; /** * {@inheritdoc} */ protected function setUp() { $this->backendPass = new BackendCompilerPass(); } /** * Tests the process method. * * @param string $expected_class * The expected used class. * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container * The container. * * @dataProvider providerTestProcess * * @covers ::process */ public function testProcess($expected_class, ContainerBuilder $container) { $this->backendPass->process($container); $this->assertInstanceOf($expected_class, $container->get('service')); } /** * Provides test data for testProcess(). * * @return array */ public function providerTestProcess() { $data = array(); // Add a container with no set default_backend. $container = new ContainerBuilder(); $prefix = '\\' . __NAMESPACE__ . '\\'; $container->setDefinition('service', (new Definition($prefix . 'ServiceClassDefault'))->addTag('backend_overridable')); $container->setDefinition('mysql.service', new Definition($prefix . 'ServiceClassMysql')); $data[] = array($prefix . 'ServiceClassDefault', $container); // Set the default_backend so the mysql service should be used. $container = clone $container; $container->setParameter('default_backend', 'mysql'); $data[] = array($prefix . 'ServiceClassMysql', $container); // Configure a manual alias for the service, so ensure that it is not // overridden by the default backend. $container = clone $container; $container->setDefinition('mariadb.service', new Definition($prefix . 'ServiceClassMariaDb')); $container->setAlias('service', new Alias('mariadb.service')); $data[] = array($prefix . 'ServiceClassMariaDb', $container); return $data; } } class ServiceClassDefault { } class ServiceClassMysql extends ServiceClassDefault { } class ServiceClassMariaDb extends ServiceClassMysql { }