Commit b1c684b8 authored by alexpott's avatar alexpott

Issue #1988508 by katbailey: Stop pretending we support Symfony bundles when...

Issue #1988508 by katbailey: Stop pretending we support Symfony bundles when we really just have service providers.
parent 77947830
...@@ -1889,8 +1889,7 @@ function drupal_handle_request($test_only = FALSE) { ...@@ -1889,8 +1889,7 @@ function drupal_handle_request($test_only = FALSE) {
exit; exit;
} }
// @todo Figure out how best to handle the Kernel constructor parameters. $kernel = new DrupalKernel('prod', drupal_classloader(), !$test_only);
$kernel = new DrupalKernel('prod', FALSE, drupal_classloader(), !$test_only);
// @todo Remove this once everything in the bootstrap has been // @todo Remove this once everything in the bootstrap has been
// converted to services in the DIC. // converted to services in the DIC.
...@@ -2026,7 +2025,7 @@ function _drupal_bootstrap_kernel() { ...@@ -2026,7 +2025,7 @@ function _drupal_bootstrap_kernel() {
// Normally, index.php puts a container in drupal_container() by creating a // Normally, index.php puts a container in drupal_container() by creating a
// kernel. If there is no container yet, create one. // kernel. If there is no container yet, create one.
if (!drupal_container()) { if (!drupal_container()) {
$kernel = new DrupalKernel('prod', FALSE, drupal_classloader()); $kernel = new DrupalKernel('prod', drupal_classloader());
$kernel->boot(); $kernel->boot();
} }
} }
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
use Drupal\Core\Config\FileStorage; use Drupal\Core\Config\FileStorage;
use Drupal\Core\DrupalKernel; use Drupal\Core\DrupalKernel;
use Drupal\Core\CoreBundle; use Drupal\Core\CoreServiceProvider;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\Database\Install\TaskException; use Drupal\Core\Database\Install\TaskException;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManager; use Drupal\Core\Language\LanguageManager;
use Drupal\Core\StringTranslation\Translator\FileTranslation; use Drupal\Core\StringTranslation\Translator\FileTranslation;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
...@@ -354,7 +354,7 @@ function install_begin_request(&$install_state) { ...@@ -354,7 +354,7 @@ function install_begin_request(&$install_state) {
// @see drupal_install_config_directories() // @see drupal_install_config_directories()
// @see install_settings_form_submit() // @see install_settings_form_submit()
if ($install_state['settings_verified']) { if ($install_state['settings_verified']) {
$kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE); $kernel = new DrupalKernel('install', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
$container = $kernel->getContainer(); $container = $kernel->getContainer();
// Add the file translation service to the container. // Add the file translation service to the container.
...@@ -426,7 +426,7 @@ function install_begin_request(&$install_state) { ...@@ -426,7 +426,7 @@ function install_begin_request(&$install_state) {
$conf['keyvalue_expirable_default'] = 'keyvalue.expirable.null'; $conf['keyvalue_expirable_default'] = 'keyvalue.expirable.null';
// Register Twig template engine for use during install. // Register Twig template engine for use during install.
CoreBundle::registerTwig($container); CoreServiceProvider::registerTwig($container);
$container->register('url_generator', 'Drupal\Core\Routing\NullGenerator'); $container->register('url_generator', 'Drupal\Core\Routing\NullGenerator');
......
...@@ -619,7 +619,7 @@ function drupal_install_system() { ...@@ -619,7 +619,7 @@ function drupal_install_system() {
if (!drupal_container()->has('kernel')) { if (!drupal_container()->has('kernel')) {
// Immediately boot a kernel to have real services ready. // Immediately boot a kernel to have real services ready.
$kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE); $kernel = new DrupalKernel('install', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
} }
......
...@@ -103,10 +103,9 @@ function update_prepare_d8_bootstrap() { ...@@ -103,10 +103,9 @@ function update_prepare_d8_bootstrap() {
$settings['cache']['default'] = 'cache.backend.memory'; $settings['cache']['default'] = 'cache.backend.memory';
new Settings($settings); new Settings($settings);
// Enable UpdateBundle service overrides. While the container_bundles array // Enable UpdateServiceProvider service overrides.
// does not need a key, let's use so it can be removed once the upgrade are // @see update_flush_all_caches()
// finished. @see update_flush_all_caches() $GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
$GLOBALS['conf']['container_bundles']['UpdateBundle'] = 'Drupal\Core\DependencyInjection\UpdateBundle';
// Check whether settings.php needs to be rewritten. // Check whether settings.php needs to be rewritten.
$settings_exist = !empty($GLOBALS['config_directories']); $settings_exist = !empty($GLOBALS['config_directories']);
...@@ -117,7 +116,7 @@ function update_prepare_d8_bootstrap() { ...@@ -117,7 +116,7 @@ function update_prepare_d8_bootstrap() {
// Bootstrap the kernel. // Bootstrap the kernel.
// Do not attempt to dump and write it. // Do not attempt to dump and write it.
$kernel = new DrupalKernel('update', FALSE, drupal_classloader(), FALSE); $kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
// If any of the required settings needs to be written, then settings.php // If any of the required settings needs to be written, then settings.php
...@@ -440,7 +439,7 @@ function update_prepare_d8_bootstrap() { ...@@ -440,7 +439,7 @@ function update_prepare_d8_bootstrap() {
$settings = settings()->getAll(); $settings = settings()->getAll();
unset($settings['cache']['default']); unset($settings['cache']['default']);
new Settings($settings); new Settings($settings);
$kernel = new DrupalKernel('update', FALSE, drupal_classloader(), FALSE); $kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
$kernel->boot(); $kernel->boot();
} }
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
* *
* The container is built by the kernel and passed in to this class which stores * The container is built by the kernel and passed in to this class which stores
* it statically. The container always contains the services from * it statically. The container always contains the services from
* \Drupal\Core\CoreBundle, the bundles of enabled modules and any other bundles * \Drupal\Core\CoreServiceProvider, the service providers of enabled modules and any other
* defined in $GLOBALS['conf']['container_bundles']. * service providers defined in $GLOBALS['conf']['container_service_providers'].
* *
* This class exists only to support legacy code that cannot be dependency * This class exists only to support legacy code that cannot be dependency
* injected. If your code needs it, consider refactoring it to be object * injected. If your code needs it, consider refactoring it to be object
......
...@@ -2,12 +2,15 @@ ...@@ -2,12 +2,15 @@
/** /**
* @file * @file
* Definition of Drupal\Core\CoreBundle. * Definition of Drupal\Core\CoreServiceProvider.
*/ */
namespace Drupal\Core; namespace Drupal\Core;
use Drupal\Core\Cache\ListCacheBinsPass; use Drupal\Core\Cache\ListCacheBinsPass;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass; use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterMatchersPass;
...@@ -18,16 +21,14 @@ ...@@ -18,16 +21,14 @@
use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass; use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Scope; use Symfony\Component\DependencyInjection\Scope;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Compiler\PassConfig;
/** /**
* Bundle class for mandatory core services. * ServiceProvider class for mandatory core services.
* *
* This is where Drupal core registers all of its compiler passes. * This is where Drupal core registers all of its compiler passes.
* The service definitions themselves are in core/core.services.yml with a * The service definitions themselves are in core/core.services.yml with a
...@@ -36,12 +37,12 @@ ...@@ -36,12 +37,12 @@
* Modules wishing to register services to the container should use * Modules wishing to register services to the container should use
* modulename.services.yml in their respective directories. * modulename.services.yml in their respective directories.
*/ */
class CoreBundle extends Bundle { class CoreServiceProvider implements ServiceProviderInterface {
/** /**
* Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build(). * {@inheritdoc}
*/ */
public function build(ContainerBuilder $container) { public function register(ContainerBuilder $container) {
// The 'request' scope and service enable services to depend on the Request // The 'request' scope and service enable services to depend on the Request
// object and get reconstructed when the request object changes (e.g., // object and get reconstructed when the request object changes (e.g.,
// during a subrequest). // during a subrequest).
...@@ -67,6 +68,9 @@ public function build(ContainerBuilder $container) { ...@@ -67,6 +68,9 @@ public function build(ContainerBuilder $container) {
// Add the compiler pass that will process the tagged breadcrumb builder // Add the compiler pass that will process the tagged breadcrumb builder
// services. // services.
$container->addCompilerPass(new RegisterBreadcrumbBuilderPass()); $container->addCompilerPass(new RegisterBreadcrumbBuilderPass());
// Add the compiler pass that lets service providers modify existing
// service definitions.
$container->addCompilerPass(new ModifyServiceDefinitionsPass());
} }
/** /**
......
<?php
/**
* @file
* Contains Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass.
*/
namespace Drupal\Core\DependencyInjection\Compiler;
use Drupal\Core\DrupalKernelInterface;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
/**
* Passes the container to the alter() method of all service providers.
*/
class ModifyServiceDefinitionsPass implements CompilerPassInterface {
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container) {
if (!$container->has('kernel')) {
return;
}
$kernel = $container->get('kernel');
if (!($kernel instanceof DrupalKernelInterface)) {
return;
}
$providers = $kernel->getServiceProviders();
foreach ($providers as $provider) {
if ($provider instanceof ServiceModifierInterface) {
$provider->alter($container);
}
}
}
}
<?php
namespace Drupal\Core\DependencyInjection;
/**
* Interface that service providers can implement to modify services.
*/
interface ServiceModifierInterface {
/**
* Modifies existing service definitions.
*
* @param ContainerBuilder $container
* The ContainerBuilder whose service definitions can be altered.
*/
public function alter(ContainerBuilder $container);
}
<?php
namespace Drupal\Core\DependencyInjection;
/**
* Interface that all service providers must implement.
*/
interface ServiceProviderInterface {
/**
* Registers services to the container.
*
* @param ContainerBuilder $container
* The ContainerBuilder to register services to.
*/
public function register(ContainerBuilder $container);
}
...@@ -2,27 +2,27 @@ ...@@ -2,27 +2,27 @@
/** /**
* @file * @file
* Contains \Drupal\Core\DependencyInjection\UpdateBundle. * Contains \Drupal\Core\DependencyInjection\UpdateServiceProvider.
*/ */
namespace Drupal\Core\DependencyInjection; namespace Drupal\Core\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle; use Drupal\Core\DependencyInjection\ServiceProviderInterface;
/** /**
* Bundle class for update.php service overrides. * ServiceProvider class for update.php service overrides.
* *
* This bundle is manually added by update.php via $conf['container_bundles'] * This class is manually added by update.php via $conf['container_service_providers']
* and required to prevent various services from trying to retrieve data from * and required to prevent various services from trying to retrieve data from
* storages that do not exist yet. * storages that do not exist yet.
*/ */
class UpdateBundle extends Bundle { class UpdateServiceProvider implements ServiceProviderInterface {
/** /**
* Implements \Symfony\Component\HttpKernel\Bundle\BundleInterface::build(). * {@inheritdoc}
*/ */
public function build(SymfonyContainerBuilder $container) { public function register(ContainerBuilder $container) {
// Disable the Lock service. // Disable the Lock service.
$container $container
->register('lock', 'Drupal\Core\Lock\NullLockBackend'); ->register('lock', 'Drupal\Core\Lock\NullLockBackend');
......
...@@ -9,26 +9,55 @@ ...@@ -9,26 +9,55 @@
use Drupal\Component\PhpStorage\PhpStorageFactory; use Drupal\Component\PhpStorage\PhpStorageFactory;
use Drupal\Core\Config\BootstrapConfigStorageFactory; use Drupal\Core\Config\BootstrapConfigStorageFactory;
use Drupal\Core\CoreBundle; use Drupal\Core\CoreServiceProvider;
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\YamlFileLoader; use Drupal\Core\DependencyInjection\YamlFileLoader;
use Symfony\Component\ClassLoader\ClassLoader; use Symfony\Component\ClassLoader\ClassLoader;
use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
/** /**
* The DrupalKernel class is the core of Drupal itself. * The DrupalKernel class is the core of Drupal itself.
* *
* This class is responsible for building the Dependency Injection Container and * This class is responsible for building the Dependency Injection Container and
* also deals with the registration of bundles. It allows registered bundles to * also deals with the registration of service providers. It allows registered
* add their services to the container. Core provides the CoreBundle, which adds * service providers to add their services to the container. Core provides the
* the services required for all core subsystems. Each module can then add its * CoreServiceProvider, which, in addition to registering any core services that
* own bundle, i.e. a subclass of Symfony\Component\HttpKernel\Bundle, to * cannot be registered in the core.services.yaml file, adds any compiler passes
* register services to the container. * needed by core, e.g. for processing tagged services. Each module can add its
* own service provider, i.e. a class implementing
* Drupal\Core\DependencyInjection\ServiceProvider, to register services to the
* container, or modify existing services.
*/ */
class DrupalKernel extends Kernel implements DrupalKernelInterface { class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
const CONTAINER_BASE_CLASS = 'Container';
/**
* Holds the container instance.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* The environment, e.g. 'testing', 'install'.
*
* @var string
*/
protected $environment;
/**
* Whether the kernel has been booted.
*
* @var bool
*/
protected $booted;
/** /**
* Holds the list of enabled modules. * Holds the list of enabled modules.
...@@ -80,11 +109,11 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { ...@@ -80,11 +109,11 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface {
protected $configStorage; protected $configStorage;
/** /**
* The list of the classnames of the bundles in this kernel. * The list of the classnames of the service providers in this kernel.
* *
* @var array * @var array
*/ */
protected $bundleClasses; protected $serviceProviderClasses;
/** /**
* Whether the container can be dumped. * Whether the container can be dumped.
...@@ -107,6 +136,13 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { ...@@ -107,6 +136,13 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface {
*/ */
protected $serviceYamls; protected $serviceYamls;
/**
* The array of registered service providers.
*
* @var array
*/
protected $serviceProviders;
/** /**
* Constructs a DrupalKernel object. * Constructs a DrupalKernel object.
* *
...@@ -114,21 +150,18 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface { ...@@ -114,21 +150,18 @@ class DrupalKernel extends Kernel implements DrupalKernelInterface {
* String indicating the environment, e.g. 'prod' or 'dev'. Used by * String indicating the environment, e.g. 'prod' or 'dev'. Used by
* Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use * Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
* this value currently. Pass 'prod'. * this value currently. Pass 'prod'.
* @param bool $debug
* Boolean indicating whether we are in debug mode. Used by
* Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
* this value currently. Pass TRUE.
* @param \Symfony\Component\ClassLoader\ClassLoader $class_loader * @param \Symfony\Component\ClassLoader\ClassLoader $class_loader
* (optional) The classloader is only used if $storage is not given or * (optional) The classloader is only used if $storage is not given or
* the load from storage fails and a container rebuild is required. In * the load from storage fails and a container rebuild is required. In
* this case, the loaded modules will be registered with this loader in * this case, the loaded modules will be registered with this loader in
* order to be able to find the module bundles. * order to be able to find the module serviceProviders.
* @param bool $allow_dumping * @param bool $allow_dumping
* (optional) FALSE to stop the container from being written to or read * (optional) FALSE to stop the container from being written to or read
* from disk. Defaults to TRUE. * from disk. Defaults to TRUE.
*/ */
public function __construct($environment, $debug, ClassLoader $class_loader, $allow_dumping = TRUE) { public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE) {
parent::__construct($environment, $debug); $this->environment = $environment;
$this->booted = false;
$this->classLoader = $class_loader; $this->classLoader = $class_loader;
$this->allowDumping = $allow_dumping; $this->allowDumping = $allow_dumping;
} }
...@@ -137,29 +170,19 @@ public function __construct($environment, $debug, ClassLoader $class_loader, $al ...@@ -137,29 +170,19 @@ public function __construct($environment, $debug, ClassLoader $class_loader, $al
* {@inheritdoc} * {@inheritdoc}
*/ */
public function serialize() { public function serialize() {
return serialize(array($this->environment, $this->debug, $this->classLoader, $this->allowDumping)); return serialize(array($this->environment, $this->classLoader, $this->allowDumping));
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function unserialize($data) { public function unserialize($data) {
list($environment, $debug, $class_loader, $allow_dumping) = unserialize($data); list($environment, $class_loader, $allow_dumping) = unserialize($data);
$this->__construct($environment, $debug, $class_loader, $allow_dumping); $this->__construct($environment, $class_loader, $allow_dumping);
}
/**
* Overrides Kernel::init().
*/
public function init() {
// Intentionally empty. The sole purpose is to not execute Kernel::init(),
// since that overrides/breaks Drupal's current error handling.
// @todo Investigate whether it is possible to migrate Drupal's error
// handling to the one of Kernel without losing functionality.
} }
/** /**
* Overrides Kernel::boot(). * {@inheritdoc}
*/ */
public function boot() { public function boot() {
if ($this->booted) { if ($this->booted) {
...@@ -167,26 +190,41 @@ public function boot() { ...@@ -167,26 +190,41 @@ public function boot() {
} }
$this->initializeContainer(); $this->initializeContainer();
$this->booted = TRUE; $this->booted = TRUE;
if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, $this->getContainerBaseClass())) { if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, static::CONTAINER_BASE_CLASS)) {
watchdog('DrupalKernel', 'Container cannot be written to disk'); watchdog('DrupalKernel', 'Container cannot be written to disk');
} }
} }
/** /**
* Returns an array of available bundles. * {@inheritdoc}
*
* @return array
* The available bundles.
*/ */
public function registerBundles() { public function shutdown() {
if (FALSE === $this->booted) {
return;
}
$this->booted = FALSE;
$this->container = null;
}
/**
* {@inheritdoc}
*/
public function getContainer() {
return $this->container;
}
/**
* {@inheritdoc}
*/
public function discoverServiceProviders() {
$this->configStorage = BootstrapConfigStorageFactory::get(); $this->configStorage = BootstrapConfigStorageFactory::get();
$bundles = array( $serviceProviders = array(
new CoreBundle(), 'CoreServiceProvider' => new CoreServiceProvider(),
); );
$this->serviceYamls = array( $this->serviceYamls = array(
'core/core.services.yml' 'core/core.services.yml'