diff --git a/core/lib/Drupal/Core/Database/Install/Tasks.php b/core/lib/Drupal/Core/Database/Install/Tasks.php index 47b973b9b00774a718237aa1885447d9431441df..b7fceace1196398a97356007d835a9adf2573a9b 100644 --- a/core/lib/Drupal/Core/Database/Install/Tasks.php +++ b/core/lib/Drupal/Core/Database/Install/Tasks.php @@ -151,6 +151,19 @@ public function runTasks() { return $this->results['fail']; } + /** + * Checks engine version requirements for the status report. + * + * This method is called during runtime and update requirements checks. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup[] + * A list of error messages. + */ + final public function engineVersionRequirementsCheck() { + $this->checkEngineVersion(); + return $this->results['fail']; + } + /** * Check if we can connect to the database. */ diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 89335d0136ff6dcd4e8885f1f747b4c79057119b..5efa64c4add1b6d6185f5a1e371b0ea5b0624544 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -427,9 +427,11 @@ function system_requirements($phase) { $requirements['database_extensions']['value'] = t('Enabled'); } } - else { + + if ($phase === 'runtime' || $phase === 'update') { // Database information. $class = Database::getConnection()->getDriverClass('Install\\Tasks'); + /** @var \Drupal\Core\Database\Install\Tasks $tasks */ $tasks = new $class(); $requirements['database_system'] = [ 'title' => t('Database system'), @@ -439,6 +441,19 @@ function system_requirements($phase) { 'title' => t('Database system version'), 'value' => Database::getConnection()->version(), ]; + + $errors = $tasks->engineVersionRequirementsCheck(); + $error_count = count($errors); + if ($error_count > 0) { + $error_message = [ + '#theme' => 'item_list', + '#items' => $errors, + // Use the comma-list style to display a single error without bullets. + '#context' => ['list_style' => $error_count === 1 ? 'comma-list' : ''], + ]; + $requirements['database_system_version']['severity'] = REQUIREMENT_ERROR; + $requirements['database_system_version']['description'] = $error_message; + } } // Test PHP memory_limit diff --git a/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Connection.php b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Connection.php new file mode 100644 index 0000000000000000000000000000000000000000..c7ec0fed72a89ea0343f4762981daed33feedb5c --- /dev/null +++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Connection.php @@ -0,0 +1,49 @@ +<?php + +namespace Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion; + +use Drupal\Core\Database\Driver\mysql\Connection as CoreConnection; + +/** + * MySQL test implementation of \Drupal\Core\Database\Connection. + */ +class Connection extends CoreConnection { + + /** + * Hardcoded database server version. + * + * Faking that we are on a deprecated database. + * + * @var string + */ + protected $databaseVersion = '10.2.31-MariaDB-1:10.2.31+maria~bionic-log'; + + /** + * {@inheritdoc} + */ + public function driver() { + return 'DrivertestMysqlDeprecatedVersion'; + } + + /** + * {@inheritdoc} + */ + public function isMariaDb(): bool { + return TRUE; + } + + /** + * {@inheritdoc} + */ + public function version() { + return $this->databaseVersion; + } + + /** + * {@inheritdoc} + */ + protected function getServerVersion(): string { + return $this->databaseVersion; + } + +} diff --git a/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Insert.php b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Insert.php new file mode 100644 index 0000000000000000000000000000000000000000..86affc1a349c6f363052b9a7add1bb176f504bea --- /dev/null +++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Insert.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion; + +use Drupal\Core\Database\Driver\mysql\Insert as CoreInsert; + +/** + * MySQL test implementation of \Drupal\Core\Database\Query\Insert. + */ +class Insert extends CoreInsert {} diff --git a/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Install/Tasks.php b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Install/Tasks.php new file mode 100644 index 0000000000000000000000000000000000000000..c768de5721efa21f0d6614b84a10234de32433c8 --- /dev/null +++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Install/Tasks.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion\Install; + +use Drupal\Core\Database\Driver\mysql\Install\Tasks as CoreTasks; + +/** + * Specifies installation tasks for MySQL test databases. + */ +class Tasks extends CoreTasks { + + /** + * {@inheritdoc} + */ + public function name() { + return t('MySQL deprecated version by the driver_test module'); + } + +} diff --git a/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Schema.php b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Schema.php new file mode 100644 index 0000000000000000000000000000000000000000..fef11ed4de0be9506c005f16a69b3fef8bd23242 --- /dev/null +++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Schema.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion; + +use Drupal\Core\Database\Driver\mysql\Schema as CoreSchema; + +/** + * MySQL test implementation of \Drupal\Core\Database\Schema. + */ +class Schema extends CoreSchema {} diff --git a/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Upsert.php b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Upsert.php new file mode 100644 index 0000000000000000000000000000000000000000..78ee82d34db4195305ae8d8eb7010eb4ee257e78 --- /dev/null +++ b/core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Upsert.php @@ -0,0 +1,10 @@ +<?php + +namespace Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion; + +use Drupal\Core\Database\Driver\mysql\Upsert as CoreUpsert; + +/** + * MySQL test implementation of \Drupal\Core\Database\Query\Upsert. + */ +class Upsert extends CoreUpsert {} diff --git a/core/modules/system/tests/src/Functional/Update/DatabaseVersionCheckUpdateTest.php b/core/modules/system/tests/src/Functional/Update/DatabaseVersionCheckUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2202dc000b2919499a5baafe437121d3f15f5a7c --- /dev/null +++ b/core/modules/system/tests/src/Functional/Update/DatabaseVersionCheckUpdateTest.php @@ -0,0 +1,68 @@ +<?php + +namespace Drupal\Tests\system\Functional\Update; + +use Drupal\Core\Database\Database; +use Drupal\Core\Url; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\UpdatePathTestTrait; + +/** + * Tests that updates fail if the database does not meet the minimum version. + * + * @group Update + */ +class DatabaseVersionCheckUpdateTest extends BrowserTestBase { + use UpdatePathTestTrait; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $this->ensureUpdatesToRun(); + } + + /** + * Tests that updates fail if the database does not meet the minimum version. + */ + public function testUpdate() { + if (Database::getConnection()->driver() !== 'mysql') { + $this->markTestSkipped('This test only works with the mysql driver'); + } + + // Use a database driver that reports a fake database version that does + // not meet requirements. Only change the necessary settings in the database + // settings array so that run-tests.sh continues to work. + $autoload = Database::findDriverAutoloadDirectory('Drupal\driver_test\Driver\Database\DrivertestMysqlDeprecatedVersion', \Drupal::root()); + $settings['databases']['default']['default']['driver'] = (object) [ + 'value' => 'DrivertestMysqlDeprecatedVersion', + 'required' => TRUE, + ]; + $settings['databases']['default']['default']['namespace'] = (object) [ + 'value' => 'Drupal\\driver_test\\Driver\\Database\\DrivertestMysqlDeprecatedVersion', + 'required' => TRUE, + ]; + $settings['databases']['default']['default']['autoload'] = (object) [ + 'value' => $autoload, + 'required' => TRUE, + ]; + $settings['settings'] = [ + 'update_free_access' => (object) [ + 'value' => TRUE, + 'required' => TRUE, + ], + ]; + $this->writeSettings($settings); + + $this->drupalGet(Url::fromRoute('system.db_update')); + $this->assertSession()->pageTextContains('Errors found'); + $this->assertSession()->pageTextContains('The database server version 10.2.31-MariaDB-1:10.2.31+maria~bionic-log is less than the minimum required version'); + } + +}