diff --git a/core/core.services.yml b/core/core.services.yml index 6049d3b..090b692 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1102,7 +1102,7 @@ services: arguments: ['@state', '@current_user'] maintenance_mode_subscriber: class: Drupal\Core\EventSubscriber\MaintenanceModeSubscriber - arguments: ['@maintenance_mode', '@config.factory', '@string_translation', '@url_generator', '@current_user', '@bare_html_page_renderer'] + arguments: ['@maintenance_mode', '@config.factory', '@string_translation', '@url_generator', '@current_user', '@bare_html_page_renderer', '@messenger'] tags: - { name: event_subscriber } path_subscriber: @@ -1607,3 +1607,6 @@ services: arguments: ['@current_user', '@path.current', '@path.matcher', '@language_manager'] tags: - { name: event_subscriber } + messenger: + class: Drupal\Core\Messenger\SessionMessenger + arguments: ['@session_manager', '@page_cache_kill_switch'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 2294d47..8d901a8 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -9,8 +9,6 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Unicode; use Drupal\Core\Logger\RfcLogLevel; -use Drupal\Core\Render\Markup; -use Drupal\Component\Render\MarkupInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Site\Settings; use Drupal\Core\Utility\Error; @@ -436,30 +434,15 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia * * @see drupal_get_messages() * @see status-messages.html.twig + * + * @deprecated Deprecated as of Drupal 8.2. + * Use \Drupal::service('messenger')->addMessage() instead. */ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) { - if (isset($message)) { - if (!isset($_SESSION['messages'][$type])) { - $_SESSION['messages'][$type] = array(); - } - - // Convert strings which are safe to the simplest Markup objects. - if (!($message instanceof Markup) && $message instanceof MarkupInterface) { - $message = Markup::create((string) $message); - } - - // Do not use strict type checking so that equivalent string and - // MarkupInterface objects are detected. - if ($repeat || !in_array($message, $_SESSION['messages'][$type])) { - $_SESSION['messages'][$type][] = $message; - } - - // Mark this page as being uncacheable. - \Drupal::service('page_cache_kill_switch')->trigger(); - } - - // Messages not set when DB connection fails. - return isset($_SESSION['messages']) ? $_SESSION['messages'] : NULL; + /* @var \Drupal\Core\Messenger\MessengerInterface $messenger */ + $messenger = \Drupal::service('messenger'); + $messenger->addMessage($message, $type, $repeat); + return $messenger->getMessages(); } /** @@ -486,12 +469,24 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) * * @see drupal_set_message() * @see status-messages.html.twig + * + * @deprecated Deprecated as of Drupal 8.2. + * Use \Drupal::service('messenger')->getMessages() or + * \Drupal::service('messenger')->getMessagesByType() instead. */ function drupal_get_messages($type = NULL, $clear_queue = TRUE) { - if ($messages = drupal_set_message()) { + // Workaround for code that can not check if the service exists. + if (!\Drupal::hasService('messenger')) { + return []; + } + + /** @var \Drupal\Core\Messenger\MessengerInterface $messenger */ + $messenger = \Drupal::service('messenger'); + + if ($messages = $messenger->getMessages()) { if ($type) { if ($clear_queue) { - unset($_SESSION['messages'][$type]); + $messenger->deleteMessagesByType($type); } if (isset($messages[$type])) { return array($type => $messages[$type]); @@ -499,7 +494,7 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) { } else { if ($clear_queue) { - unset($_SESSION['messages']); + $messenger->deleteMessages(); } return $messages; } diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php index 873996b..3e9fac5 100644 --- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php @@ -6,6 +6,7 @@ use Drupal\Component\Utility\Xss; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Render\BareHtmlPageRendererInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\Session\AccountInterface; @@ -59,6 +60,13 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface { protected $bareHtmlPageRenderer; /** + * The messenger. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + + /** * Constructs a new MaintenanceModeSubscriber. * * @param \Drupal\Core\Site\MaintenanceModeInterface $maintenance_mode @@ -73,14 +81,17 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface { * The current user. * @param \Drupal\Core\Render\BareHtmlPageRendererInterface $bare_html_page_renderer * The bare HTML page renderer. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger. */ - public function __construct(MaintenanceModeInterface $maintenance_mode, ConfigFactoryInterface $config_factory, TranslationInterface $translation, UrlGeneratorInterface $url_generator, AccountInterface $account, BareHtmlPageRendererInterface $bare_html_page_renderer) { + public function __construct(MaintenanceModeInterface $maintenance_mode, ConfigFactoryInterface $config_factory, TranslationInterface $translation, UrlGeneratorInterface $url_generator, AccountInterface $account, BareHtmlPageRendererInterface $bare_html_page_renderer, MessengerInterface $messenger) { $this->maintenanceMode = $maintenance_mode; $this->config = $config_factory; $this->stringTranslation = $translation; $this->urlGenerator = $url_generator; $this->account = $account; $this->bareHtmlPageRenderer = $bare_html_page_renderer; + $this->messenger = $messenger; } /** @@ -111,10 +122,10 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) { // settings page. if ($route_match->getRouteName() != 'system.site_maintenance_mode') { if ($this->account->hasPermission('administer site configuration')) { - $this->drupalSetMessage($this->t('Operating in maintenance mode. Go online.', array(':url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE); + $this->messenger->addMessage($this->t('Operating in maintenance mode. Go online.', array('@url' => $this->urlGenerator->generate('system.site_maintenance_mode'))), 'status', FALSE); } else { - $this->drupalSetMessage($this->t('Operating in maintenance mode.'), 'status', FALSE); + $this->messenger->addMessage($this->t('Operating in maintenance mode.'), 'status', FALSE); } } } @@ -122,13 +133,6 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) { } /** - * Wraps the drupal_set_message function. - */ - protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) { - return drupal_set_message($message, $type, $repeat); - } - - /** * {@inheritdoc} */ public static function getSubscribedEvents() { diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php index 5603e4c..e2670b0 100644 --- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php +++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php @@ -34,6 +34,9 @@ public function register(ContainerBuilder $container) { ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueMemoryFactory'); $container ->register('keyvalue.expirable', 'Drupal\Core\KeyValueStore\KeyValueNullExpirableFactory'); + $definition = $container->getDefinition('messenger'); + $definition->setClass(StaticMessenger::class); + $definition->setArguments([new Reference('page_cache_kill_switch')]); // Replace services with no-op implementations. $container diff --git a/core/lib/Drupal/Core/Messenger/MessengerInterface.php b/core/lib/Drupal/Core/Messenger/MessengerInterface.php new file mode 100644 index 0000000..d9b7547 --- /dev/null +++ b/core/lib/Drupal/Core/Messenger/MessengerInterface.php @@ -0,0 +1,79 @@ +pageCacheKillSwitch = $page_cache_kill_switch; + $this->sessionManager = $session_manager; + } + + /** + * {@inheritdoc} + */ + public function addMessage($message, $type = self::STATUS, $repeat = FALSE) { + if (!isset($_SESSION['messages'][$type])) { + $_SESSION['messages'][$type] = []; + } + + // Convert strings which are safe to the simplest Markup objects. + if (!($message instanceof Markup) && $message instanceof MarkupInterface) { + $message = Markup::create((string) $message); + } + + // Do not use strict type checking so that equivalent string and + // MarkupInterface objects are detected. + if ($repeat || !in_array($message, $_SESSION['messages'][$type])) { + $_SESSION['messages'][$type][] = $message; + $this->pageCacheKillSwitch->trigger(); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getMessages() { + $messages = isset($_SESSION['messages']) ? $_SESSION['messages'] : []; + foreach ($messages as $type => $messages_by_type) { + $messages[$type] = $messages_by_type; + } + + return $messages; + } + + /** + * {@inheritdoc} + */ + public function getMessagesByType($type) { + $messages = isset($_SESSION['messages']) && isset($_SESSION['messages'][$type]) ? $_SESSION['messages'][$type] : []; + + return $messages; + } + + /** + * {@inheritdoc} + */ + public function deleteMessages() { + unset($_SESSION['messages']); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function deleteMessagesByType($type) { + unset($_SESSION['messages'][$type]); + + return $this; + } + +} diff --git a/core/lib/Drupal/Core/Messenger/StaticMessenger.php b/core/lib/Drupal/Core/Messenger/StaticMessenger.php new file mode 100644 index 0000000..52f7dcb --- /dev/null +++ b/core/lib/Drupal/Core/Messenger/StaticMessenger.php @@ -0,0 +1,104 @@ +pageCacheKillSwitch = $page_cache_kill_switch; + } + + /** + * {@inheritdoc} + */ + public function addMessage($message, $type = self::STATUS, $repeat = FALSE) { + if (!isset($this->messages[$type])) { + $this->messages[$type] = []; + } + + // Convert strings which are safe to the simplest Markup objects. + if (!($message instanceof Markup) && $message instanceof MarkupInterface) { + $message = Markup::create((string) $message); + } + + // Do not use strict type checking so that equivalent string and + // MarkupInterface objects are detected. + if ($repeat || !in_array($message, $this->messages[$type])) { + $this->messages[$type][] = $message; + $this->pageCacheKillSwitch->trigger(); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getMessages() { + $messages = isset($this->messages) ? $this->messages : []; + foreach ($messages as $type => $messages_by_type) { + $messages[$type] = $messages_by_type; + } + + return $messages; + } + + /** + * {@inheritdoc} + */ + public function getMessagesByType($type) { + $messages = isset($this->messages) && isset($this->messages[$type]) ? $this->messages[$type] : []; + + return $messages; + } + + /** + * {@inheritdoc} + */ + public function deleteMessages() { + unset($this->messages); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function deleteMessagesByType($type) { + unset($this->messages[$type]); + + return $this; + } + +} diff --git a/core/tests/Drupal/Tests/Core/Messenger/SessionMessengerTest.php b/core/tests/Drupal/Tests/Core/Messenger/SessionMessengerTest.php new file mode 100644 index 0000000..951ff10 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Messenger/SessionMessengerTest.php @@ -0,0 +1,110 @@ +pageCacheKillSwitch = $this->prophesize(KillSwitch::class); + $this->sessionManager = $this->prophesize(SessionManagerInterface::class); + + $this->existingSession = isset($_SESSION) ? $_SESSION : NULL; + $_SESSION = []; + } + + /** + * {@inheritdoc} + */ + public function tearDown() { + if ($this->existingSession !== NULL) { + $_SESSION = $this->existingSession; + } + else { + unset($_SESSION); + } + } + + /** + * @covers ::addMessage + * @covers ::getMessages + * @covers ::getMessagesByType + * @covers ::deleteMessages + * @covers ::deleteMessagesByType + */ + public function testMessenger() { + $this->pageCacheKillSwitch->trigger()->shouldBeCalled(); + + $this->sessionManager->start()->shouldBeCalled(); + $this->messenger = new SessionMessenger($this->sessionManager->reveal(), $this->pageCacheKillSwitch->reveal()); + + $message_a = $this->randomMachineName(); + $type_a = $this->randomMachineName(); + $message_b = $this->randomMachineName(); + $type_b = $this->randomMachineName(); + + // Test that if there are no messages, the default is an empty array. + $this->assertEquals($this->messenger->getMessages(), []); + + // Test that adding a message returns the messenger and that the message can + // be retrieved. + $this->assertEquals($this->messenger->addMessage($message_a, $type_a), $this->messenger); + $this->messenger->addMessage($message_a, $type_a); + $this->messenger->addMessage($message_a, $type_a, TRUE); + $this->messenger->addMessage($message_b, $type_b, TRUE); + $this->assertEquals($this->messenger->getMessages(), [ + $type_a => [$message_a, $message_a], + $type_b => [$message_b], + ]); + + // Test deleting messages of a certain type. + $this->assertEquals($this->messenger->deleteMessagesByType($type_a), $this->messenger); + $this->assertEquals($this->messenger->getMessages(), [ + $type_b => [$message_b], + ]); + + // Test deleting all messages. + $this->assertEquals($this->messenger->deleteMessages(), $this->messenger); + $this->assertEquals($this->messenger->getMessages(), []); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Messenger/StaticMessengerTest.php b/core/tests/Drupal/Tests/Core/Messenger/StaticMessengerTest.php new file mode 100644 index 0000000..d315895 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Messenger/StaticMessengerTest.php @@ -0,0 +1,80 @@ +pageCacheKillSwitch = $this->prophesize(KillSwitch::class); + } + + /** + * @covers ::addMessage + * @covers ::getMessages + * @covers ::getMessagesByType + * @covers ::deleteMessages + * @covers ::deleteMessagesByType + */ + public function testMessenger() { + $message_a = $this->randomMachineName(); + $type_a = $this->randomMachineName(); + $message_b = $this->randomMachineName(); + $type_b = $this->randomMachineName(); + + $this->pageCacheKillSwitch->trigger()->shouldBeCalled(); + + $this->messenger = new StaticMessenger($this->pageCacheKillSwitch->reveal()); + + // Test that if there are no messages, the default is an empty array. + $this->assertEquals($this->messenger->getMessages(), []); + + // Test that adding a message returns the messenger and that the message can + // be retrieved. + $this->assertSame($this->messenger->addMessage($message_a, $type_a), $this->messenger); + $this->messenger->addMessage($message_a, $type_a); + $this->messenger->addMessage($message_a, $type_a, TRUE); + $this->messenger->addMessage($message_b, $type_b, TRUE); + $this->assertEquals([ + $type_a => [$message_a, $message_a], + $type_b => [$message_b], + ], $this->messenger->getMessages()); + + // Test deleting messages of a certain type. + $this->assertEquals($this->messenger->deleteMessagesByType($type_a), $this->messenger); + $this->assertEquals([ + $type_b => [$message_b], + ], $this->messenger->getMessages()); + + // Test deleting all messages. + $this->assertEquals($this->messenger->deleteMessages(), $this->messenger); + $this->assertEquals([], $this->messenger->getMessages()); + } + +}