diff --git a/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php b/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php index 4c32cd8..b210a92 100644 --- a/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php +++ b/core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php @@ -52,6 +52,52 @@ public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE */ public function set($id, $service, $scope = self::SCOPE_CONTAINER) { SymfonyContainer::set($id, $service, $scope); + + if ($this->hasDefinition($id) && ($definition = $this->getDefinition($id)) && $definition->isSynchronized()) { + $this->synchronize($id); + } + } + + /** + * Synchronizes a service change. + * + * This method is a copy of the ContainerBuilder of symfony. + * + * This method updates all services that depend on the given + * service by calling all methods referencing it. + * + * @param string $id A service id + */ + private function synchronize($id) { + foreach ($this->getDefinitions() as $definitionId => $definition) { + // only check initialized services + if (!$this->initialized($definitionId)) { + continue; + } + + foreach ($definition->getMethodCalls() as $call) { + foreach ($call[1] as $argument) { + if ($argument instanceof Reference && $id == (string) $argument) { + $this->callMethod($this->get($definitionId), $call); + } + } + } + } + } + + /** + * A 1to1 copy of parent::callMethod. + */ + protected function callMethod($service, $call) { + $services = self::getServiceConditionals($call[1]); + + foreach ($services as $s) { + if (!$this->has($s)) { + return; + } + } + + call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1]))); } /** diff --git a/core/modules/system/src/Tests/Theme/RegistryTest.php b/core/modules/system/src/Tests/Theme/RegistryTest.php index b2bfd3e..46587b2 100644 --- a/core/modules/system/src/Tests/Theme/RegistryTest.php +++ b/core/modules/system/src/Tests/Theme/RegistryTest.php @@ -37,7 +37,6 @@ public static function getInfo() { function testRaceCondition() { // The theme registry is not marked as persistable in case we don't have a // proper request. - \Drupal::getContainer()->enterScope('request'); \Drupal::request()->setMethod('GET'); $cid = 'test_theme_registry'; diff --git a/core/tests/Drupal/Tests/Core/DependencyInjection/ContainerBuilderTest.php b/core/tests/Drupal/Tests/Core/DependencyInjection/ContainerBuilderTest.php index fcc898f..7baf589 100644 --- a/core/tests/Drupal/Tests/Core/DependencyInjection/ContainerBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/DependencyInjection/ContainerBuilderTest.php @@ -41,6 +41,9 @@ public function testSetOnSynchronizedService() { $container->register('bar', 'BarClass') ->addMethodCall('setBaz', array(new Reference('baz'))); + // Ensure that we can set services on a compiled container. + $container->compile(); + $container->set('baz', $baz = new \BazClass()); $this->assertSame($baz, $container->get('bar')->getBaz());