Commit a3f5ca8a authored by catch's avatar catch
Browse files

Issue #2338747 by dawehner, chx: Move {router} out of system.install and create the table lazy

parent 252fee22
......@@ -7,6 +7,8 @@
namespace Drupal\Core\Routing;
use Drupal\Core\Database\Query\Query;
use Drupal\Core\Database\SchemaObjectExistsException;
use Drupal\Core\State\StateInterface;
use Symfony\Component\Routing\RouteCollection;
......@@ -14,6 +16,8 @@
/**
* Dumps Route information to a database table.
*
* @see \Drupal\Core\Routing\RouteProvider
*/
class MatcherDumper implements MatcherDumperInterface {
......@@ -97,7 +101,13 @@ public function dump(array $options = array()) {
try {
// We don't use truncate, because it is not guaranteed to be transaction
// safe.
$this->connection->delete($this->tableName)->execute();
try {
$this->connection->delete($this->tableName)
->execute();
}
catch (\Exception $e) {
$this->ensureTableExists();
}
// Split the routes into chunks to avoid big INSERT queries.
$route_chunks = array_chunk($this->routes->all(), 50, TRUE);
......@@ -162,4 +172,85 @@ public function getRoutes() {
return $this->routes;
}
/**
* Checks if the tree table exists and create it if not.
*
* @return bool
* TRUE if the table was created, FALSE otherwise.
*/
protected function ensureTableExists() {
try {
if (!$this->connection->schema()->tableExists($this->tableName)) {
$this->connection->schema()->createTable($this->tableName, $this->schemaDefinition());
return TRUE;
}
}
catch (SchemaObjectExistsException $e) {
// If another process has already created the config table, attempting to
// recreate it will throw an exception. In this case just catch the
// exception and do nothing.
return TRUE;
}
return FALSE;
}
/**
* Defines the schema for the router table.
*
* @return array
* The schema API definition for the SQL storage table.
*/
protected function schemaDefinition() {
$schema = [
'description' => 'Maps paths to various callbacks (access, page and title)',
'fields' => [
'name' => [
'description' => 'Primary Key: Machine name of this route',
'type' => 'varchar_ascii',
'length' => 255,
'not null' => TRUE,
'default' => '',
],
'path' => [
'description' => 'The path for this URI',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
],
'pattern_outline' => [
'description' => 'The pattern',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
],
'fit' => [
'description' => 'A numeric representation of how specific the path is.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
],
'route' => [
'description' => 'A serialized Route object',
'type' => 'blob',
'size' => 'big',
],
'number_parts' => [
'description' => 'Number of parts in this router path.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'small',
],
],
'indexes' => [
'pattern_outline_parts' => ['pattern_outline', 'number_parts'],
],
'primary key' => ['name'],
];
return $schema;
}
}
......@@ -210,7 +210,12 @@ public function preLoadRoutes($names) {
$routes = $cache->data;
}
else {
$result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN ( :names[] )', array(':names[]' => $routes_to_load));
try {
$result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN ( :names[] )', array(':names[]' => $routes_to_load));
}
catch (\Exception $e) {
$result = [];
}
$routes = $result->fetchAllKeyed();
$this->cache->set($cid, $routes, Cache::PERMANENT, ['routes']);
......@@ -336,10 +341,15 @@ protected function getRoutesByPath($path) {
// The >= check on number_parts allows us to match routes with optional
// trailing wildcard parts as long as the pattern matches, since we
// dump the route pattern without those optional parts.
$routes = $this->connection->query("SELECT name, route, fit FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN ( :patterns[] ) AND number_parts >= :count_parts", array(
':patterns[]' => $ancestors, ':count_parts' => count($parts),
))
->fetchAll(\PDO::FETCH_ASSOC);
try {
$routes = $this->connection->query("SELECT name, route, fit FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN ( :patterns[] ) AND number_parts >= :count_parts", array(
':patterns[]' => $ancestors, ':count_parts' => count($parts),
))
->fetchAll(\PDO::FETCH_ASSOC);
}
catch (\Exception $e) {
$routes = [];
}
// We sort by fit and name in PHP to avoid a SQL filesort.
usort($routes, array($this, 'routeProviderRouteCompare'));
......
......@@ -24,7 +24,6 @@ class BreakpointDiscoveryTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('router'));
\Drupal::service('theme_handler')->install(array('breakpoint_theme_test'));
}
......
......@@ -59,7 +59,6 @@ protected function setUp() {
$this->installConfig(array('system', 'filter', 'comment'));
// Comment rendering generates links, so build the router.
$this->installSchema('system', array('router'));
$this->container->get('router.builder')->rebuild();
// Set up a field, so that the entity that'll be referenced bubbles up a
......
......@@ -33,7 +33,6 @@ protected function setUp() {
$this->installEntitySchema('node');
$this->installEntitySchema('comment');
$this->installSchema('comment', ['comment_entity_statistics']);
$this->installSchema('system', ['router']);
$this->installConfig(['comment']);
// The entity.node.canonical route must exist when the RDF hook is called.
......
......@@ -30,7 +30,6 @@ class ConfigInstallTest extends KernelTestBase {
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['router']);
// Ensure the global variable being asserted by this test does not exist;
// a previous test executed in this request/process might have set it.
......
......@@ -41,7 +41,7 @@ class EditorImageDialogTest extends EntityUnitTestBase {
protected function setUp() {
parent::setUp();
$this->installEntitySchema('file');
$this->installSchema('system', ['router', 'key_value_expire']);
$this->installSchema('system', ['key_value_expire']);
$this->installSchema('node', array('node_access'));
$this->installSchema('file', array('file_usage'));
$this->installConfig(['node']);
......
......@@ -77,7 +77,6 @@ protected function setUp() {
->save();
// The label formatter rendering generates links, so build the router.
$this->installSchema('system', 'router');
$this->container->get('router.builder')->rebuild();
$this->createEntityReferenceField($this->entityType, $this->bundle, $this->fieldName, 'Field test', $this->entityType, 'default', array(), FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
......
......@@ -29,7 +29,7 @@ class FieldImportDeleteUninstallTest extends FieldUnitTestBase {
protected function setUp() {
parent::setUp();
// Module uninstall requires the router and users_data tables.
// Module uninstall requires users_data tables.
// @see drupal_flush_all_caches()
// @see user_modules_uninstalled()
$this->installSchema('user', array('users_data'));
......
......@@ -52,7 +52,7 @@ protected function setUp() {
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
$this->installSchema('system', ['router', 'sequences', 'key_value']);
$this->installSchema('system', ['sequences', 'key_value']);
// Set default storage backend and configure the theme system.
$this->installConfig(array('field', 'system'));
......
......@@ -58,7 +58,6 @@ protected function setUp() {
// Configure the theme system.
$this->installConfig(array('system', 'field'));
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('entity_test');
......
......@@ -58,7 +58,6 @@ protected function setUp() {
// Configure the theme system.
$this->installConfig(array('system', 'field'));
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('entity_test_rev');
......
......@@ -32,7 +32,6 @@ protected function setUp() {
parent::setUp();
$this->installConfig(['system', 'field']);
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('entity_test');
}
......
......@@ -41,7 +41,7 @@ class TextFormatElementFormTest extends KernelTestBase implements FormInterface
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installSchema('system', ['sequences', 'router']);
$this->installSchema('system', ['sequences']);
$this->installConfig(['filter', 'filter_test']);
// Filter tips link to the full-page.
\Drupal::service('router.builder')->rebuild();
......
......@@ -63,7 +63,6 @@ abstract class NormalizerTestBase extends KernelTestBase {
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('router'));
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
// If the concrete test sub-class installs the Node or Comment modules,
......
......@@ -24,15 +24,6 @@ class HelpEmptyPageTest extends KernelTestBase {
*/
public static $modules = ['system', 'help_test', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'router');
}
/**
* {@inheritdoc}
*/
......
......@@ -41,7 +41,6 @@ protected function setUp() {
$this->installEntitySchema('entity_test');
$this->installEntitySchema('configurable_language');
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
// In order to reflect the changes for a multilingual site in the container
......
......@@ -39,7 +39,6 @@ protected function setUp() {
$this->installEntitySchema('menu_link_content');
$this->installEntitySchema('user');
$this->installSchema('system', ['router']);
// Ensure that the weight of module_link_content is higher than system.
// @see menu_link_content_install()
......
......@@ -33,7 +33,6 @@ protected function setUp() {
parent::setUp();
$this->installEntitySchema('menu_link_content');
$this->installSchema('system', 'router');
}
/**
......
......@@ -27,7 +27,6 @@ class MigrateMenuLinkTest extends MigrateDrupal6TestBase {
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['router']);
$this->installEntitySchema('menu_link_content');
$this->executeMigrations(['menu', 'menu_links']);
}
......
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