From 274abbdd53bf3af61a555fb5b6531b1c72ae373f Mon Sep 17 00:00:00 2001 From: binoli-lalani <binoliblalani@gmail.com> Date: Mon, 13 May 2024 13:06:16 +0530 Subject: [PATCH 1/6] Issue #2720109 by Spokje, kndr, sharma.amitt16, maacl, felribeiro, Neslee Canil Pinto, yogeshmpawar, quietone, joey-santiago, zeuty, Brian-C, ranjith_kumar_k_u, seppelM, jenny.cha, kiwimind, NikLP: maintenance-page--offline.html.twig is not picked up when system is offline --- core/includes/errors.inc | 12 +- .../FinalExceptionSubscriber.php | 19 +- core/lib/Drupal/Core/Utility/Error.php | 70 +++++- .../tests/src/Functional/BigPipeTest.php | 4 +- .../maintenance-page--offline.html.twig | 41 ++++ .../System/MaintenancePageOfflineTest.php | 210 ++++++++++++++++++ .../maintenance-page--offline.html.twig | 41 ++++ sites/default/default.settings.php | 5 + 8 files changed, 394 insertions(+), 8 deletions(-) create mode 100644 core/modules/system/templates/maintenance-page--offline.html.twig create mode 100644 core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php create mode 100644 core/modules/system/tests/themes/test_theme/templates/maintenance-page--offline.html.twig diff --git a/core/includes/errors.inc b/core/includes/errors.inc index d82ed9bdd165..38138b738ad6 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -262,7 +262,7 @@ function _drupal_log_error($error, $fatal = FALSE): void { // We fallback to a maintenance page at this point, because the page // generation itself can generate errors. // Should not translate the string to avoid errors producing more errors. - $message = 'The website encountered an unexpected error. Try again later.' . '<br />' . $message; + $message = 'The website encountered an unexpected error. Please try again later.' . '<br /><br />' . $message; if ($is_installer) { // install_display_output() prints the output and ends script execution. @@ -279,6 +279,16 @@ function _drupal_log_error($error, $fatal = FALSE): void { } } + $html = Error::renderFatalError([ + 'title' => 'Service unavailable', + 'content' => $message, + 'displayable' => error_displayable($error), + ]); + if (!empty($html)) { + $message = $html; + $response->headers->set('Content-Type', 'text/html'); + } + $response->setContent($message); $response->setStatusCode(500, '500 Service unavailable (with message)'); diff --git a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php index 3473a1b5775d..a75bdac1393b 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php @@ -30,9 +30,10 @@ * handled by a single exception subscriber:: serialization.exception.default. * * This exception subscriber runs after all the above (it has a lower priority), - * which makes it the last-chance exception handler. It always sends a plain - * text response. If it's a displayable error and the error level is configured - * to be verbose, then a helpful backtrace is also printed. + * which makes it the last-chance exception handler. It sends a html response + * if a request format is html and a plain text otherwise. If it's a displayable + * error and the error level is configured to be verbose, then a helpful + * backtrace is also printed. */ class FinalExceptionSubscriber implements EventSubscriberInterface { use StringTranslationTrait; @@ -129,6 +130,18 @@ public function onException(ExceptionEvent $event) { $content_type = $event->getRequest()->getRequestFormat() == 'html' ? 'text/html' : 'text/plain'; $content = $this->t('The website encountered an unexpected error. Try again later.'); $content .= $message ? '<br><br>' . $message : ''; + + if ($content_type == 'text/html') { + $html = Error::renderFatalError([ + 'title' => $this->t('Service unavailable'), + 'content' => $content, + 'displayable' => $this->isErrorDisplayable($error), + ]); + if (!empty($html)) { + $content = $html; + } + } + $response = new Response($content, 500, ['Content-Type' => $content_type]); if ($exception instanceof HttpExceptionInterface) { diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php index 459af44d8c51..6e7d29ef0f76 100644 --- a/core/lib/Drupal/Core/Utility/Error.php +++ b/core/lib/Drupal/Core/Utility/Error.php @@ -2,13 +2,18 @@ namespace Drupal\Core\Utility; -use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\DependencyInjection\ContainerNotInitializedException; +use Drupal\Core\Extension\ExtensionDiscovery; +use Drupal\Core\Site\Settings; use Drupal\Component\Utility\Xss; +use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Database\Connection; use Drupal\Core\Database\Database; use Drupal\Core\Database\DatabaseExceptionWrapper; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; +use Twig\Environment; +use Twig\Loader\ArrayLoader; /** * Drupal error utility class. @@ -120,6 +125,69 @@ public static function renderExceptionSafe($exception) { return new FormattableMarkup(Error::DEFAULT_ERROR_MESSAGE . ' <pre class="backtrace">@backtrace</pre>', $decode); } + /** + * Renders fatal error page from twig template using Symfony twig engine. + * + * @param array $context + * Variables to be passed to twig template. + * + * @return string + * An html code with rendered fatal error page. + */ + public static function renderFatalError(array $context) { + $template_path = '/templates/maintenance-page--offline.html.twig'; + $system_path = 'core/modules/system'; + $theme = ''; + + // Get offline theme from settings.php and check if the template exists. + try { + $theme = Settings::get('maintenance_theme', ''); + if (!$theme) { + $theme_path = $system_path; + } + else { + $theme_path = \Drupal::service('extension.list.theme')->getPath($theme); + } + } + catch (ContainerNotInitializedException $e) { + // The maintenance theme is set but the container doesn't exist + // since the database is inactive. Hence there are no services available + // to retrieve a maintenance theme path. The path can be obtained by using + // ExtensionDiscovery::scan() but the app root should be guessed first + // in the same way as DrupalKernel::guessApplicationRoot() does. + $app_root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2); + $listing = new ExtensionDiscovery($app_root, FALSE, NULL, NULL); + // An empty profile directory prevents ExtensionDiscovery::scan() + // from calling \Drupal::installProfile() that needs working container. + $listing->setProfileDirectories([]); + $themes = $listing->scan('theme'); + $theme_path = isset($themes[$theme]) ? $themes[$theme]->getPath() : $system_path; + if ($context['displayable']) { + $context['content'] = $context['content'] . "<pre>" . $e . "</pre>"; + } + } + catch (\Throwable $error) { + // Handle any other cases. + $theme_path = $system_path; + if ($context['displayable']) { + $context['content'] = $context['content'] . "<pre>" . $error . "</pre>"; + } + } + + $path = $theme_path . $template_path; + if (!file_exists($path)) { + $path = $system_path . $template_path; + } + + // Directly use Symfony twig engine without Drupal wrapper to minimize + // possibility of nested exception. + $template = file_get_contents($path); + $loader = new ArrayLoader(['maintenance_page_offline' => $template]); + $environment = new Environment($loader); + + return $environment->render('maintenance_page_offline', $context); + } + /** * Gets the last caller from a backtrace. * diff --git a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php index 26e92fc14982..38f6083fbb99 100644 --- a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php +++ b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php @@ -212,9 +212,8 @@ public function testBigPipe(): void { // The 'edge_case__html_exception' case throws an exception. $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later'); $this->assertSession()->pageTextContains('You are not allowed to say llamas are not cool!'); - // Check that stop signal and closing body tag are absent. + // Check that stop signal is absent. $this->assertSession()->responseNotContains(BigPipe::STOP_SIGNAL); - $this->assertSession()->responseNotContains('</body>'); // The exception is expected. Do not interpret it as a test failure. unlink($this->root . '/' . $this->siteDirectory . '/error.log'); @@ -294,7 +293,6 @@ public function testBigPipeNoJs(): void { // The 'edge_case__html_exception' case throws an exception. $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later'); $this->assertSession()->pageTextContains('You are not allowed to say llamas are not cool!'); - $this->assertSession()->responseNotContains('</body>'); // The exception is expected. Do not interpret it as a test failure. unlink($this->root . '/' . $this->siteDirectory . '/error.log'); } diff --git a/core/modules/system/templates/maintenance-page--offline.html.twig b/core/modules/system/templates/maintenance-page--offline.html.twig new file mode 100644 index 000000000000..f7ba55ddecd4 --- /dev/null +++ b/core/modules/system/templates/maintenance-page--offline.html.twig @@ -0,0 +1,41 @@ +{# +/** + * @file + * Default theme implementation to display a single Drupal page while offline. + * + * @see template_preprocess_maintenance_page() + * + * @ingroup themeable + */ +#} +<!DOCTYPE html> +<html lang="en"> + <head> + <title> + {% if title %} + {{ title }} + {% else %} + Service Unavailable + {% endif %} + </title> + </head> + <body class="maintenance-page layout-no-sidebars path-frontpage"> + <div id="page-wrapper"> + <div id="page"> + <div id="main-wrapper"> + <div id="main" class="clearfix"> + <main id="content" class="column" role="main"> + <section class="section"> + <a id="main-content"></a> + {% if title %} + <h1 class="title" id="page-title">{{ title }}</h1> + {% endif %} + {{ content|striptags('<p>,<br>,<em>,<pre>')|raw }} + </section> + </main> + </div> + </div> + </div> + </div> + </body> +</html> \ No newline at end of file diff --git a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php new file mode 100644 index 000000000000..2db794b10e55 --- /dev/null +++ b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php @@ -0,0 +1,210 @@ +<?php + +namespace Drupal\Tests\system\Functional\System; + +use Drupal\Core\Database\Database; +use Drupal\Tests\BrowserTestBase; + +/** + * Tests if the Maintenance page is served when the site is offline. + * + * @group system + */ +class MaintenancePageOfflineTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'test_theme'; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $settings_filename = $this->siteDirectory . '/settings.php'; + chmod($settings_filename, 0777); + $settings_php = file_get_contents($settings_filename); + // Ensure we can test errors rather than being caught in + // \Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware. + $settings_php .= "\ndefine('SIMPLETEST_COLLECT_ERRORS', FALSE);\n"; + file_put_contents($settings_filename, $settings_php); + } + + /** + * Prepare settings values before a test case. + * + * @param string $maintenance_theme + * The name of a maintenance theme. Empty if there is no maintenance theme. + * @param string $error_level + * The name of an error level. + * @param bool $active_database + * TRUE if a database should be active. + * @param bool $valid_hash_salt + * TRUE if a hash_salt should be valid. + */ + protected function prepareCaseSettings($maintenance_theme, $error_level, $active_database = TRUE, $valid_hash_salt = TRUE) { + $settings = []; + if (!empty($maintenance_theme)) { + $settings['settings']['maintenance_theme'] = (object) [ + 'value' => $maintenance_theme, + 'required' => TRUE, + ]; + } + $settings['config']['system.logging']['error_level'] = (object) [ + 'value' => $error_level, + 'required' => TRUE, + ]; + if (!$active_database) { + // Make a database inactive by setting an invalid password. + $connection_info = Database::getConnectionInfo(); + $settings['databases']['default']['default']['password'] = (object) [ + 'value' => $connection_info['default']['password'] . $this->randomMachineName(), + 'required' => TRUE, + ]; + } + if (!$valid_hash_salt) { + // Set a hash_salt to invalid value. + $settings['settings']['hash_salt'] = (object) [ + 'value' => NULL, + 'required' => TRUE, + ]; + } + $this->writeSettings($settings); + } + + /** + * Tests cases when settings.php contains invalid database settings. + * + * Tests if the maintenance offline page is served when settings.php + * contains invalid database settings. + */ + public function testInvalidDatabaseSettings() { + // Open a frontpage without any error. + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Log in'); + + // CASE 1 - a maintenance theme's template is picked up + // and no errors are displayed. + $this->prepareCaseSettings('test_theme', ERROR_REPORTING_HIDE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A maintenance theme's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title test-theme"'); + // A fatal error message and a backtrace should be hidden. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextNotContains('Access denied for user'); + $this->assertSession()->responseNotContains('<pre class="backtrace">'); + + // CASE 2 - a maintenance theme's template is picked up + // and all errors with a backtrace are displayed. + $this->prepareCaseSettings('test_theme', ERROR_REPORTING_DISPLAY_VERBOSE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A maintenance theme's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title test-theme"'); + // A fatal error message and a backtrace should be shown. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('Access denied for user'); + $this->assertSession()->responseContains('<pre class="backtrace">'); + + // CASE 3 - a system's template is picked up + // since a maintenance theme doesn't have the template + // and no errors are displayed. + $this->prepareCaseSettings('test_subtheme', ERROR_REPORTING_HIDE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A system's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title"'); + // A fatal error message and a backtrace should be hidden. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextNotContains('Access denied for user'); + $this->assertSession()->responseNotContains('<pre class="backtrace">'); + + // CASE 4 - a system's template is picked up + // since a maintenance theme is not set + // and all errors with a backtrace are displayed. + $this->prepareCaseSettings('', ERROR_REPORTING_DISPLAY_VERBOSE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A system's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title"'); + // A fatal error message and a backtrace should be shown. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('Access denied for user'); + $this->assertSession()->responseContains('<pre class="backtrace">'); + } + + /** + * Tests cases when settings.php doesn't have a hash_salt defined. + * + * Tests if the maintenance offline page is served when settings.php + * originally did have a hash_salt defined, which is emptied out afterwards. + */ + public function testRemovedHashSalt() { + // Open a frontpage without any error. + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Log in'); + + // CASE 1 - a maintenance theme's template is picked up + // and no errors are displayed. + $this->prepareCaseSettings('test_theme', ERROR_REPORTING_HIDE, TRUE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A maintenance theme's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title test-theme"'); + // A fatal error message and a backtrace should be hidden. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextNotContains('Missing $settings[\'hash_salt\'] in settings.php'); + $this->assertSession()->responseNotContains('<pre class="backtrace">'); + + // CASE 2 - a maintenance theme's template is picked up + // and all errors with a backtrace are displayed. + $this->prepareCaseSettings('test_theme', ERROR_REPORTING_DISPLAY_VERBOSE, TRUE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A maintenance theme's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title test-theme"'); + // A fatal error message and a backtrace should be shown. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('Missing $settings[\'hash_salt\'] in settings.php'); + $this->assertSession()->responseContains('<pre class="backtrace">'); + + // CASE 3 - a system's template is picked up + // since a maintenance theme doesn't have the template + // and no errors are displayed. + $this->prepareCaseSettings('test_subtheme', ERROR_REPORTING_HIDE, TRUE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A system's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title"'); + // A fatal error message and a backtrace should be hidden. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextNotContains('Missing $settings[\'hash_salt\'] in settings.php'); + $this->assertSession()->responseNotContains('<pre class="backtrace">'); + + // CASE 4 - a system's template is picked up + // since a maintenance theme is not set + // and all errors with a backtrace are displayed. + $this->prepareCaseSettings('', ERROR_REPORTING_DISPLAY_VERBOSE, TRUE, FALSE); + $this->drupalGet(''); + $this->assertSession()->statusCodeEquals(500); + // A system's offline template should be picked up. + $this->assertSession()->pageTextContains('Service unavailable'); + $this->assertSession()->responseContains('<h1 class="title"'); + // A fatal error message and a backtrace should be shown. + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('Missing $settings[\'hash_salt\'] in settings.php'); + $this->assertSession()->responseContains('<pre class="backtrace">'); + } + +} \ No newline at end of file diff --git a/core/modules/system/tests/themes/test_theme/templates/maintenance-page--offline.html.twig b/core/modules/system/tests/themes/test_theme/templates/maintenance-page--offline.html.twig new file mode 100644 index 000000000000..f73983c4eb2d --- /dev/null +++ b/core/modules/system/tests/themes/test_theme/templates/maintenance-page--offline.html.twig @@ -0,0 +1,41 @@ +{# +/** + * @file + * Default theme implementation to display a single Drupal page while offline. + * + * @see template_preprocess_maintenance_page() + * + * @ingroup themeable + */ +#} +<!DOCTYPE html> +<html lang="en"> + <head> + <title> + {% if title %} + {{ title }} + {% else %} + Service Unavailable + {% endif %} + </title> + </head> + <body class="maintenance-page layout-no-sidebars path-frontpage"> + <div id="page-wrapper"> + <div id="page"> + <div id="main-wrapper"> + <div id="main" class="clearfix"> + <main id="content" class="column" role="main"> + <section class="section"> + <a id="main-content"></a> + {% if title %} + <h1 class="title test-theme" id="page-title">{{ title }}</h1> + {% endif %} + {{ content|striptags('<p>,<br>,<em>,<pre>')|raw }} + </section> + </main> + </div> + </div> + </div> + </div> + </body> +</html> \ No newline at end of file diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index e121075454fd..9f336a2b651c 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -658,6 +658,11 @@ * The template file should also be copied into the theme. It is located inside * 'core/modules/system/templates/maintenance-page.html.twig'. * + * This applies also when the database is inactive due to an error + * or when a fatal error is thrown. + * The template file should also be copied into the theme. It is located at + * 'core/modules/system/templates/maintenance-page--offline.html.twig'. + * * Note: This setting does not apply to installation and update pages. */ # $settings['maintenance_theme'] = 'claro'; -- GitLab From 42d1b10cb4cbc557d9c8257b7a843885c3f2d5d9 Mon Sep 17 00:00:00 2001 From: binoli-lalani <binoliblalani@gmail.com> Date: Mon, 13 May 2024 15:57:33 +0530 Subject: [PATCH 2/6] Issue #2720109 by Spokje, kndr, sharma.amitt16, maacl, felribeiro, Neslee Canil Pinto, yogeshmpawar, quietone, zeuty, joey-santiago, Brian-C, ranjith_kumar_k_u, seppelM, jenny.cha, kiwimind, NikLP: maintenance-page--offline.html.twig is not picked up when system is offline --- core/modules/big_pipe/tests/src/Functional/BigPipeTest.php | 2 +- .../tests/src/Functional/System/MaintenancePageOfflineTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php index 38f6083fbb99..e7aa0d4fa730 100644 --- a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php +++ b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php @@ -212,7 +212,7 @@ public function testBigPipe(): void { // The 'edge_case__html_exception' case throws an exception. $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later'); $this->assertSession()->pageTextContains('You are not allowed to say llamas are not cool!'); - // Check that stop signal is absent. + // Check that stop signal is absent. $this->assertSession()->responseNotContains(BigPipe::STOP_SIGNAL); // The exception is expected. Do not interpret it as a test failure. unlink($this->root . '/' . $this->siteDirectory . '/error.log'); diff --git a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php index 2db794b10e55..2b0de0be9c66 100644 --- a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php +++ b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php @@ -207,4 +207,4 @@ public function testRemovedHashSalt() { $this->assertSession()->responseContains('<pre class="backtrace">'); } -} \ No newline at end of file +} -- GitLab From 16fd4e4a125cd593ea35864eaa55a2677960c89f Mon Sep 17 00:00:00 2001 From: Brandon Lira <brandonlira98@gmail.com> Date: Thu, 27 Mar 2025 00:37:27 -0300 Subject: [PATCH 3/6] Issue #2720109: Add declare(strict_types=1); to fix PHPCS error --- .../tests/src/Functional/System/MaintenancePageOfflineTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php index 2b0de0be9c66..ce1c6cbed578 100644 --- a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php +++ b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + namespace Drupal\Tests\system\Functional\System; use Drupal\Core\Database\Database; -- GitLab From f29e322d7a23afc198f650039f08c91e9120a821 Mon Sep 17 00:00:00 2001 From: Brandon Lira <brandonlira98@gmail.com> Date: Thu, 27 Mar 2025 01:03:39 -0300 Subject: [PATCH 4/6] Issue #2720109: Add missing return type declarations to test methods --- .../src/Functional/System/MaintenancePageOfflineTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php index ce1c6cbed578..f205230a3949 100644 --- a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php +++ b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php @@ -45,7 +45,7 @@ protected function setUp(): void { * @param bool $valid_hash_salt * TRUE if a hash_salt should be valid. */ - protected function prepareCaseSettings($maintenance_theme, $error_level, $active_database = TRUE, $valid_hash_salt = TRUE) { + protected function prepareCaseSettings($maintenance_theme, $error_level, $active_database = TRUE, $valid_hash_salt = TRUE): void { $settings = []; if (!empty($maintenance_theme)) { $settings['settings']['maintenance_theme'] = (object) [ @@ -81,7 +81,7 @@ protected function prepareCaseSettings($maintenance_theme, $error_level, $active * Tests if the maintenance offline page is served when settings.php * contains invalid database settings. */ - public function testInvalidDatabaseSettings() { + public function testInvalidDatabaseSettings(): void { // Open a frontpage without any error. $this->drupalGet(''); $this->assertSession()->statusCodeEquals(200); @@ -148,7 +148,7 @@ public function testInvalidDatabaseSettings() { * Tests if the maintenance offline page is served when settings.php * originally did have a hash_salt defined, which is emptied out afterwards. */ - public function testRemovedHashSalt() { + public function testRemovedHashSalt(): void { // Open a frontpage without any error. $this->drupalGet(''); $this->assertSession()->statusCodeEquals(200); -- GitLab From c1844ef79b42281048a1603795da709c9b37e8d2 Mon Sep 17 00:00:00 2001 From: Brandon Lira <brandonlira98@gmail.com> Date: Thu, 27 Mar 2025 01:13:10 -0300 Subject: [PATCH 5/6] Issue #2720109: fix spellcheck violation by removing 'Please' from error messages --- .../System/MaintenancePageOfflineTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php index f205230a3949..06e2f5da9a22 100644 --- a/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php +++ b/core/modules/system/tests/src/Functional/System/MaintenancePageOfflineTest.php @@ -96,7 +96,7 @@ public function testInvalidDatabaseSettings(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title test-theme"'); // A fatal error message and a backtrace should be hidden. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextNotContains('Access denied for user'); $this->assertSession()->responseNotContains('<pre class="backtrace">'); @@ -109,7 +109,7 @@ public function testInvalidDatabaseSettings(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title test-theme"'); // A fatal error message and a backtrace should be shown. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextContains('Access denied for user'); $this->assertSession()->responseContains('<pre class="backtrace">'); @@ -123,7 +123,7 @@ public function testInvalidDatabaseSettings(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title"'); // A fatal error message and a backtrace should be hidden. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextNotContains('Access denied for user'); $this->assertSession()->responseNotContains('<pre class="backtrace">'); @@ -137,7 +137,7 @@ public function testInvalidDatabaseSettings(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title"'); // A fatal error message and a backtrace should be shown. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextContains('Access denied for user'); $this->assertSession()->responseContains('<pre class="backtrace">'); } @@ -163,7 +163,7 @@ public function testRemovedHashSalt(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title test-theme"'); // A fatal error message and a backtrace should be hidden. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextNotContains('Missing $settings[\'hash_salt\'] in settings.php'); $this->assertSession()->responseNotContains('<pre class="backtrace">'); @@ -176,7 +176,7 @@ public function testRemovedHashSalt(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title test-theme"'); // A fatal error message and a backtrace should be shown. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextContains('Missing $settings[\'hash_salt\'] in settings.php'); $this->assertSession()->responseContains('<pre class="backtrace">'); @@ -190,7 +190,7 @@ public function testRemovedHashSalt(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title"'); // A fatal error message and a backtrace should be hidden. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextNotContains('Missing $settings[\'hash_salt\'] in settings.php'); $this->assertSession()->responseNotContains('<pre class="backtrace">'); @@ -204,7 +204,7 @@ public function testRemovedHashSalt(): void { $this->assertSession()->pageTextContains('Service unavailable'); $this->assertSession()->responseContains('<h1 class="title"'); // A fatal error message and a backtrace should be shown. - $this->assertSession()->pageTextContains('The website encountered an unexpected error. Please try again later.'); + $this->assertSession()->pageTextContains('The website encountered an unexpected error. Try again later.'); $this->assertSession()->pageTextContains('Missing $settings[\'hash_salt\'] in settings.php'); $this->assertSession()->responseContains('<pre class="backtrace">'); } -- GitLab From 49e2a38a556bceeffa51c3cb09d902fb8248af83 Mon Sep 17 00:00:00 2001 From: Brandon Lira <brandonlira98@gmail.com> Date: Thu, 27 Mar 2025 01:20:33 -0300 Subject: [PATCH 6/6] Issue #2720109: fix spellcheck violation by removing 'Please' from error messages --- core/includes/errors.inc | 2 +- sites/default/default.settings.php | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 38138b738ad6..ea27cbef93a5 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -262,7 +262,7 @@ function _drupal_log_error($error, $fatal = FALSE): void { // We fallback to a maintenance page at this point, because the page // generation itself can generate errors. // Should not translate the string to avoid errors producing more errors. - $message = 'The website encountered an unexpected error. Please try again later.' . '<br /><br />' . $message; + $message = 'The website encountered an unexpected error. Try again later.' . '<br /><br />' . $message; if ($is_installer) { // install_display_output() prints the output and ends script execution. diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 9f336a2b651c..e121075454fd 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -658,11 +658,6 @@ * The template file should also be copied into the theme. It is located inside * 'core/modules/system/templates/maintenance-page.html.twig'. * - * This applies also when the database is inactive due to an error - * or when a fatal error is thrown. - * The template file should also be copied into the theme. It is located at - * 'core/modules/system/templates/maintenance-page--offline.html.twig'. - * * Note: This setting does not apply to installation and update pages. */ # $settings['maintenance_theme'] = 'claro'; -- GitLab