Commit 22fbcd41 authored by alexpott's avatar alexpott

Issue #2497243 by Fabianx, znerol, fgm, Wim Leers, darol100, jhedstrom,...

Issue #2497243 by Fabianx, znerol, fgm, Wim Leers, darol100, jhedstrom, hussainweb, pfrenssen, neclimdul, jibran, Nitesh Sethia, dawehner, chx, catch, benjy, Aki Tendo: Replace Symfony container with a Drupal one, stored in cache
parent 8cf5b80c
This diff is collapsed.
<?php
/**
* @file
* Contains \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper.
*/
namespace Drupal\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* PhpArrayDumper dumps a service container as a PHP array.
*
* The format of this dumper is a human-readable serialized PHP array, which is
* very similar to the YAML based format, but based on PHP arrays instead of
* YAML strings.
*
* It is human-readable, for a machine-optimized version based on this one see
* \Drupal\Component\DependencyInjection\Dumper\OptimizedPhpArrayDumper.
*
* @see \Drupal\Component\DependencyInjection\PhpArrayContainer
*/
class PhpArrayDumper extends OptimizedPhpArrayDumper {
/**
* {@inheritdoc}
*/
public function getArray() {
$this->serialize = FALSE;
return parent::getArray();
}
/**
* {@inheritdoc}
*/
protected function dumpCollection($collection, &$resolve = FALSE) {
$code = array();
foreach ($collection as $key => $value) {
if (is_array($value)) {
$code[$key] = $this->dumpCollection($value);
}
else {
$code[$key] = $this->dumpValue($value);
}
}
return $code;
}
/**
* {@inheritdoc}
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
if ($invalid_behavior !== ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return '@?' . $id;
}
return '@' . $id;
}
/**
* {@inheritdoc}
*/
protected function getParameterCall($name) {
return '%' . $name . '%';
}
/**
* {@inheritdoc}
*/
protected function supportsMachineFormat() {
return FALSE;
}
}
{
"name": "drupal/core-dependency-injection",
"description": "Dependency Injection container optimized for Drupal's needs.",
"keywords": ["drupal", "dependency injection"],
"type": "library",
"homepage": "https://www.drupal.org/project/drupal",
"license": "GPL-2.0+",
"support": {
"issues": "https://www.drupal.org/project/issues/drupal",
"irc": "irc://irc.freenode.net/drupal-contribute",
"source": "https://www.drupal.org/project/drupal/git-instructions"
},
"autoload": {
"psr-4": {
"Drupal\\Component\\DependencyInjection\\": ""
}
}
}
...@@ -7,17 +7,18 @@ ...@@ -7,17 +7,18 @@
namespace Drupal\Core\DependencyInjection; namespace Drupal\Core\DependencyInjection;
use Symfony\Component\DependencyInjection\Container as SymfonyContainer; use Drupal\Component\DependencyInjection\Container as DrupalContainer;
use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Extends the symfony container to set the service ID on the created object. * Extends the Drupal container to set the service ID on the created object.
*/ */
class Container extends SymfonyContainer { class Container extends DrupalContainer {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function set($id, $service, $scope = SymfonyContainer::SCOPE_CONTAINER) { public function set($id, $service, $scope = ContainerInterface::SCOPE_CONTAINER) {
parent::set($id, $service, $scope); parent::set($id, $service, $scope);
// Ensure that the _serviceId property is set on synthetic services as well. // Ensure that the _serviceId property is set on synthetic services as well.
......
This diff is collapsed.
...@@ -58,6 +58,16 @@ public function getServiceProviders($origin); ...@@ -58,6 +58,16 @@ public function getServiceProviders($origin);
*/ */
public function getContainer(); public function getContainer();
/**
* Returns the cached container definition - if any.
*
* This also allows inspecting a built container for debugging purposes.
*
* @return array|NULL
* The cached container definition or NULL if not found in cache.
*/
public function getCachedContainerDefinition();
/** /**
* Set the current site path. * Set the current site path.
* *
......
...@@ -55,13 +55,11 @@ protected function prepareConfigDirectories() { ...@@ -55,13 +55,11 @@ protected function prepareConfigDirectories() {
* A request object to use in booting the kernel. * A request object to use in booting the kernel.
* @param array $modules_enabled * @param array $modules_enabled
* A list of modules to enable on the kernel. * A list of modules to enable on the kernel.
* @param bool $read_only
* Build the kernel in a read only state.
* *
* @return \Drupal\Core\DrupalKernel * @return \Drupal\Core\DrupalKernel
* New kernel for testing. * New kernel for testing.
*/ */
protected function getTestKernel(Request $request, array $modules_enabled = NULL, $read_only = FALSE) { protected function getTestKernel(Request $request, array $modules_enabled = NULL) {
// Manually create kernel to avoid replacing settings. // Manually create kernel to avoid replacing settings.
$class_loader = require DRUPAL_ROOT . '/autoload.php'; $class_loader = require DRUPAL_ROOT . '/autoload.php';
$kernel = DrupalKernel::createFromRequest($request, $class_loader, 'testing'); $kernel = DrupalKernel::createFromRequest($request, $class_loader, 'testing');
...@@ -72,11 +70,6 @@ protected function getTestKernel(Request $request, array $modules_enabled = NULL ...@@ -72,11 +70,6 @@ protected function getTestKernel(Request $request, array $modules_enabled = NULL
} }
$kernel->boot(); $kernel->boot();
if ($read_only) {
$php_storage = Settings::get('php_storage');
$php_storage['service_container']['class'] = 'Drupal\Component\PhpStorage\FileReadOnlyStorage';
$this->settingsSet('php_storage', $php_storage);
}
return $kernel; return $kernel;
} }
...@@ -98,24 +91,19 @@ public function testCompileDIC() { ...@@ -98,24 +91,19 @@ public function testCompileDIC() {
$kernel = $this->getTestKernel($request); $kernel = $this->getTestKernel($request);
$container = $kernel->getContainer(); $container = $kernel->getContainer();
$refClass = new \ReflectionClass($container); $refClass = new \ReflectionClass($container);
$is_compiled_container = $is_compiled_container = !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$refClass->getParentClass()->getName() == 'Drupal\Core\DependencyInjection\Container' &&
!$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$this->assertTrue($is_compiled_container); $this->assertTrue($is_compiled_container);
// Verify that the list of modules is the same for the initial and the // Verify that the list of modules is the same for the initial and the
// compiled container. // compiled container.
$module_list = array_keys($container->get('module_handler')->getModuleList()); $module_list = array_keys($container->get('module_handler')->getModuleList());
$this->assertEqual(array_values($modules_enabled), $module_list); $this->assertEqual(array_values($modules_enabled), $module_list);
// Now use the read-only storage implementation, simulating a "production" // Get the container another time, simulating a "production" environment.
// environment. $container = $this->getTestKernel($request, NULL)
$container = $this->getTestKernel($request, NULL, TRUE)
->getContainer(); ->getContainer();
$refClass = new \ReflectionClass($container); $refClass = new \ReflectionClass($container);
$is_compiled_container = $is_compiled_container = !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$refClass->getParentClass()->getName() == 'Drupal\Core\DependencyInjection\Container' &&
!$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$this->assertTrue($is_compiled_container); $this->assertTrue($is_compiled_container);
// Verify that the list of modules is the same for the initial and the // Verify that the list of modules is the same for the initial and the
...@@ -137,16 +125,16 @@ public function testCompileDIC() { ...@@ -137,16 +125,16 @@ public function testCompileDIC() {
// Add another module so that we can test that the new module's bundle is // Add another module so that we can test that the new module's bundle is
// registered to the new container. // registered to the new container.
$modules_enabled['service_provider_test'] = 'service_provider_test'; $modules_enabled['service_provider_test'] = 'service_provider_test';
$this->getTestKernel($request, $modules_enabled, TRUE); $this->getTestKernel($request, $modules_enabled);
// Instantiate it a second time and we should still get a ContainerBuilder // Instantiate it a second time and we should not get a ContainerBuilder
// class because we are using the read-only PHP storage. // class because we are loading the container definition from cache.
$kernel = $this->getTestKernel($request, $modules_enabled, TRUE); $kernel = $this->getTestKernel($request, $modules_enabled);
$container = $kernel->getContainer(); $container = $kernel->getContainer();
$refClass = new \ReflectionClass($container); $refClass = new \ReflectionClass($container);
$is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder'); $is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
$this->assertTrue($is_container_builder, 'Container is a builder'); $this->assertFalse($is_container_builder, 'Container is not a builder');
// Assert that the new module's bundle was registered to the new container. // Assert that the new module's bundle was registered to the new container.
$this->assertTrue($container->has('service_provider_test_class'), 'Container has test service'); $this->assertTrue($container->has('service_provider_test_class'), 'Container has test service');
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
namespace Drupal\system\Tests\ServiceProvider; namespace Drupal\system\Tests\ServiceProvider;
use Drupal\simpletest\WebTestBase; use Drupal\simpletest\KernelTestBase;
/** /**
* Tests service provider registration to the DIC. * Tests service provider registration to the DIC.
* *
* @group ServiceProvider * @group ServiceProvider
*/ */
class ServiceProviderTest extends WebTestBase { class ServiceProviderTest extends KernelTestBase {
/** /**
* Modules to enable. * Modules to enable.
...@@ -27,13 +27,9 @@ class ServiceProviderTest extends WebTestBase { ...@@ -27,13 +27,9 @@ class ServiceProviderTest extends WebTestBase {
* Tests that services provided by module service providers get registered to the DIC. * Tests that services provided by module service providers get registered to the DIC.
*/ */
function testServiceProviderRegistration() { function testServiceProviderRegistration() {
$this->assertTrue(\Drupal::getContainer()->getDefinition('file.usage')->getClass() == 'Drupal\\service_provider_test\\TestFileUsage', 'Class has been changed'); $definition = $this->container->getDefinition('file.usage');
$this->assertTrue($definition->getClass() == 'Drupal\\service_provider_test\\TestFileUsage', 'Class has been changed');
$this->assertTrue(\Drupal::hasService('service_provider_test_class'), 'The service_provider_test_class service has been registered to the DIC'); $this->assertTrue(\Drupal::hasService('service_provider_test_class'), 'The service_provider_test_class service has been registered to the DIC');
// The event subscriber method in the test class calls drupal_set_message with
// a message saying it has fired. This will fire on every page request so it
// should show up on the front page.
$this->drupalGet('');
$this->assertText(t('The service_provider_test event subscriber fired!'), 'The service_provider_test event subscriber fired');
} }
/** /**
......
<?php
/**
* @file
* Contains \Drupal\system\Tests\ServiceProvider\ServiceProviderWebTest.
*/
namespace Drupal\system\Tests\ServiceProvider;
use Drupal\simpletest\WebTestBase;
/**
* Tests service provider registration to the DIC.
*
* @group ServiceProvider
*/
class ServiceProviderWebTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file', 'service_provider_test');
/**
* Tests that module service providers get registered to the DIC.
*
* Also tests that services provided by module service providers get
* registered to the DIC.
*/
public function testServiceProviderRegistrationIntegration() {
$this->assertTrue(\Drupal::hasService('service_provider_test_class'), 'The service_provider_test_class service has been registered to the DIC');
// The event subscriber method in the test class calls drupal_set_message()
// with a message saying it has fired. This will fire on every page request
// so it should show up on the front page.
$this->drupalGet('');
$this->assertText(t('The service_provider_test event subscriber fired!'), 'The service_provider_test event subscriber fired');
}
}
...@@ -170,14 +170,7 @@ public function testErrorContainer() { ...@@ -170,14 +170,7 @@ public function testErrorContainer() {
'required' => TRUE, 'required' => TRUE,
]; ];
$this->writeSettings($settings); $this->writeSettings($settings);
\Drupal::service('kernel')->invalidateContainer();
// Need to rebuild the container, so the dumped container can be tested
// and not the container builder.
\Drupal::service('kernel')->rebuildContainer();
// Ensure that we don't use the now broken generated container on the test
// process.
\Drupal::setContainer($this->container);
$this->expectedExceptionMessage = 'Argument 1 passed to Drupal\system\Tests\Bootstrap\ErrorContainer::Drupal\system\Tests\Bootstrap\{closur'; $this->expectedExceptionMessage = 'Argument 1 passed to Drupal\system\Tests\Bootstrap\ErrorContainer::Drupal\system\Tests\Bootstrap\{closur';
$this->drupalGet(''); $this->drupalGet('');
...@@ -196,14 +189,7 @@ public function testExceptionContainer() { ...@@ -196,14 +189,7 @@ public function testExceptionContainer() {
'required' => TRUE, 'required' => TRUE,
]; ];
$this->writeSettings($settings); $this->writeSettings($settings);
\Drupal::service('kernel')->invalidateContainer();
// Need to rebuild the container, so the dumped container can be tested
// and not the container builder.
\Drupal::service('kernel')->rebuildContainer();
// Ensure that we don't use the now broken generated container on the test
// process.
\Drupal::setContainer($this->container);
$this->expectedExceptionMessage = 'Thrown exception during Container::get'; $this->expectedExceptionMessage = 'Thrown exception during Container::get';
$this->drupalGet(''); $this->drupalGet('');
......
<?php
/**
* @file
* Contains \Drupal\Tests\Component\DependencyInjection\Dumper\PhpArrayDumperTest.
*/
namespace Drupal\Tests\Component\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @coversDefaultClass \Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper
* @group DependencyInjection
*/
class PhpArrayDumperTest extends OptimizedPhpArrayDumperTest {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->machineFormat = FALSE;
$this->dumperClass = '\Drupal\Component\DependencyInjection\Dumper\PhpArrayDumper';
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function serializeDefinition(array $service_definition) {
return $service_definition;
}
/**
* {@inheritdoc}
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
if ($invalid_behavior !== ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return sprintf('@?%s', $id);
}
return sprintf('@%s', $id);
}
/**
* {@inheritdoc}
*/
protected function getParameterCall($name) {
return '%' . $name . '%';
}
/**
* {@inheritdoc}
*/
protected function getCollection($collection, $resolve = TRUE) {
return $collection;
}
}
<?php
/**
* @file
* Contains a test function for container 'file' include testing.
*/
/**
* Test function for container testing.
*
* @return string
* A string just for testing.
*/
function container_test_file_service_test_service_function() {
return 'Hello Container';
}
<?php
/**
* @file
* Contains \Drupal\Tests\Component\DependencyInjection\PhpArrayContainerTest.
*/
namespace Drupal\Tests\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* @coversDefaultClass \Drupal\Component\DependencyInjection\PhpArrayContainer
* @group DependencyInjection
*/
class PhpArrayContainerTest extends ContainerTest {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->machineFormat = FALSE;
$this->containerClass = '\Drupal\Component\DependencyInjection\PhpArrayContainer';
$this->containerDefinition = $this->getMockContainerDefinition();
$this->container = new $this->containerClass($this->containerDefinition);
}
/**
* Helper function to return a service definition.
*/
protected function getServiceCall($id, $invalid_behavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
if ($invalid_behavior !== ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) {
return sprintf('@?%s', $id);
}
return sprintf('@%s', $id);
}
/**
* Helper function to return a service definition.
*/
protected function getParameterCall($name) {
return '%' . $name . '%';
}
/**
* Helper function to return a machine-optimized '@notation'.
*/
protected function getCollection($collection, $resolve = TRUE) {
return $collection;
}
}
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