Issue #2302617 by dawehner, chx | Crell: Define a standard mechaism for backend-aware service overrides.
parent
64387e5c5e
commit
36faf4e8f1
|
@ -9,6 +9,7 @@ namespace Drupal\Core;
|
|||
|
||||
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;
|
||||
|
@ -49,6 +50,8 @@ class CoreServiceProvider implements ServiceProviderInterface {
|
|||
// 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());
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?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…
Reference in New Issue