Issue #2908886 by andypost, martin107, kim.pepper, daffie, aleevas, vacho, catch, longwave, alexpott, voleger, dww: Split off schema management out of schema.inc
parent
aea84a7cc9
commit
535fb843aa
|
@ -524,7 +524,7 @@ services:
|
|||
class: Drupal\Core\Extension\ModuleInstaller
|
||||
tags:
|
||||
- { name: service_collector, tag: 'module_install.uninstall_validator', call: addUninstallValidator }
|
||||
arguments: ['%app.root%', '@module_handler', '@kernel']
|
||||
arguments: ['%app.root%', '@module_handler', '@kernel', '@database']
|
||||
lazy: true
|
||||
extension.list.module:
|
||||
class: Drupal\Core\Extension\ModuleExtensionList
|
||||
|
|
|
@ -112,8 +112,15 @@ function drupal_set_installed_schema_version($module, $version) {
|
|||
*
|
||||
* @param string $module
|
||||
* The module for which the tables will be created.
|
||||
*
|
||||
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct
|
||||
* replacement is provided.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2970993
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::installSchema()
|
||||
*/
|
||||
function drupal_install_schema($module) {
|
||||
@trigger_error('drupal_install_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993', E_USER_DEPRECATED);
|
||||
$schema = drupal_get_module_schema($module);
|
||||
_drupal_schema_initialize($schema, $module, FALSE);
|
||||
|
||||
|
@ -127,8 +134,15 @@ function drupal_install_schema($module) {
|
|||
*
|
||||
* @param string $module
|
||||
* The module for which the tables will be removed.
|
||||
*
|
||||
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct
|
||||
* replacement is provided.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2970993
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::uninstallSchema()
|
||||
*/
|
||||
function drupal_uninstall_schema($module) {
|
||||
@trigger_error('drupal_uninstall_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993', E_USER_DEPRECATED);
|
||||
$tables = drupal_get_module_schema($module);
|
||||
_drupal_schema_initialize($tables, $module, FALSE);
|
||||
$schema = \Drupal::database()->schema();
|
||||
|
@ -151,8 +165,16 @@ function drupal_uninstall_schema($module) {
|
|||
* @param string $table
|
||||
* The name of the table. If not given, the module's complete schema
|
||||
* is returned.
|
||||
*
|
||||
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct
|
||||
* replacement is provided. Testing classes could use
|
||||
* \Drupal\TestTools\Extension\SchemaInspector for introspection.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2970993
|
||||
* @see \Drupal\TestTools\Extension\SchemaInspector::getTablesSpecification()
|
||||
*/
|
||||
function drupal_get_module_schema($module, $table = NULL) {
|
||||
@trigger_error('drupal_get_module_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. Testing classes could use \Drupal\TestTools\Extension\SchemaInspector for introspection. See https://www.drupal.org/node/2970993', E_USER_DEPRECATED);
|
||||
// Load the .install file to get hook_schema.
|
||||
module_load_install($module);
|
||||
$schema = \Drupal::moduleHandler()->invoke($module, 'schema');
|
||||
|
@ -181,8 +203,14 @@ function drupal_get_module_schema($module, $table = NULL) {
|
|||
* (optional) Whether to additionally remove 'description' keys of all tables
|
||||
* and fields to improve performance of serialize() and unserialize().
|
||||
* Defaults to TRUE.
|
||||
*
|
||||
* @deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct
|
||||
* replacement is provided.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2970993
|
||||
*/
|
||||
function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRUE) {
|
||||
@trigger_error('_drupal_schema_initialize() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993', E_USER_DEPRECATED);
|
||||
// Set the name and module key for all tables.
|
||||
foreach ($schema as $name => &$table) {
|
||||
if (empty($table['module'])) {
|
||||
|
|
|
@ -390,7 +390,9 @@ use Drupal\Core\Database\Query\SelectInterface;
|
|||
* ];
|
||||
* @endcode
|
||||
*
|
||||
* @see drupal_install_schema()
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::installSchema()
|
||||
* @see \Drupal\Core\Extension\ModuleInstaller::uninstallSchema()
|
||||
* @see \Drupal\TestTools\Extension\SchemaInspector::getTablesSpecification()
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Drupal\Core\Extension;
|
|||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\DrupalKernelInterface;
|
||||
use Drupal\Core\Entity\EntityStorageException;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
|
@ -44,6 +45,13 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The uninstall validators.
|
||||
*
|
||||
|
@ -60,14 +68,21 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
* The module handler.
|
||||
* @param \Drupal\Core\DrupalKernelInterface $kernel
|
||||
* The drupal kernel.
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The database connection.
|
||||
*
|
||||
* @see \Drupal\Core\DrupalKernel
|
||||
* @see \Drupal\Core\CoreServiceProvider
|
||||
*/
|
||||
public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel) {
|
||||
public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, Connection $connection = NULL) {
|
||||
$this->root = $root;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->kernel = $kernel;
|
||||
if (!$connection) {
|
||||
@trigger_error('The database connection must be passed to ' . __METHOD__ . '(). Creating ' . __CLASS__ . ' without it is deprecated in drupal:9.2.0 and will be required in drupal:10.0.0. See https://www.drupal.org/node/2970993', E_USER_DEPRECATED);
|
||||
$connection = \Drupal::service('database');
|
||||
}
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,7 +242,7 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
$this->moduleHandler->invokeAll('module_preinstall', [$module]);
|
||||
|
||||
// Now install the module's schema if necessary.
|
||||
drupal_install_schema($module);
|
||||
$this->installSchema($module);
|
||||
|
||||
// Clear plugin manager caches.
|
||||
\Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
|
||||
|
@ -468,7 +483,7 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
}
|
||||
|
||||
// Remove the schema.
|
||||
drupal_uninstall_schema($module);
|
||||
$this->uninstallSchema($module);
|
||||
|
||||
// Remove the module's entry from the config. Don't check schema when
|
||||
// uninstalling a module since we are only clearing a key.
|
||||
|
@ -585,6 +600,7 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
// dependencies.
|
||||
$container = $this->kernel->getContainer();
|
||||
$this->moduleHandler = $container->get('module_handler');
|
||||
$this->connection = $container->get('database');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,4 +622,38 @@ class ModuleInstaller implements ModuleInstallerInterface {
|
|||
return $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates all tables defined in a module's hook_schema().
|
||||
*
|
||||
* @param string $module
|
||||
* The module for which the tables will be created.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function installSchema(string $module): void {
|
||||
$tables = $this->moduleHandler->invoke($module, 'schema') ?? [];
|
||||
$schema = $this->connection->schema();
|
||||
foreach ($tables as $name => $table) {
|
||||
$schema->createTable($name, $table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all tables defined in a module's hook_schema().
|
||||
*
|
||||
* @param string $module
|
||||
* The module for which the tables will be removed.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function uninstallSchema(string $module): void {
|
||||
$tables = $this->moduleHandler->invoke($module, 'schema') ?? [];
|
||||
$schema = $this->connection->schema();
|
||||
foreach (array_keys($tables) as $table) {
|
||||
if ($schema->tableExists($table)) {
|
||||
$schema->dropTable($table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ function module_test_schema() {
|
|||
* Implements hook_install().
|
||||
*/
|
||||
function module_test_install() {
|
||||
$schema = drupal_get_module_schema('module_test', 'module_test');
|
||||
$schema = module_test_schema()['module_test'];
|
||||
Database::getConnection()->insert('module_test')
|
||||
->fields([
|
||||
'data' => $schema['fields']['data']['type'],
|
||||
|
|
|
@ -8,6 +8,7 @@ use Drupal\Core\Database\Database;
|
|||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Logger\RfcLogLevel;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\TestTools\Extension\SchemaInspector;
|
||||
|
||||
/**
|
||||
* Helper class for module test cases.
|
||||
|
@ -40,7 +41,7 @@ abstract class ModuleTestBase extends BrowserTestBase {
|
|||
* The name of the module.
|
||||
*/
|
||||
public function assertModuleTablesExist($module) {
|
||||
$tables = array_keys(drupal_get_module_schema($module));
|
||||
$tables = array_keys(SchemaInspector::getTablesSpecification(\Drupal::moduleHandler(), $module));
|
||||
$tables_exist = TRUE;
|
||||
$schema = Database::getConnection()->schema();
|
||||
foreach ($tables as $table) {
|
||||
|
@ -58,7 +59,7 @@ abstract class ModuleTestBase extends BrowserTestBase {
|
|||
* The name of the module.
|
||||
*/
|
||||
public function assertModuleTablesDoNotExist($module) {
|
||||
$tables = array_keys(drupal_get_module_schema($module));
|
||||
$tables = array_keys(SchemaInspector::getTablesSpecification(\Drupal::moduleHandler(), $module));
|
||||
$tables_exist = FALSE;
|
||||
$schema = Database::getConnection()->schema();
|
||||
foreach ($tables as $table) {
|
||||
|
|
|
@ -13,15 +13,14 @@ class InsertDefaultsTest extends DatabaseTestBase {
|
|||
|
||||
/**
|
||||
* Tests that we can run a query that uses default values for everything.
|
||||
*
|
||||
* @see \database_test_schema()
|
||||
*/
|
||||
public function testDefaultInsert() {
|
||||
$query = $this->connection->insert('test')->useDefaults(['job']);
|
||||
$id = $query->execute();
|
||||
|
||||
$schema = drupal_get_module_schema('database_test', 'test');
|
||||
|
||||
$job = $this->connection->query('SELECT [job] FROM {test} WHERE [id] = :id', [':id' => $id])->fetchField();
|
||||
$this->assertEqual($schema['fields']['job']['default'], $job, 'Default field value is set.');
|
||||
$this->assertSame('Undefined', $job, 'Default field value is set.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,17 +44,16 @@ class InsertDefaultsTest extends DatabaseTestBase {
|
|||
|
||||
/**
|
||||
* Tests that we can insert fields with values and defaults in the same query.
|
||||
*
|
||||
* @see \database_test_schema()
|
||||
*/
|
||||
public function testDefaultInsertWithFields() {
|
||||
$query = $this->connection->insert('test')
|
||||
->fields(['name' => 'Bob'])
|
||||
->useDefaults(['job']);
|
||||
$id = $query->execute();
|
||||
|
||||
$schema = drupal_get_module_schema('database_test', 'test');
|
||||
|
||||
$job = $this->connection->query('SELECT [job] FROM {test} WHERE [id] = :id', [':id' => $id])->fetchField();
|
||||
$this->assertEqual($schema['fields']['job']['default'], $job, 'Default field value is set.');
|
||||
$this->assertSame('Undefined', $job, 'Default field value is set.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\Extension;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests deprecated schema.inc functions.
|
||||
*
|
||||
* @group legacy
|
||||
* @group extension
|
||||
*/
|
||||
class SchemaDeprecationTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = ['system', 'dblog'];
|
||||
|
||||
/**
|
||||
* Tests deprecation of database schema API functions.
|
||||
*/
|
||||
public function testDeprecatedInstallSchema() {
|
||||
$this->expectDeprecation('drupal_install_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993');
|
||||
drupal_install_schema('dblog');
|
||||
$table = 'watchdog';
|
||||
$this->expectDeprecation('drupal_get_module_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. Testing classes could use \Drupal\TestTools\Extension\SchemaInspector for introspection. See https://www.drupal.org/node/2970993');
|
||||
$this->assertArrayHasKey($table, drupal_get_module_schema('dblog'));
|
||||
$this->assertTrue(\Drupal::database()->schema()->tableExists($table));
|
||||
$this->expectDeprecation('drupal_uninstall_schema() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993');
|
||||
drupal_uninstall_schema('dblog');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deprecation of _drupal_schema_initialize() function.
|
||||
*/
|
||||
public function testDeprecatedSchemaInitialize() {
|
||||
$module = 'dblog';
|
||||
$table = 'watchdog';
|
||||
$schema = [$table => []];
|
||||
$this->expectDeprecation('_drupal_schema_initialize() is deprecated in drupal:9.2.0 and is removed from drupal:10.0.0. No direct replacement is provided. See https://www.drupal.org/node/2970993');
|
||||
_drupal_schema_initialize($schema, $module, FALSE);
|
||||
$this->assertEquals($module, $schema[$table]['module']);
|
||||
$this->assertEquals($table, $schema[$table]['name']);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,7 @@ use Drupal\Tests\PhpUnitCompatibilityTrait;
|
|||
use Drupal\Tests\TestRequirementsTrait;
|
||||
use Drupal\Tests\Traits\PhpUnitWarnings;
|
||||
use Drupal\TestTools\Comparator\MarkupInterfaceComparator;
|
||||
use Drupal\TestTools\Extension\SchemaInspector;
|
||||
use Drupal\TestTools\TestVarDumper;
|
||||
use PHPUnit\Framework\Exception;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
@ -715,14 +716,20 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
|
|||
* If $module is not enabled or the table schema cannot be found.
|
||||
*/
|
||||
protected function installSchema($module, $tables) {
|
||||
// drupal_get_module_schema() is technically able to install a schema
|
||||
// of a non-enabled module, but its ability to load the module's .install
|
||||
// file depends on many other factors. To prevent differences in test
|
||||
// behavior and non-reproducible test failures, we only allow the schema of
|
||||
// explicitly loaded/enabled modules to be installed.
|
||||
if (!$this->container->get('module_handler')->moduleExists($module)) {
|
||||
/** @var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
|
||||
$module_handler = $this->container->get('module_handler');
|
||||
// Database connection schema is technically able to create database tables
|
||||
// using any valid specification, for example of a non-enabled module. But
|
||||
// ability to load the module's .install file depends on many other factors.
|
||||
// To prevent differences in test behavior and non-reproducible test
|
||||
// failures, we only allow the schema of explicitly loaded/enabled modules
|
||||
// to be installed.
|
||||
if (!$module_handler->moduleExists($module)) {
|
||||
throw new \LogicException("$module module is not enabled.");
|
||||
}
|
||||
$specification = SchemaInspector::getTablesSpecification($module_handler, $module);
|
||||
/** @var \Drupal\Core\Database\Schema $schema */
|
||||
$schema = $this->container->get('database')->schema();
|
||||
$tables = (array) $tables;
|
||||
foreach ($tables as $table) {
|
||||
// The tables key_value and key_value_expire are lazy loaded and therefore
|
||||
|
@ -732,11 +739,10 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
|
|||
@trigger_error('Installing the tables key_value and key_value_expire with the method KernelTestBase::installSchema() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. The tables are now lazy loaded and therefore will be installed automatically when used. See https://www.drupal.org/node/3143286', E_USER_DEPRECATED);
|
||||
continue;
|
||||
}
|
||||
$schema = drupal_get_module_schema($module, $table);
|
||||
if (empty($schema)) {
|
||||
if (empty($specification[$table])) {
|
||||
throw new \LogicException("$module module does not define a schema for table '$table'.");
|
||||
}
|
||||
$this->container->get('database')->schema()->createTable($table, $schema);
|
||||
$schema->createTable($table, $specification[$table]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\TestTools\Extension;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
|
||||
/**
|
||||
* Provides methods to access modules' schema.
|
||||
*/
|
||||
class SchemaInspector {
|
||||
|
||||
/**
|
||||
* Returns the module's schema specification.
|
||||
*
|
||||
* This function can be used to retrieve a schema specification provided by
|
||||
* hook_schema(), so it allows you to derive your tables from existing
|
||||
* specifications.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $handler
|
||||
* The module handler to use for calling schema hook.
|
||||
* @param string $module
|
||||
* The module to which the table belongs.
|
||||
*
|
||||
* @return array
|
||||
* An array of schema definition provided by hook_schema().
|
||||
*
|
||||
* @see \hook_schema()
|
||||
*/
|
||||
public static function getTablesSpecification(ModuleHandlerInterface $handler, string $module): array {
|
||||
if ($handler->loadInclude($module, 'install')) {
|
||||
return $handler->invoke($module, 'schema') ?? [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue