diff --git a/core/lib/Drupal/Core/Update/UpdateServiceProvider.php b/core/lib/Drupal/Core/Update/UpdateServiceProvider.php index 45ed20c168..0f50b090d7 100644 --- a/core/lib/Drupal/Core/Update/UpdateServiceProvider.php +++ b/core/lib/Drupal/Core/Update/UpdateServiceProvider.php @@ -5,6 +5,7 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceModifierInterface; use Drupal\Core\DependencyInjection\ServiceProviderInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; @@ -51,9 +52,12 @@ protected function removeUndefinedServices(ContainerBuilder $container) { $definitions = $container->getDefinitions(); foreach ($definitions as $key => $definition) { foreach ($definition->getArguments() as $argument) { - if ($argument instanceof Reference && !$container->has((string) $argument)) { - // If the container does not have the argument, remove the service. - $container->removeDefinition($key); + if ($argument instanceof Reference) { + if (!$container->has((string) $argument) && $argument->getInvalidBehavior() === ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { + // If the container does not have the argument but would throw an + // exception, remove the service. + $container->removeDefinition($key); + } } } } diff --git a/core/modules/system/src/Tests/Update/UpdatePathNewDependencyTest.php b/core/modules/system/src/Tests/Update/UpdatePathNewDependencyTest.php deleted file mode 100644 index 5408141c77..0000000000 --- a/core/modules/system/src/Tests/Update/UpdatePathNewDependencyTest.php +++ /dev/null @@ -1,48 +0,0 @@ -databaseDumpFiles = [ - __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz', - ]; - } - - /** - * Test that a module can add services that depend on new modules. - */ - public function testUpdateNewDependency() { - // The new_dependency_test before the update is just an empty info.yml file. - // The code of the new_dependency_test module is after the update and - // contains the dependency on the new_dependency_test_with_service module. - $extension_config = \Drupal::configFactory()->getEditable('core.extension'); - $extension_config - ->set('module.new_dependency_test', 0) - ->set('module', module_config_sort($extension_config->get('module'))) - ->save(TRUE); - drupal_set_installed_schema_version('new_dependency_test', \Drupal::CORE_MINIMUM_SCHEMA_VERSION); - - // Running the updates enables the dependency. - $this->runUpdates(); - - $this->assertTrue(array_key_exists('new_dependency_test', \Drupal::config('core.extension')->get('module'))); - $this->assertTrue(array_key_exists('new_dependency_test_with_service', \Drupal::config('core.extension')->get('module'))); - - // Rebuild the container and test that the new service works. - $this->rebuildContainer(); - $this->assertEqual('Hello', \Drupal::service('new_dependency_test.dependent')->greet()); - $this->assertEqual('Hello World', \Drupal::service('new_dependency_test.decorated')->greet()); - - } - -} diff --git a/core/modules/system/tests/modules/new_dependency_test/new_dependency_test.services.yml b/core/modules/system/tests/modules/new_dependency_test/new_dependency_test.services.yml index 56d2dfef9c..29a6de5b5f 100644 --- a/core/modules/system/tests/modules/new_dependency_test/new_dependency_test.services.yml +++ b/core/modules/system/tests/modules/new_dependency_test/new_dependency_test.services.yml @@ -5,5 +5,8 @@ services: new_dependency_test.decorated: class: Drupal\new_dependency_test\DecoratedDependentService arguments: ['@new_dependency_test.dependent'] + new_dependency_test.decorated_optional: + class: Drupal\new_dependency_test\DecoratedDependentService + arguments: ['@?new_dependency_test.dependent'] new_dependency_test.alias: alias: new_dependency_test.dependent diff --git a/core/modules/system/tests/modules/new_dependency_test/src/DependentService.php b/core/modules/system/tests/modules/new_dependency_test/src/DependentService.php index 22e1631a09..facf7de198 100644 --- a/core/modules/system/tests/modules/new_dependency_test/src/DependentService.php +++ b/core/modules/system/tests/modules/new_dependency_test/src/DependentService.php @@ -19,10 +19,10 @@ class DependentService { /** * DependentService constructor. * - * @param \Drupal\new_dependency_test_with_service\NewService $service + * @param \Drupal\new_dependency_test_with_service\NewService|null $service * The service of the new module. */ - public function __construct(NewService $service) { + public function __construct(NewService $service = null) { $this->service = $service; } @@ -33,7 +33,10 @@ public function __construct(NewService $service) { * The greeting. */ public function greet() { - return $this->service->greet(); + if (isset($this->service)) { + return $this->service->greet(); + } + return 'Sorry, no service.'; } } diff --git a/core/modules/system/tests/src/Functional/Update/UpdatePathNewDependencyTest.php b/core/modules/system/tests/src/Functional/Update/UpdatePathNewDependencyTest.php new file mode 100644 index 0000000000..e5d38ed595 --- /dev/null +++ b/core/modules/system/tests/src/Functional/Update/UpdatePathNewDependencyTest.php @@ -0,0 +1,63 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz', + ]; + } + + /** + * Test that a module can add services that depend on new modules. + */ + public function testUpdateNewDependency() { + // The new_dependency_test before the update is just an empty info.yml file. + // The code of the new_dependency_test module is after the update and + // contains the dependency on the new_dependency_test_with_service module. + $extension_config = $this->container->get('config.factory')->getEditable('core.extension'); + $extension_config + ->set('module.new_dependency_test', 0) + ->set('module', module_config_sort($extension_config->get('module'))) + ->save(TRUE); + drupal_set_installed_schema_version('new_dependency_test', \Drupal::CORE_MINIMUM_SCHEMA_VERSION); + + // Rebuild the container and test that the service with the optional unmet + // dependency is still available while the ones that fail are not. + $this->rebuildContainer(); + $this->container; + + $this->assertFalse($this->container->has('new_dependency_test_with_service.service')); + $this->assertFalse($this->container->has('new_dependency_test.dependent')); + $this->assertFalse($this->container->has('new_dependency_test.decorated')); + $this->assertFalse($this->container->has('new_dependency_test.alias')); + $this->assertEquals('Sorry, no service.', $this->container->get('new_dependency_test.decorated_optional')->greet()); + + + // Running the updates enables the dependency. + $this->runUpdates(); + + $this->assertTrue(array_key_exists('new_dependency_test', $this->container->get('config.factory')->get('core.extension')->get('module'))); + $this->assertTrue(array_key_exists('new_dependency_test_with_service', $this->container->get('config.factory')->get('core.extension')->get('module'))); + + // Rebuild the container and test that the new service works. + $this->rebuildContainer(); + $this->assertEquals('Hello', $this->container->get('new_dependency_test_with_service.service')->greet()); + $this->assertEquals('Hello', $this->container->get('new_dependency_test.dependent')->greet()); + $this->assertEquals('Hello', $this->container->get('new_dependency_test.alias')->greet()); + $this->assertEquals('Hello World', $this->container->get('new_dependency_test.decorated')->greet()); + $this->assertEquals('Hello World', $this->container->get('new_dependency_test.decorated_optional')->greet()); + + } + +}