Issue #1599108: first pass at adding bundles

Conflicts:

	core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php
8.0.x
Katherine Bailey 2012-06-25 21:04:49 -07:00
parent e06c4610db
commit 47c9feb9e7
8 changed files with 274 additions and 104 deletions

View File

@ -2458,7 +2458,7 @@ function drupal_container(ContainerBuilder $reset = NULL) {
$container = $reset;
}
elseif (!isset($container)) {
$container = new ContainerBuilder();
// HALP!!
}
return $container;
}

View File

@ -4913,9 +4913,9 @@ function _drupal_bootstrap_code() {
}
/**
* Temporary BC function for scripts not using HttpKernel.
* Temporary BC function for scripts not using DrupalKernel.
*
* HttpKernel skips this and replicates it via event listeners.
* DrupalKernel skips this and replicates it via event listeners.
*
* @see Drupal\Core\EventSubscriber\PathSubscriber;
* @see Drupal\Core\EventSubscriber\LegacyRequestSubscriber;

View File

@ -0,0 +1,36 @@
<?php
/**
* @file
* Definition of Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass.
*/
namespace Drupal\Core\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
class RegisterKernelListenersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('dispatcher')) {
return;
}
$definition = $container->getDefinition('dispatcher');
foreach ($container->findTaggedServiceIds('kernel.event_subscriber') 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 = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
if (!$refClass->implementsInterface($interface)) {
throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
}
$definition->addMethodCall('addSubscriberService', array($id, $class));
}
}
}

View File

@ -7,113 +7,38 @@
namespace Drupal\Core\DependencyInjection;
use Drupal\Core\ContentNegotiation;
use Drupal\Core\EventSubscriber\AccessSubscriber;
use Drupal\Core\EventSubscriber\FinishResponseSubscriber;
use Drupal\Core\EventSubscriber\LegacyControllerSubscriber;
use Drupal\Core\EventSubscriber\LegacyRequestSubscriber;
use Drupal\Core\EventSubscriber\MaintenanceModeSubscriber;
use Drupal\Core\EventSubscriber\PathSubscriber;
use Drupal\Core\EventSubscriber\RequestCloseSubscriber;
use Drupal\Core\EventSubscriber\RouterListener;
use Drupal\Core\EventSubscriber\ViewSubscriber;
use Drupal\Core\ExceptionController;
use Drupal\Core\LegacyUrlMatcher;
use Symfony\Component\DependencyInjection\ContainerBuilder as BaseContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\DependencyInjection\Compiler\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**
* Drupal's dependency injection container.
*/
class ContainerBuilder extends BaseContainerBuilder {
/**
* Registers the base Drupal services for the dependency injection container.
*/
public function __construct() {
parent::__construct();
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
{
if (!isset($this->compiler) || null === $this->compiler) {
$this->compiler = new Compiler();
}
// An interface language always needs to be available for t() and other
// functions. This default is overridden by drupal_language_initialize()
// during language negotiation.
$this->register(LANGUAGE_TYPE_INTERFACE, 'Drupal\\Core\\Language\\Language');
$this->compiler->addPass($pass, $type);
}
// Register the default language content.
$this->register(LANGUAGE_TYPE_CONTENT, 'Drupal\\Core\\Language\\Language');
public function compile()
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
// Register configuration storage dispatcher.
$this->setParameter('config.storage.info', array(
'Drupal\Core\Config\DatabaseStorage' => array(
'connection' => 'default',
'target' => 'default',
'read' => TRUE,
'write' => TRUE,
),
'Drupal\Core\Config\FileStorage' => array(
'directory' => config_get_config_directory(),
'read' => TRUE,
'write' => FALSE,
),
));
$this->register('config.storage.dispatcher', 'Drupal\Core\Config\StorageDispatcher')
->addArgument('%config.storage.info%');
$this->compiler->compile($this);
$this->parameterBag->resolve();
// TODO: The line below is commented out because there is code that calls
// the set() method on the container after it has been built - that method
// throws an exception if the container's parameters have been frozen.
//$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
}
// Register configuration object factory.
$this->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
->addArgument(new Reference('config.storage.dispatcher'));
// Register the HTTP kernel services.
$this->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher')
->addArgument(new Reference('service_container'))
->setFactoryClass('Drupal\Core\DependencyInjection\ContainerBuilder')
->setFactoryMethod('getKernelEventDispatcher');
$this->register('resolver', 'Symfony\Component\HttpKernel\Controller\ControllerResolver');
$this->register('httpkernel', 'Symfony\Component\HttpKernel\HttpKernel')
->addArgument(new Reference('dispatcher'))
->addArgument(new Reference('resolver'));
}
/**
* Creates an EventDispatcher for the HttpKernel. Factory method.
*
* @param Drupal\Core\DependencyInjection\ContainerBuilder $container
* The dependency injection container that contains the HTTP kernel.
*
* @return Symfony\Component\EventDispatcher\EventDispatcher
* An EventDispatcher with the default listeners attached to it.
*/
public static function getKernelEventDispatcher($container) {
$dispatcher = new EventDispatcher();
$matcher = new LegacyUrlMatcher();
$dispatcher->addSubscriber(new RouterListener($matcher));
$negotiation = new ContentNegotiation();
// @todo Make this extensible rather than just hard coding some.
// @todo Add a subscriber to handle other things, too, like our Ajax
// replacement system.
$dispatcher->addSubscriber(new ViewSubscriber($negotiation));
$dispatcher->addSubscriber(new AccessSubscriber());
$dispatcher->addSubscriber(new MaintenanceModeSubscriber());
$dispatcher->addSubscriber(new PathSubscriber());
$dispatcher->addSubscriber(new LegacyRequestSubscriber());
$dispatcher->addSubscriber(new LegacyControllerSubscriber());
$dispatcher->addSubscriber(new FinishResponseSubscriber());
$dispatcher->addSubscriber(new RequestCloseSubscriber());
// Some other form of error occured that wasn't handled by another kernel
// listener. That could mean that it's a method/mime-type/error combination
// that is not accounted for, or some other type of error. Either way, treat
// it as a server-level error and return an HTTP 500. By default, this will
// be an HTML-type response because that's a decent best guess if we don't
// know otherwise.
$exceptionController = new ExceptionController($negotiation);
$exceptionController->setContainer($container);
$dispatcher->addSubscriber(new ExceptionListener(array($exceptionController, 'execute')));
return $dispatcher;
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace Drupal\Core;
use Drupal\Core\DependencyInjection\Compiler\RegisterKernelListenersPass;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
class DrupalBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
// An interface language always needs to be available for t() and other
// functions. This default is overridden by drupal_language_initialize()
// during language negotiation.
$container->register(LANGUAGE_TYPE_INTERFACE, 'Drupal\\Core\\Language\\Language');
// Register the default language content.
$container->register(LANGUAGE_TYPE_CONTENT, 'Drupal\\Core\\Language\\Language');
$definitions = array(
'dispatcher' => array(
'class' => 'Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher',
'references' => array(
'service_container',
),
),
'resolver' => array(
'class' => 'Symfony\Component\HttpKernel\Controller\ControllerResolver',
),
'http_kernel' => array(
'class' => 'Symfony\Component\HttpKernel\HttpKernel',
'references' => array(
'dispatcher', 'resolver',
)
),
'matcher' => array(
'class' => 'Drupal\Core\LegacyUrlMatcher',
),
'router_listener' => array(
'class' => 'Drupal\Core\EventSubscriber\RouterListener',
'references' => array('matcher'),
'tags' => array('kernel.event_subscriber')
),
'content_negotiation' => array(
'class' => 'Drupal\Core\ContentNegotiation',
),
'view_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\ViewSubscriber',
'references' => array('content_negotiation'),
'tags' => array('kernel.event_subscriber')
),
'access_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\AccessSubscriber',
'tags' => array('kernel.event_subscriber')
),
'maintenance_mode_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\MaintenanceModeSubscriber',
'tags' => array('kernel.event_subscriber')
),
'path_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\PathSubscriber',
'tags' => array('kernel.event_subscriber')
),
'legacy_request_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\LegacyRequestSubscriber',
'tags' => array('kernel.event_subscriber')
),
'legacy_controller_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\LegacyControllerSubscriber',
'tags' => array('kernel.event_subscriber')
),
'finish_response_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\FinishResponseSubscriber',
'tags' => array('kernel.event_subscriber')
),
'request_close_subscriber' => array(
'class' => 'Drupal\Core\EventSubscriber\RequestCloseSubscriber',
'tags' => array('kernel.event_subscriber')
),
'exception_controller' => array(
'class' => 'Drupal\Core\ExceptionController',
'references' => array('content_negotiation'),
'methods' => array('setContainer' => array('service_container'))
),
'exception_listener' => array(
'class' => 'Symfony\Component\HttpKernel\EventListener\ExceptionListener',
'references' => array('exception_controller'),
'tags' => array('kernel.event_subscriber')
),
);
foreach ($definitions as $id => $info) {
$info += array(
'tags' => array(),
'references' => array(),
'methods' => array(),
);
$references = array();
foreach ($info['references'] as $ref_id) {
$references[] = new Reference($ref_id);
}
$definition = new Definition($info['class'], $references);
foreach($info['tags'] as $tag) {
$definition->addTag($tag);
}
foreach ($info['methods'] as $method => $args) {
$definition->addMethodCall($method, $args);
}
$container->setDefinition($id, $definition);
}
$container->addCompilerPass(new RegisterKernelListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* @file
* Definition of Drupal\Core\DrupalKernel.
*/
namespace Drupal\Core;
use Drupal\Core\DrupalBundle;
use Symfony\Component\HttpKernel\Kernel;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**
* The DrupalKernel class is the core of Drupal itself.
*/
class DrupalKernel extends Kernel {
public function registerBundles()
{
$bundles = array(
new DrupalBundle(),
);
$modules = array_keys(system_list('module_enabled'));
foreach ($modules as $module) {
$class = "\Drupal\{$module}\{$module}Bundle";
if (class_exists($class)) {
$bundles[] = new $class();
}
}
return $bundles;
}
/**
* Initializes the service container.
*/
protected function initializeContainer()
{
$this->container = $this->buildContainer();
$this->container->set('kernel', $this);
drupal_container($this->container);
}
/**
* Builds the service container.
*
* @return ContainerBuilder The compiled service container
*/
protected function buildContainer()
{
$container = $this->getContainerBuilder();
foreach ($this->bundles as $bundle) {
$bundle->build($container);
}
$container->compile();
return $container;
}
/**
* Gets a new ContainerBuilder instance used to build the service container.
*
* @return ContainerBuilder
*/
protected function getContainerBuilder()
{
return new ContainerBuilder(new ParameterBag($this->getKernelParameters()));
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
// We have to define this method because it's not defined in the base class,
// but the LoaderInterface class is part of the config component, which we
// are not using, so this is badness :-/ The alternative is to not extend
// the base Kernel class and just implement the KernelInterface.
}
}

View File

@ -107,7 +107,7 @@ class ExceptionController extends ContainerAware {
drupal_static_reset('menu_set_active_trail');
menu_reset_static_cache();
$response = $this->container->get('httpkernel')->handle($subrequest, HttpKernel::SUB_REQUEST);
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernel::SUB_REQUEST);
$response->setStatusCode(403, 'Access denied');
}
else {
@ -172,7 +172,7 @@ class ExceptionController extends ContainerAware {
drupal_static_reset('menu_set_active_trail');
menu_reset_static_cache();
$response = $this->container->get('httpkernel')->handle($subrequest, HttpKernel::SUB_REQUEST);
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernel::SUB_REQUEST);
$response->setStatusCode(404, 'Not Found');
}
else {

View File

@ -11,6 +11,7 @@
* See COPYRIGHT.txt and LICENSE.txt files in the "core" directory.
*/
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
/**
@ -20,6 +21,7 @@ define('DRUPAL_ROOT', getcwd());
// Bootstrap the lowest level of what we need.
require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
// Create a request object from the HTTPFoundation.
$request = Request::createFromGlobals();
@ -29,6 +31,9 @@ $request = Request::createFromGlobals();
// container at some point.
request($request);
$kernel = new DrupalKernel('prod', FALSE);
$kernel->boot();
// Bootstrap all of Drupal's subsystems, but do not initialize anything that
// depends on the fully resolved Drupal path, because path resolution happens
// during the REQUEST event of the kernel.
@ -36,6 +41,6 @@ request($request);
// @see Drupal\Core\EventSubscriber\LegacyRequestSubscriber;
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
$kernel = drupal_container()->get('httpkernel');
$response = $kernel->handle($request)->prepare($request)->send();
$kernel->terminate($request, $response);