Commit 8723cb96 authored by catch's avatar catch

Revert "Revert "Issue #2241633 by sun: Simplify site-specific service overrides.""

This reverts commit ecf2fa72.
parent ecf2fa72
...@@ -28,7 +28,13 @@ public function process(ContainerBuilder $container) { ...@@ -28,7 +28,13 @@ public function process(ContainerBuilder $container) {
if (!($kernel instanceof DrupalKernelInterface)) { if (!($kernel instanceof DrupalKernelInterface)) {
return; return;
} }
$providers = $kernel->getServiceProviders(); $providers = $kernel->getServiceProviders('app');
foreach ($providers as $provider) {
if ($provider instanceof ServiceModifierInterface) {
$provider->alter($container);
}
}
$providers = $kernel->getServiceProviders('site');
foreach ($providers as $provider) { foreach ($providers as $provider) {
if ($provider instanceof ServiceModifierInterface) { if ($provider instanceof ServiceModifierInterface) {
$provider->alter($container); $provider->alter($container);
......
...@@ -109,13 +109,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { ...@@ -109,13 +109,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
*/ */
protected $configStorage; protected $configStorage;
/**
* The list of the classnames of the service providers in this kernel.
*
* @var array
*/
protected $serviceProviderClasses;
/** /**
* Whether the container can be dumped. * Whether the container can be dumped.
* *
...@@ -131,14 +124,33 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface { ...@@ -131,14 +124,33 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
protected $containerNeedsDumping; protected $containerNeedsDumping;
/** /**
* Holds the list of YAML files containing service definitions. * List of discovered services.yml pathnames.
*
* This is a nested array whose top-level keys are 'app' and 'site', denoting
* the origin of a service provider. Site-specific providers have to be
* collected separately, because they need to be processed last, so as to be
* able to override services from application service providers.
* *
* @var array * @var array
*/ */
protected $serviceYamls; protected $serviceYamls;
/** /**
* The array of registered service providers. * List of discovered service provider class names.
*
* This is a nested array whose top-level keys are 'app' and 'site', denoting
* the origin of a service provider. Site-specific providers have to be
* collected separately, because they need to be processed last, so as to be
* able to override services from application service providers.
*
* @var array
*/
protected $serviceProviderClasses;
/**
* List of instantiated service provider classes.
*
* @see \Drupal\Core\DrupalKernel::$serviceProviderClasses
* *
* @var array * @var array
*/ */
...@@ -203,16 +215,18 @@ public function getContainer() { ...@@ -203,16 +215,18 @@ public function getContainer() {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function discoverServiceProviders() { public function discoverServiceProviders() {
$serviceProviders = array(
'CoreServiceProvider' => new CoreServiceProvider(),
);
$this->serviceYamls = array( $this->serviceYamls = array(
'core/core.services.yml' 'app' => array(),
'site' => array(),
); );
$this->serviceProviderClasses = array('Drupal\Core\CoreServiceProvider'); $this->serviceProviderClasses = array(
'app' => array(),
'site' => array(),
);
$this->serviceYamls['app']['core'] = 'core/core.services.yml';
$this->serviceProviderClasses['app']['core'] = 'Drupal\Core\CoreServiceProvider';
// Ensure we know what modules are enabled and that their namespaces are // Retrieve enabled modules and register their namespaces.
// registered.
if (!isset($this->moduleList)) { if (!isset($this->moduleList)) {
$extensions = $this->getConfigStorage()->read('core.extension'); $extensions = $this->getConfigStorage()->read('core.extension');
$this->moduleList = isset($extensions['module']) ? $extensions['module'] : array(); $this->moduleList = isset($extensions['module']) ? $extensions['module'] : array();
...@@ -226,34 +240,35 @@ public function discoverServiceProviders() { ...@@ -226,34 +240,35 @@ public function discoverServiceProviders() {
$name = "{$camelized}ServiceProvider"; $name = "{$camelized}ServiceProvider";
$class = "Drupal\\{$module}\\{$name}"; $class = "Drupal\\{$module}\\{$name}";
if (class_exists($class)) { if (class_exists($class)) {
$serviceProviders[$name] = new $class(); $this->serviceProviderClasses['app'][$module] = $class;
$this->serviceProviderClasses[] = $class;
} }
$filename = dirname($module_filenames[$module]) . "/$module.services.yml"; $filename = dirname($module_filenames[$module]) . "/$module.services.yml";
if (file_exists($filename)) { if (file_exists($filename)) {
$this->serviceYamls[] = $filename; $this->serviceYamls['app'][$module] = $filename;
} }
} }
// Add site specific or test service providers. // Add site-specific service providers.
if (!empty($GLOBALS['conf']['container_service_providers'])) { if (!empty($GLOBALS['conf']['container_service_providers'])) {
foreach ($GLOBALS['conf']['container_service_providers'] as $name => $class) { foreach ($GLOBALS['conf']['container_service_providers'] as $class) {
$serviceProviders[$name] = new $class(); if (class_exists($class)) {
$this->serviceProviderClasses[] = $class; $this->serviceProviderClasses['site'][] = $class;
}
} }
} }
// Add site specific or test YAMLs.
if (!empty($GLOBALS['conf']['container_yamls'])) { if (!empty($GLOBALS['conf']['container_yamls'])) {
$this->serviceYamls = array_merge($this->serviceYamls, $GLOBALS['conf']['container_yamls']); $this->serviceYamls['site'] = $GLOBALS['conf']['container_yamls'];
}
if (file_exists($site_services_yml = conf_path() . '/services.yml')) {
$this->serviceYamls['site'][] = $site_services_yml;
} }
return $serviceProviders;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getServiceProviders() { public function getServiceProviders($origin) {
return $this->serviceProviders; return $this->serviceProviders[$origin];
} }
/** /**
...@@ -496,7 +511,6 @@ protected function buildContainer() { ...@@ -496,7 +511,6 @@ protected function buildContainer() {
$this->initializeServiceProviders(); $this->initializeServiceProviders();
$container = $this->getContainerBuilder(); $container = $this->getContainerBuilder();
$container->set('kernel', $this); $container->set('kernel', $this);
$container->setParameter('container.service_providers', $this->serviceProviderClasses);
$container->setParameter('container.modules', $this->getModulesParameter()); $container->setParameter('container.modules', $this->getModulesParameter());
// Get a list of namespaces and put it onto the container. // Get a list of namespaces and put it onto the container.
...@@ -531,11 +545,22 @@ protected function buildContainer() { ...@@ -531,11 +545,22 @@ protected function buildContainer() {
$container->register('class_loader')->setSynthetic(TRUE); $container->register('class_loader')->setSynthetic(TRUE);
$container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE); $container->register('kernel', 'Symfony\Component\HttpKernel\KernelInterface')->setSynthetic(TRUE);
$container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE); $container->register('service_container', 'Symfony\Component\DependencyInjection\ContainerInterface')->setSynthetic(TRUE);
// Register application services.
$yaml_loader = new YamlFileLoader($container); $yaml_loader = new YamlFileLoader($container);
foreach ($this->serviceYamls as $filename) { foreach ($this->serviceYamls['app'] as $filename) {
$yaml_loader->load($filename);
}
foreach ($this->serviceProviders['app'] as $provider) {
if ($provider instanceof ServiceProviderInterface) {
$provider->register($container);
}
}
// Register site-specific service overrides.
foreach ($this->serviceYamls['site'] as $filename) {
$yaml_loader->load($filename); $yaml_loader->load($filename);
} }
foreach ($this->serviceProviders as $provider) { foreach ($this->serviceProviders['site'] as $provider) {
if ($provider instanceof ServiceProviderInterface) { if ($provider instanceof ServiceProviderInterface) {
$provider->register($container); $provider->register($container);
} }
...@@ -563,13 +588,15 @@ protected function buildContainer() { ...@@ -563,13 +588,15 @@ protected function buildContainer() {
* @throws \LogicException * @throws \LogicException
*/ */
protected function initializeServiceProviders() { protected function initializeServiceProviders() {
$this->serviceProviders = array(); $this->discoverServiceProviders();
$this->serviceProviders = array(
foreach ($this->discoverServiceProviders() as $name => $provider) { 'app' => array(),
if (isset($this->serviceProviders[$name])) { 'site' => array(),
throw new \LogicException(sprintf('Trying to register two service providers with the same name "%s"', $name)); );
foreach ($this->serviceProviderClasses as $origin => $classes) {
foreach ($classes as $name => $class) {
$this->serviceProviders[$origin][$name] = new $class;
} }
$this->serviceProviders[$name] = $provider;
} }
} }
......
...@@ -38,10 +38,13 @@ public function discoverServiceProviders(); ...@@ -38,10 +38,13 @@ public function discoverServiceProviders();
/** /**
* Returns all registered service providers. * Returns all registered service providers.
* *
* @param string $origin
* The origin for which to return service providers; one of 'app' or 'site'.
*
* @return array * @return array
* An associative array of ServiceProvider objects, keyed by name. * An associative array of ServiceProvider objects, keyed by name.
*/ */
public function getServiceProviders(); public function getServiceProviders($origin);
/** /**
* Gets the current container. * Gets the current container.
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\DrupalKernel\DrupalKernelSiteTest.
*/
namespace Drupal\system\Tests\DrupalKernel;
use Drupal\simpletest\DrupalUnitTestBase;
/**
* Tests site-specific service overrides.
*/
class DrupalKernelSiteTest extends DrupalUnitTestBase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'DrupalKernel site service overrides',
'description' => 'Tests site-specific service overrides.',
'group' => 'DrupalKernel',
);
}
/**
* Tests services.yml in site directory.
*/
public function testServicesYml() {
$this->assertFalse($this->container->has('site.service.yml'));
// A service provider class always has precedence over services.yml files.
// DrupalUnitTestBase::buildContainer() swaps out many services with
// in-memory implementations already, so those cannot be tested.
$this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\DatabaseBackendFactory');
$class = __CLASS__;
$doc = <<<EOD
services:
# Add a new service.
site.service.yml:
class: $class
# Swap out a core service.
cache.backend.database:
class: Drupal\Core\Cache\MemoryBackendFactory
EOD;
file_put_contents($this->siteDirectory . '/services.yml', $doc);
// Rebuild the container.
$this->kernel->updateModules(array());
$this->assertTrue($this->container->has('site.service.yml'));
$this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\MemoryBackendFactory');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment