From 9c25560ff565891f365c45abeecf830debb8b102 Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Mon, 6 Jun 2022 20:48:26 +0000 Subject: [PATCH] Issue #3277007 by phenaproxima, chrisfromredfin, tedbow, Theresa.Grannum: Validation messages displayed on admin pages should be grouped together so it's clear they are all related to automatic updates --- .../src/Form/UpdaterForm.php | 16 +++- src/Form/UpdaterForm.php | 18 ++++- src/Validation/AdminReadinessMessages.php | 18 ++++- src/Validation/ReadinessTrait.php | 36 +++++---- .../{Unit => Kernel}/ReadinessTraitTest.php | 74 +++++-------------- 5 files changed, 84 insertions(+), 78 deletions(-) rename tests/src/{Unit => Kernel}/ReadinessTraitTest.php (52%) diff --git a/automatic_updates_extensions/src/Form/UpdaterForm.php b/automatic_updates_extensions/src/Form/UpdaterForm.php index b059c9df51..46915c1ae6 100644 --- a/automatic_updates_extensions/src/Form/UpdaterForm.php +++ b/automatic_updates_extensions/src/Form/UpdaterForm.php @@ -9,6 +9,7 @@ use Drupal\automatic_updates_extensions\ExtensionUpdater; use Drupal\Core\Batch\BatchBuilder; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\RendererInterface; use Drupal\system\SystemManager; use Drupal\update\UpdateManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -38,6 +39,13 @@ final class UpdaterForm extends FormBase { */ private $eventDispatcher; + /** + * The renderer service. + * + * @var \Drupal\Core\Render\RendererInterface + */ + private $renderer; + /** * {@inheritdoc} */ @@ -45,6 +53,7 @@ final class UpdaterForm extends FormBase { return new static( $container->get('automatic_updates_extensions.updater'), $container->get('event_dispatcher'), + $container->get('renderer') ); } @@ -55,10 +64,13 @@ final class UpdaterForm extends FormBase { * The extension updater service. * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher * The extension event dispatcher service. + * @param \Drupal\Core\Render\RendererInterface $renderer + * The renderer service. */ - public function __construct(ExtensionUpdater $extension_updater, EventDispatcherInterface $event_dispatcher) { + public function __construct(ExtensionUpdater $extension_updater, EventDispatcherInterface $event_dispatcher, RendererInterface $renderer) { $this->extensionUpdater = $extension_updater; $this->eventDispatcher = $event_dispatcher; + $this->renderer = $renderer; } /** @@ -120,7 +132,7 @@ final class UpdaterForm extends FormBase { $this->eventDispatcher->dispatch($event); $results = $event->getResults(); } - $this->displayResults($results, $this->messenger()); + $this->displayResults($results, $this->messenger(), $this->renderer); $security_level = $this->getOverallSeverity($results); if ($update_projects && $security_level !== SystemManager::REQUIREMENT_ERROR) { diff --git a/src/Form/UpdaterForm.php b/src/Form/UpdaterForm.php index 82977859cd..7a8e8250c8 100644 --- a/src/Form/UpdaterForm.php +++ b/src/Form/UpdaterForm.php @@ -13,6 +13,7 @@ use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Link; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\State\StateInterface; use Drupal\Core\Url; use Drupal\package_manager\Exception\StageException; @@ -60,6 +61,13 @@ class UpdaterForm extends FormBase { */ protected $releaseChooser; + /** + * The renderer service. + * + * @var \Drupal\Core\Render\RendererInterface + */ + protected $renderer; + /** * Constructs a new UpdaterForm object. * @@ -71,12 +79,15 @@ class UpdaterForm extends FormBase { * The event dispatcher service. * @param \Drupal\automatic_updates\ReleaseChooser $release_chooser * The release chooser service. + * @param \Drupal\Core\Render\RendererInterface $renderer + * The renderer service. */ - public function __construct(StateInterface $state, Updater $updater, EventDispatcherInterface $event_dispatcher, ReleaseChooser $release_chooser) { + public function __construct(StateInterface $state, Updater $updater, EventDispatcherInterface $event_dispatcher, ReleaseChooser $release_chooser, RendererInterface $renderer) { $this->updater = $updater; $this->state = $state; $this->eventDispatcher = $event_dispatcher; $this->releaseChooser = $release_chooser; + $this->renderer = $renderer; } /** @@ -94,7 +105,8 @@ class UpdaterForm extends FormBase { $container->get('state'), $container->get('automatic_updates.updater'), $container->get('event_dispatcher'), - $container->get('automatic_updates.release_chooser') + $container->get('automatic_updates.release_chooser'), + $container->get('renderer') ); } @@ -252,7 +264,7 @@ class UpdaterForm extends FormBase { $this->eventDispatcher->dispatch($event); $results = $event->getResults(); } - $this->displayResults($results, $this->messenger()); + $this->displayResults($results, $this->messenger(), $this->renderer); if ($stage_exists) { // If the form has been submitted, do not display this error message diff --git a/src/Validation/AdminReadinessMessages.php b/src/Validation/AdminReadinessMessages.php index 82084f29ce..b5e2777d15 100644 --- a/src/Validation/AdminReadinessMessages.php +++ b/src/Validation/AdminReadinessMessages.php @@ -6,6 +6,7 @@ use Drupal\automatic_updates\CronUpdater; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Messenger\MessengerTrait; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\Routing\AdminContext; use Drupal\Core\Routing\CurrentRouteMatch; use Drupal\Core\Routing\RedirectDestinationTrait; @@ -65,6 +66,13 @@ final class AdminReadinessMessages implements ContainerInjectionInterface { */ protected $cronUpdater; + /** + * The renderer service. + * + * @var \Drupal\Core\Render\RendererInterface + */ + protected $renderer; + /** * Constructs a ReadinessRequirement object. * @@ -82,8 +90,10 @@ final class AdminReadinessMessages implements ContainerInjectionInterface { * The current route match. * @param \Drupal\automatic_updates\CronUpdater $cron_updater * The cron updater service. + * @param \Drupal\Core\Render\RendererInterface $renderer + * The renderer service. */ - public function __construct(ReadinessValidationManager $readiness_checker_manager, MessengerInterface $messenger, AdminContext $admin_context, AccountProxyInterface $current_user, TranslationInterface $translation, CurrentRouteMatch $current_route_match, CronUpdater $cron_updater) { + public function __construct(ReadinessValidationManager $readiness_checker_manager, MessengerInterface $messenger, AdminContext $admin_context, AccountProxyInterface $current_user, TranslationInterface $translation, CurrentRouteMatch $current_route_match, CronUpdater $cron_updater, RendererInterface $renderer) { $this->readinessCheckerManager = $readiness_checker_manager; $this->setMessenger($messenger); $this->adminContext = $admin_context; @@ -91,6 +101,7 @@ final class AdminReadinessMessages implements ContainerInjectionInterface { $this->setStringTranslation($translation); $this->currentRouteMatch = $current_route_match; $this->cronUpdater = $cron_updater; + $this->renderer = $renderer; } /** @@ -104,7 +115,8 @@ final class AdminReadinessMessages implements ContainerInjectionInterface { $container->get('current_user'), $container->get('string_translation'), $container->get('current_route_match'), - $container->get('automatic_updates.cron_updater') + $container->get('automatic_updates.cron_updater'), + $container->get('renderer') ); } @@ -167,7 +179,7 @@ final class AdminReadinessMessages implements ContainerInjectionInterface { if (empty($results)) { return FALSE; } - $this->displayResults($results, $this->messenger()); + $this->displayResults($results, $this->messenger(), $this->renderer); return TRUE; } diff --git a/src/Validation/ReadinessTrait.php b/src/Validation/ReadinessTrait.php index 9966f24b5c..12b0df150f 100644 --- a/src/Validation/ReadinessTrait.php +++ b/src/Validation/ReadinessTrait.php @@ -3,11 +3,17 @@ namespace Drupal\automatic_updates\Validation; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\Render\RendererInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\system\SystemManager; /** * Common methods for working with readiness checkers. + * + * @internal + * This class implements logic to output the messages from readiness checkers + * on admin pages. It may be changed or removed at any time without warning + * and should not be used by external code. */ trait ReadinessTrait { @@ -59,33 +65,35 @@ trait ReadinessTrait { * The validation results. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. + * @param \Drupal\Core\Render\RendererInterface $renderer + * The renderer service. */ - protected function displayResults(array $results, MessengerInterface $messenger): void { + protected function displayResults(array $results, MessengerInterface $messenger, RendererInterface $renderer): void { $severity = $this->getOverallSeverity($results); if ($severity === SystemManager::REQUIREMENT_OK) { return; } - $message = $this->getFailureMessageForSeverity($severity); + // Format the results as a single item list prefixed by a preamble message. + $build = [ + '#theme' => 'item_list__automatic_updates_validation_results', + '#prefix' => $this->getFailureMessageForSeverity($severity), + ]; + foreach ($results as $result) { + $messages = $result->getMessages(); + // @todo Find a way to show all the messages, not just the summary, if + // we're on the updater form in https://drupal.org/i/3284346. + $build['#items'][] = count($messages) === 1 ? reset($messages) : $result->getSummary(); + } + $message = $renderer->renderRoot($build); + if ($severity === SystemManager::REQUIREMENT_ERROR) { $messenger->addError($message); } else { $messenger->addWarning($message); } - - foreach ($results as $result) { - $messages = $result->getMessages(); - $message = count($messages) === 1 ? $messages[0] : $result->getSummary(); - - if ($result->getSeverity() === SystemManager::REQUIREMENT_ERROR) { - $messenger->addError($message); - } - else { - $messenger->addWarning($message); - } - } } } diff --git a/tests/src/Unit/ReadinessTraitTest.php b/tests/src/Kernel/ReadinessTraitTest.php similarity index 52% rename from tests/src/Unit/ReadinessTraitTest.php rename to tests/src/Kernel/ReadinessTraitTest.php index 808927a099..6fb6c3423d 100644 --- a/tests/src/Unit/ReadinessTraitTest.php +++ b/tests/src/Kernel/ReadinessTraitTest.php @@ -1,25 +1,19 @@ <?php -namespace Drupal\Tests\automatic_updates\Unit; +namespace Drupal\Tests\automatic_updates\Kernel; use Drupal\automatic_updates\Validation\ReadinessTrait; -use Drupal\Core\Messenger\Messenger; -use Drupal\Core\PageCache\ResponsePolicy\KillSwitch; -use Drupal\Core\StringTranslation\PluralTranslatableMarkup; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\Core\StringTranslation\TranslatableMarkup; -use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\package_manager\ValidationResult; use Drupal\system\SystemManager; -use Drupal\Tests\UnitTestCase; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; /** * @coversDefaultClass \Drupal\automatic_updates\Validation\ReadinessTrait * * @group automatic_updates */ -class ReadinessTraitTest extends UnitTestCase { +class ReadinessTraitTest extends AutomaticUpdatesKernelTestBase { use ReadinessTrait; use StringTranslationTrait; @@ -49,47 +43,43 @@ class ReadinessTraitTest extends UnitTestCase { * @covers ::displayResults */ public function testDisplayResults(): void { - $messenger = new Messenger(new FlashBag(), new KillSwitch()); - - $translation = new TestTranslationManager(); - $this->setStringTranslation($translation); + $messenger = $this->container->get('messenger'); + $renderer = $this->container->get('renderer'); // An error and a warning should display the error preamble, and the result // messages as errors and warnings, respectively. $results = [ ValidationResult::createError(['Boo!']), - ValidationResult::createError(['Wednesday', 'Thursday'], $this->t('The Addams Family')), + ValidationResult::createError(['Wednesday', 'Lurch'], $this->t('The Addams Family')), ValidationResult::createWarning(['Moo!']), ValidationResult::createWarning(['Shaggy', 'The dog'], $this->t('Mystery Mobile')), ]; - $this->displayResults($results, $messenger); + $this->displayResults($results, $messenger, $renderer); + $failure_message = (string) $this->getFailureMessageForSeverity(SystemManager::REQUIREMENT_ERROR); $expected_errors = [ - (string) $this->getFailureMessageForSeverity(SystemManager::REQUIREMENT_ERROR), - 'Boo!', - 'The Addams Family', + "$failure_message<ul><li>Boo!</li><li>The Addams Family</li><li>Moo!</li><li>Mystery Mobile</li></ul>", ]; - $actual_errors = array_map('strval', $messenger->deleteByType(Messenger::TYPE_ERROR)); + $actual_errors = array_map('strval', $messenger->deleteByType(MessengerInterface::TYPE_ERROR)); $this->assertSame($expected_errors, $actual_errors); - // Even though there were warnings, we shouldn't see the warning preamble. - $expected_warnings = ['Moo!', 'Mystery Mobile']; - $actual_warnings = array_map('strval', $messenger->deleteByType(Messenger::TYPE_WARNING)); - $this->assertSame($expected_warnings, $actual_warnings); + // Even though there were warnings, they should have been included with the + // errors. + $actual_warnings = array_map('strval', $messenger->deleteByType(MessengerInterface::TYPE_WARNING)); + $this->assertEmpty($actual_warnings); // There shouldn't be any more messages. $this->assertEmpty($messenger->all()); // If there are only warnings, we should see the warning preamble. $results = array_slice($results, -2); - $this->displayResults($results, $messenger); + $this->displayResults($results, $messenger, $renderer); + $failure_message = (string) $this->getFailureMessageForSeverity(SystemManager::REQUIREMENT_WARNING); $expected_warnings = [ - (string) $this->getFailureMessageForSeverity(SystemManager::REQUIREMENT_WARNING), - 'Moo!', - 'Mystery Mobile', + "$failure_message<ul><li>Moo!</li><li>Mystery Mobile</li></ul>", ]; - $actual_warnings = array_map('strval', $messenger->deleteByType(Messenger::TYPE_WARNING)); + $actual_warnings = array_map('strval', $messenger->deleteByType(MessengerInterface::TYPE_WARNING)); $this->assertSame($expected_warnings, $actual_warnings); // There shouldn't be any more messages. @@ -97,31 +87,3 @@ class ReadinessTraitTest extends UnitTestCase { } } - -/** - * Implements a translation manager in tests. - */ -class TestTranslationManager implements TranslationInterface { - - /** - * {@inheritdoc} - */ - public function translate($string, array $args = [], array $options = []) { - return new TranslatableMarkup($string, $args, $options, $this); - } - - /** - * {@inheritdoc} - */ - public function translateString(TranslatableMarkup $translated_string) { - return $translated_string->getUntranslatedString(); - } - - /** - * {@inheritdoc} - */ - public function formatPlural($count, $singular, $plural, array $args = [], array $options = []) { - return new PluralTranslatableMarkup($count, $singular, $plural, $args, $options, $this); - } - -} -- GitLab