summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2017-10-31 14:21:17 +0000
committerNathaniel Catchpole2017-10-31 14:21:17 +0000
commit391b71037b9f1a50cbaed4ded28a5bb458b80d88 (patch)
tree22ea4b0fedf56b859667de79e248897bdc90fcc0
parentd743db4f9432561d21c59a260fc584e1d2ab85d5 (diff)
Issue #2913912 by alexpott, phenaproxima: URL generator may have a stale route provider during module installation
-rw-r--r--core/lib/Drupal/Core/Extension/ModuleInstaller.php15
-rw-r--r--core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.info.yml6
-rw-r--r--core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.services.yml5
-rw-r--r--core/modules/system/tests/modules/lazy_route_provider_install_test/src/PluginManager.php39
-rw-r--r--core/modules/system/tests/modules/router_test_directory/router_test.install17
-rw-r--r--core/tests/Drupal/FunctionalTests/Routing/LazyRouteProviderInstallTest.php28
6 files changed, 106 insertions, 4 deletions
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index 10fabd4..5374bd3 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -194,6 +194,17 @@ class ModuleInstaller implements ModuleInstallerInterface {
// Update the kernel to include it.
$this->updateKernel($module_filenames);
+ // Replace the route provider service with a version that will rebuild
+ // if routes used during installation. This ensures that a module's
+ // routes are available during installation. This has to occur before
+ // any services that depend on the it are instantiated otherwise those
+ // services will have the old route provider injected. Note that, since
+ // the container is rebuilt by updating the kernel, the route provider
+ // service is the regular one even though we are in a loop and might
+ // have replaced it before.
+ \Drupal::getContainer()->set('router.route_provider.old', \Drupal::service('router.route_provider'));
+ \Drupal::getContainer()->set('router.route_provider', \Drupal::service('router.route_provider.lazy_builder'));
+
// Allow modules to react prior to the installation of a module.
$this->moduleHandler->invokeAll('module_preinstall', [$module]);
@@ -283,10 +294,6 @@ class ModuleInstaller implements ModuleInstallerInterface {
// @see https://www.drupal.org/node/2208429
\Drupal::service('theme_handler')->refreshInfo();
- // In order to make uninstalling transactional if anything uses routes.
- \Drupal::getContainer()->set('router.route_provider.old', \Drupal::service('router.route_provider'));
- \Drupal::getContainer()->set('router.route_provider', \Drupal::service('router.route_provider.lazy_builder'));
-
// Allow the module to perform install tasks.
$this->moduleHandler->invoke($module, 'install');
diff --git a/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.info.yml b/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.info.yml
new file mode 100644
index 0000000..e7e55e5
--- /dev/null
+++ b/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.info.yml
@@ -0,0 +1,6 @@
+name: 'Lazy route provider install test'
+description: 'Helps test a bug triggered by the url_generator maintaining a stale route provider.'
+type: module
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.services.yml b/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.services.yml
new file mode 100644
index 0000000..2de99d3
--- /dev/null
+++ b/core/modules/system/tests/modules/lazy_route_provider_install_test/lazy_route_provider_install_test.services.yml
@@ -0,0 +1,5 @@
+services:
+ plugin.manager.lazy_route_provider_install_test:
+ class: '\Drupal\lazy_route_provider_install_test\PluginManager'
+ parent: default_plugin_manager
+ arguments: ['@url_generator']
diff --git a/core/modules/system/tests/modules/lazy_route_provider_install_test/src/PluginManager.php b/core/modules/system/tests/modules/lazy_route_provider_install_test/src/PluginManager.php
new file mode 100644
index 0000000..cac59a7
--- /dev/null
+++ b/core/modules/system/tests/modules/lazy_route_provider_install_test/src/PluginManager.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\lazy_route_provider_install_test;
+
+use Drupal\Component\Annotation\PluginID;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Url;
+
+class PluginManager extends DefaultPluginManager {
+
+ /**
+ * PluginManager constructor.
+ *
+ * This plugin manager depends on the URL generator to ensure that this
+ * service is instantiated during module installation when the plugin caches
+ * are cleared.
+ *
+ * @param \Traversable $namespaces
+ * An object that implements \Traversable which contains the root paths
+ * keyed by the corresponding namespace to look for plugin implementations.
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+ * A cache backend.
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
+ * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
+ * The URL generator.
+ */
+ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, UrlGeneratorInterface $url_generator) {
+ // Generate a URL during construction to prove that URL generation works. If
+ // the route was missing an exception would be thrown. This also forces the
+ // route provider to be initialized very early during a module install.
+ \Drupal::state()->set(__CLASS__, Url::fromRoute('system.admin')->toString());
+ parent::__construct('Plugin/LazyRouteProviderInstallTest', $namespaces, $module_handler, NULL, PluginID::class);
+ }
+
+}
diff --git a/core/modules/system/tests/modules/router_test_directory/router_test.install b/core/modules/system/tests/modules/router_test_directory/router_test.install
new file mode 100644
index 0000000..7c718fa
--- /dev/null
+++ b/core/modules/system/tests/modules/router_test_directory/router_test.install
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the router_test module.
+ */
+
+use Drupal\Core\Url;
+
+/**
+ * Implements hook_install().
+ */
+function router_test_install() {
+ // Ensure a URL can be generated for routes provided by the module during
+ // installation.
+ \Drupal::state()->set(__FUNCTION__, Url::fromRoute('router_test.1')->toString());
+}
diff --git a/core/tests/Drupal/FunctionalTests/Routing/LazyRouteProviderInstallTest.php b/core/tests/Drupal/FunctionalTests/Routing/LazyRouteProviderInstallTest.php
new file mode 100644
index 0000000..bc01dc2
--- /dev/null
+++ b/core/tests/Drupal/FunctionalTests/Routing/LazyRouteProviderInstallTest.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\FunctionalTests\Routing;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * @group routing
+ */
+class LazyRouteProviderInstallTest extends BrowserTestBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected static $modules = ['lazy_route_provider_install_test'];
+
+ /**
+ * Tests that the lazy route provider is used during a module install.
+ */
+ public function testInstallation() {
+ $this->container->get('module_installer')->install(['router_test']);
+ // Note that on DrupalCI the test site is installed in a sub directory so
+ // we cannot use ::assertEquals().
+ $this->assertStringEndsWith('/admin', \Drupal::state()->get('Drupal\lazy_route_provider_install_test\PluginManager'));
+ $this->assertStringEndsWith('/router_test/test1', \Drupal::state()->get('router_test_install'));
+ }
+
+}