1<?php 2 3/** 4 * @file 5 * Contains \Drupal. 6 */ 7 8use Drupal\Core\DependencyInjection\ContainerNotInitializedException; 9use Drupal\Core\Messenger\LegacyMessenger; 10use Drupal\Core\Url; 11use Symfony\Component\DependencyInjection\ContainerInterface; 12 13/** 14 * Static Service Container wrapper. 15 * 16 * Generally, code in Drupal should accept its dependencies via either 17 * constructor injection or setter method injection. However, there are cases, 18 * particularly in legacy procedural code, where that is infeasible. This 19 * class acts as a unified global accessor to arbitrary services within the 20 * system in order to ease the transition from procedural code to injected OO 21 * code. 22 * 23 * The container is built by the kernel and passed in to this class which stores 24 * it statically. The container always contains the services from 25 * \Drupal\Core\CoreServiceProvider, the service providers of enabled modules and any other 26 * service providers defined in $GLOBALS['conf']['container_service_providers']. 27 * 28 * This class exists only to support legacy code that cannot be dependency 29 * injected. If your code needs it, consider refactoring it to be object 30 * oriented, if possible. When this is not possible, for instance in the case of 31 * hook implementations, and your code is more than a few non-reusable lines, it 32 * is recommended to instantiate an object implementing the actual logic. 33 * 34 * @code 35 * // Legacy procedural code. 36 * function hook_do_stuff() { 37 * $lock = lock()->acquire('stuff_lock'); 38 * // ... 39 * } 40 * 41 * // Correct procedural code. 42 * function hook_do_stuff() { 43 * $lock = \Drupal::lock()->acquire('stuff_lock'); 44 * // ... 45 * } 46 * 47 * // The preferred way: dependency injected code. 48 * function hook_do_stuff() { 49 * // Move the actual implementation to a class and instantiate it. 50 * $instance = new StuffDoingClass(\Drupal::lock()); 51 * $instance->doStuff(); 52 * 53 * // Or, even better, rely on the service container to avoid hard coding a 54 * // specific interface implementation, so that the actual logic can be 55 * // swapped. This might not always make sense, but in general it is a good 56 * // practice. 57 * \Drupal::service('stuff.doing')->doStuff(); 58 * } 59 * 60 * interface StuffDoingInterface { 61 * public function doStuff(); 62 * } 63 * 64 * class StuffDoingClass implements StuffDoingInterface { 65 * protected $lockBackend; 66 * 67 * public function __construct(LockBackendInterface $lock_backend) { 68 * $this->lockBackend = $lock_backend; 69 * } 70 * 71 * public function doStuff() { 72 * $lock = $this->lockBackend->acquire('stuff_lock'); 73 * // ... 74 * } 75 * } 76 * @endcode 77 * 78 * @see \Drupal\Core\DrupalKernel 79 */ 80class Drupal { 81 82 /** 83 * The current system version. 84 */ 85 const VERSION = '8.9.20'; 86 87 /** 88 * Core API compatibility. 89 */ 90 const CORE_COMPATIBILITY = '8.x'; 91 92 /** 93 * Core minimum schema version. 94 */ 95 const CORE_MINIMUM_SCHEMA_VERSION = 8000; 96 97 /** 98 * The currently active container object, or NULL if not initialized yet. 99 * 100 * @var \Symfony\Component\DependencyInjection\ContainerInterface|null 101 */ 102 protected static $container; 103 104 /** 105 * Sets a new global container. 106 * 107 * @param \Symfony\Component\DependencyInjection\ContainerInterface $container 108 * A new container instance to replace the current. 109 */ 110 public static function setContainer(ContainerInterface $container) { 111 static::$container = $container; 112 } 113 114 /** 115 * Unsets the global container. 116 */ 117 public static function unsetContainer() { 118 static::$container = NULL; 119 } 120 121 /** 122 * Returns the currently active global container. 123 * 124 * @return \Symfony\Component\DependencyInjection\ContainerInterface 125 * 126 * @throws \Drupal\Core\DependencyInjection\ContainerNotInitializedException 127 */ 128 public static function getContainer() { 129 if (static::$container === NULL) { 130 throw new ContainerNotInitializedException('\Drupal::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.'); 131 } 132 return static::$container; 133 } 134 135 /** 136 * Returns TRUE if the container has been initialized, FALSE otherwise. 137 * 138 * @return bool 139 */ 140 public static function hasContainer() { 141 return static::$container !== NULL; 142 } 143 144 /** 145 * Retrieves a service from the container. 146 * 147 * Use this method if the desired service is not one of those with a dedicated 148 * accessor method below. If it is listed below, those methods are preferred 149 * as they can return useful type hints. 150 * 151 * @param string $id 152 * The ID of the service to retrieve. 153 * 154 * @return mixed 155 * The specified service. 156 */ 157 public static function service($id) { 158 return static::getContainer()->get($id); 159 } 160 161 /** 162 * Indicates if a service is defined in the container. 163 * 164 * @param string $id 165 * The ID of the service to check. 166 * 167 * @return bool 168 * TRUE if the specified service exists, FALSE otherwise. 169 */ 170 public static function hasService($id) { 171 // Check hasContainer() first in order to always return a Boolean. 172 return static::hasContainer() && static::getContainer()->has($id); 173 } 174 175 /** 176 * Gets the app root. 177 * 178 * @return string 179 */ 180 public static function root() { 181 return static::getContainer()->get('app.root'); 182 } 183 184 /** 185 * Gets the active install profile. 186 * 187 * @return string|null 188 * The name of the active install profile. 189 */ 190 public static function installProfile() { 191 return static::getContainer()->getParameter('install_profile'); 192 } 193 194 /** 195 * Indicates if there is a currently active request object. 196 * 197 * @return bool 198 * TRUE if there is a currently active request object, FALSE otherwise. 199 */ 200 public static function hasRequest() { 201 // Check hasContainer() first in order to always return a Boolean. 202 return static::hasContainer() && static::getContainer()->has('request_stack') && static::getContainer()->get('request_stack')->getCurrentRequest() !== NULL; 203 } 204 205 /** 206 * Retrieves the currently active request object. 207 * 208 * Note: The use of this wrapper in particular is especially discouraged. Most 209 * code should not need to access the request directly. Doing so means it 210 * will only function when handling an HTTP request, and will require special 211 * modification or wrapping when run from a command line tool, from certain 212 * queue processors, or from automated tests. 213 * 214 * If code must access the request, it is considerably better to register 215 * an object with the Service Container and give it a setRequest() method 216 * that is configured to run when the service is created. That way, the 217 * correct request object can always be provided by the container and the 218 * service can still be unit tested. 219 * 220 * If this method must be used, never save the request object that is 221 * returned. Doing so may lead to inconsistencies as the request object is 222 * volatile and may change at various times, such as during a subrequest. 223 * 224 * @return \Symfony\Component\HttpFoundation\Request 225 * The currently active request object. 226 */ 227 public static function request() { 228 return static::getContainer()->get('request_stack')->getCurrentRequest(); 229 } 230 231 /** 232 * Retrieves the request stack. 233 * 234 * @return \Symfony\Component\HttpFoundation\RequestStack 235 * The request stack 236 */ 237 public static function requestStack() { 238 return static::getContainer()->get('request_stack'); 239 } 240 241 /** 242 * Retrieves the currently active route match object. 243 * 244 * @return \Drupal\Core\Routing\RouteMatchInterface 245 * The currently active route match object. 246 */ 247 public static function routeMatch() { 248 return static::getContainer()->get('current_route_match'); 249 } 250 251 /** 252 * Gets the current active user. 253 * 254 * This method will return the \Drupal\Core\Session\AccountProxy object of the 255 * current user. You can use the \Drupal\user\Entity\User::load() method to 256 * load the full user entity object. For example: 257 * @code 258 * $user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id()); 259 * @endcode 260 * 261 * @return \Drupal\Core\Session\AccountProxyInterface 262 */ 263 public static function currentUser() { 264 return static::getContainer()->get('current_user'); 265 } 266 267 /** 268 * Retrieves the entity manager service. 269 * 270 * @return \Drupal\Core\Entity\EntityManagerInterface 271 * The entity manager service. 272 * 273 * @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. 274 * Use \Drupal::entityTypeManager() instead in most cases. If the needed 275 * method is not on \Drupal\Core\Entity\EntityTypeManagerInterface, see the 276 * deprecated \Drupal\Core\Entity\EntityManager to find the 277 * correct interface or service. 278 */ 279 public static function entityManager() { 280 @trigger_error("\Drupal::entityManager() is deprecated in Drupal 8.0.0 and will be removed before Drupal 9.0.0. Use \Drupal::entityTypeManager() instead in most cases. If the needed method is not on \Drupal\Core\Entity\EntityTypeManagerInterface, see the deprecated \Drupal\Core\Entity\EntityManager to find the correct interface or service. See https://www.drupal.org/node/2549139", E_USER_DEPRECATED); 281 return static::getContainer()->get('entity.manager'); 282 } 283 284 /** 285 * Retrieves the entity type manager. 286 * 287 * @return \Drupal\Core\Entity\EntityTypeManagerInterface 288 * The entity type manager. 289 */ 290 public static function entityTypeManager() { 291 return static::getContainer()->get('entity_type.manager'); 292 } 293 294 /** 295 * Returns the current primary database. 296 * 297 * @return \Drupal\Core\Database\Connection 298 * The current active database's master connection. 299 */ 300 public static function database() { 301 return static::getContainer()->get('database'); 302 } 303 304 /** 305 * Returns the requested cache bin. 306 * 307 * @param string $bin 308 * (optional) The cache bin for which the cache object should be returned, 309 * defaults to 'default'. 310 * 311 * @return \Drupal\Core\Cache\CacheBackendInterface 312 * The cache object associated with the specified bin. 313 * 314 * @ingroup cache 315 */ 316 public static function cache($bin = 'default') { 317 return static::getContainer()->get('cache.' . $bin); 318 } 319 320 /** 321 * Retrieves the class resolver. 322 * 323 * This is to be used in procedural code such as module files to instantiate 324 * an object of a class that implements 325 * \Drupal\Core\DependencyInjection\ContainerInjectionInterface. 326 * 327 * One common usecase is to provide a class which contains the actual code 328 * of a hook implementation, without having to create a service. 329 * 330 * @param string $class 331 * (optional) A class name to instantiate. 332 * 333 * @return \Drupal\Core\DependencyInjection\ClassResolverInterface|object 334 * The class resolver or if $class is provided, a class instance with a 335 * given class definition. 336 * 337 * @throws \InvalidArgumentException 338 * If $class does not exist. 339 */ 340 public static function classResolver($class = NULL) { 341 if ($class) { 342 return static::getContainer()->get('class_resolver')->getInstanceFromDefinition($class); 343 } 344 return static::getContainer()->get('class_resolver'); 345 } 346 347 /** 348 * Returns an expirable key value store collection. 349 * 350 * @param string $collection 351 * The name of the collection holding key and value pairs. 352 * 353 * @return \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface 354 * An expirable key value store collection. 355 */ 356 public static function keyValueExpirable($collection) { 357 return static::getContainer()->get('keyvalue.expirable')->get($collection); 358 } 359 360 /** 361 * Returns the locking layer instance. 362 * 363 * @return \Drupal\Core\Lock\LockBackendInterface 364 * 365 * @ingroup lock 366 */ 367 public static function lock() { 368 return static::getContainer()->get('lock'); 369 } 370 371 /** 372 * Retrieves a configuration object. 373 * 374 * This is the main entry point to the configuration API. Calling 375 * @code \Drupal::config('book.admin') @endcode will return a configuration 376 * object the Book module can use to read its administrative settings. 377 * 378 * @param string $name 379 * The name of the configuration object to retrieve, which typically 380 * corresponds to a configuration file. For 381 * @code \Drupal::config('book.admin') @endcode, the configuration 382 * object returned will contain the content of the book.admin 383 * configuration file. 384 * 385 * @return \Drupal\Core\Config\ImmutableConfig 386 * An immutable configuration object. 387 */ 388 public static function config($name) { 389 return static::getContainer()->get('config.factory')->get($name); 390 } 391 392 /** 393 * Retrieves the configuration factory. 394 * 395 * This is mostly used to change the override settings on the configuration 396 * factory. For example, changing the language, or turning all overrides on 397 * or off. 398 * 399 * @return \Drupal\Core\Config\ConfigFactoryInterface 400 * The configuration factory service. 401 */ 402 public static function configFactory() { 403 return static::getContainer()->get('config.factory'); 404 } 405 406 /** 407 * Returns a queue for the given queue name. 408 * 409 * The following values can be set in your settings.php file's $settings 410 * array to define which services are used for queues: 411 * - queue_reliable_service_$name: The container service to use for the 412 * reliable queue $name. 413 * - queue_service_$name: The container service to use for the 414 * queue $name. 415 * - queue_default: The container service to use by default for queues 416 * without overrides. This defaults to 'queue.database'. 417 * 418 * @param string $name 419 * The name of the queue to work with. 420 * @param bool $reliable 421 * (optional) TRUE if the ordering of items and guaranteeing every item 422 * executes at least once is important, FALSE if scalability is the main 423 * concern. Defaults to FALSE. 424 * 425 * @return \Drupal\Core\Queue\QueueInterface 426 * The queue object for a given name. 427 */ 428 public static function queue($name, $reliable = FALSE) { 429 return static::getContainer()->get('queue')->get($name, $reliable); 430 } 431 432 /** 433 * Returns a key/value storage collection. 434 * 435 * @param string $collection 436 * Name of the key/value collection to return. 437 * 438 * @return \Drupal\Core\KeyValueStore\KeyValueStoreInterface 439 */ 440 public static function keyValue($collection) { 441 return static::getContainer()->get('keyvalue')->get($collection); 442 } 443 444 /** 445 * Returns the state storage service. 446 * 447 * Use this to store machine-generated data, local to a specific environment 448 * that does not need deploying and does not need human editing; for example, 449 * the last time cron was run. Data which needs to be edited by humans and 450 * needs to be the same across development, production, etc. environments 451 * (for example, the system maintenance message) should use \Drupal::config() instead. 452 * 453 * @return \Drupal\Core\State\StateInterface 454 */ 455 public static function state() { 456 return static::getContainer()->get('state'); 457 } 458 459 /** 460 * Returns the default http client. 461 * 462 * @return \GuzzleHttp\Client 463 * A guzzle http client instance. 464 */ 465 public static function httpClient() { 466 return static::getContainer()->get('http_client'); 467 } 468 469 /** 470 * Returns the entity query object for this entity type. 471 * 472 * @param string $entity_type 473 * The entity type (for example, node) for which the query object should be 474 * returned. 475 * @param string $conjunction 476 * (optional) Either 'AND' if all conditions in the query need to apply, or 477 * 'OR' if any of them is sufficient. Defaults to 'AND'. 478 * 479 * @return \Drupal\Core\Entity\Query\QueryInterface 480 * The query object that can query the given entity type. 481 */ 482 public static function entityQuery($entity_type, $conjunction = 'AND') { 483 return static::entityTypeManager()->getStorage($entity_type)->getQuery($conjunction); 484 } 485 486 /** 487 * Returns the entity query aggregate object for this entity type. 488 * 489 * @param string $entity_type 490 * The entity type (for example, node) for which the query object should be 491 * returned. 492 * @param string $conjunction 493 * (optional) Either 'AND' if all conditions in the query need to apply, or 494 * 'OR' if any of them is sufficient. Defaults to 'AND'. 495 * 496 * @return \Drupal\Core\Entity\Query\QueryAggregateInterface 497 * The query object that can query the given entity type. 498 */ 499 public static function entityQueryAggregate($entity_type, $conjunction = 'AND') { 500 return static::entityTypeManager()->getStorage($entity_type)->getAggregateQuery($conjunction); 501 } 502 503 /** 504 * Returns the flood instance. 505 * 506 * @return \Drupal\Core\Flood\FloodInterface 507 */ 508 public static function flood() { 509 return static::getContainer()->get('flood'); 510 } 511 512 /** 513 * Returns the module handler. 514 * 515 * @return \Drupal\Core\Extension\ModuleHandlerInterface 516 */ 517 public static function moduleHandler() { 518 return static::getContainer()->get('module_handler'); 519 } 520 521 /** 522 * Returns the typed data manager service. 523 * 524 * Use the typed data manager service for creating typed data objects. 525 * 526 * @return \Drupal\Core\TypedData\TypedDataManagerInterface 527 * The typed data manager. 528 * 529 * @see \Drupal\Core\TypedData\TypedDataManager::create() 530 */ 531 public static function typedDataManager() { 532 return static::getContainer()->get('typed_data_manager'); 533 } 534 535 /** 536 * Returns the token service. 537 * 538 * @return \Drupal\Core\Utility\Token 539 * The token service. 540 */ 541 public static function token() { 542 return static::getContainer()->get('token'); 543 } 544 545 /** 546 * Returns the url generator service. 547 * 548 * @return \Drupal\Core\Routing\UrlGeneratorInterface 549 * The url generator service. 550 */ 551 public static function urlGenerator() { 552 return static::getContainer()->get('url_generator'); 553 } 554 555 /** 556 * Generates a URL string for a specific route based on the given parameters. 557 * 558 * This method is a convenience wrapper for generating URL strings for URLs 559 * that have Drupal routes (that is, most pages generated by Drupal) using 560 * the \Drupal\Core\Url object. See \Drupal\Core\Url::fromRoute() for 561 * detailed documentation. For non-routed local URIs relative to 562 * the base path (like robots.txt) use Url::fromUri()->toString() with the 563 * base: scheme. 564 * 565 * @param string $route_name 566 * The name of the route. 567 * @param array $route_parameters 568 * (optional) An associative array of parameter names and values. 569 * @param array $options 570 * (optional) An associative array of additional options. 571 * @param bool $collect_bubbleable_metadata 572 * (optional) Defaults to FALSE. When TRUE, both the generated URL and its 573 * associated bubbleable metadata are returned. 574 * 575 * @return string|\Drupal\Core\GeneratedUrl 576 * A string containing a URL to the given path. 577 * When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is 578 * returned, containing the generated URL plus bubbleable metadata. 579 * 580 * @see \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() 581 * @see \Drupal\Core\Url 582 * @see \Drupal\Core\Url::fromRoute() 583 * @see \Drupal\Core\Url::fromUri() 584 * 585 * @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. 586 * Instead create a \Drupal\Core\Url object directly, for example using 587 * Url::fromRoute(). 588 */ 589 public static function url($route_name, $route_parameters = [], $options = [], $collect_bubbleable_metadata = FALSE) { 590 @trigger_error('Drupal::url() is deprecated as of Drupal 8.0.x, will be removed before Drupal 9.0.0. Instead create a \Drupal\Core\Url object directly, for example using Url::fromRoute()', E_USER_DEPRECATED); 591 return static::getContainer()->get('url_generator')->generateFromRoute($route_name, $route_parameters, $options, $collect_bubbleable_metadata); 592 } 593 594 /** 595 * Returns the link generator service. 596 * 597 * @return \Drupal\Core\Utility\LinkGeneratorInterface 598 */ 599 public static function linkGenerator() { 600 return static::getContainer()->get('link_generator'); 601 } 602 603 /** 604 * Renders a link with a given link text and Url object. 605 * 606 * This method is a convenience wrapper for the link generator service's 607 * generate() method. 608 * 609 * @param string|array|\Drupal\Component\Render\MarkupInterface $text 610 * The link text for the anchor tag as a translated string or render array. 611 * @param \Drupal\Core\Url $url 612 * The URL object used for the link. 613 * 614 * @return \Drupal\Core\GeneratedLink 615 * A GeneratedLink object containing a link to the given route and 616 * parameters and bubbleable metadata. 617 * 618 * @deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use 619 * \Drupal\Core\Link::fromTextAndUrl() instead. 620 * 621 * @see https://www.drupal.org/node/2614344 622 * @see \Drupal\Core\Utility\LinkGeneratorInterface::generate() 623 * @see \Drupal\Core\Url 624 */ 625 public static function l($text, Url $url) { 626 @trigger_error('\Drupal::l() is deprecated in drupal:8.0.0 and is removed from drupal:9.0.0. Use \Drupal\Core\Link::fromTextAndUrl() instead. See https://www.drupal.org/node/2614344', E_USER_DEPRECATED); 627 return static::getContainer()->get('link_generator')->generate($text, $url); 628 } 629 630 /** 631 * Returns the string translation service. 632 * 633 * @return \Drupal\Core\StringTranslation\TranslationManager 634 * The string translation manager. 635 */ 636 public static function translation() { 637 return static::getContainer()->get('string_translation'); 638 } 639 640 /** 641 * Returns the language manager service. 642 * 643 * @return \Drupal\Core\Language\LanguageManagerInterface 644 * The language manager. 645 */ 646 public static function languageManager() { 647 return static::getContainer()->get('language_manager'); 648 } 649 650 /** 651 * Returns the CSRF token manager service. 652 * 653 * The generated token is based on the session ID of the current user. Normally, 654 * anonymous users do not have a session, so the generated token will be 655 * different on every page request. To generate a token for users without a 656 * session, manually start a session prior to calling this function. 657 * 658 * @return \Drupal\Core\Access\CsrfTokenGenerator 659 * The CSRF token manager. 660 * 661 * @see \Drupal\Core\Session\SessionManager::start() 662 */ 663 public static function csrfToken() { 664 return static::getContainer()->get('csrf_token'); 665 } 666 667 /** 668 * Returns the transliteration service. 669 * 670 * @return \Drupal\Core\Transliteration\PhpTransliteration 671 * The transliteration manager. 672 */ 673 public static function transliteration() { 674 return static::getContainer()->get('transliteration'); 675 } 676 677 /** 678 * Returns the form builder service. 679 * 680 * @return \Drupal\Core\Form\FormBuilderInterface 681 * The form builder. 682 */ 683 public static function formBuilder() { 684 return static::getContainer()->get('form_builder'); 685 } 686 687 /** 688 * Gets the theme service. 689 * 690 * @return \Drupal\Core\Theme\ThemeManagerInterface 691 */ 692 public static function theme() { 693 return static::getContainer()->get('theme.manager'); 694 } 695 696 /** 697 * Gets the syncing state. 698 * 699 * @return bool 700 * Returns TRUE is syncing flag set. 701 */ 702 public static function isConfigSyncing() { 703 return static::getContainer()->get('config.installer')->isSyncing(); 704 } 705 706 /** 707 * Returns a channel logger object. 708 * 709 * @param string $channel 710 * The name of the channel. Can be any string, but the general practice is 711 * to use the name of the subsystem calling this. 712 * 713 * @return \Psr\Log\LoggerInterface 714 * The logger for this channel. 715 */ 716 public static function logger($channel) { 717 return static::getContainer()->get('logger.factory')->get($channel); 718 } 719 720 /** 721 * Returns the menu tree. 722 * 723 * @return \Drupal\Core\Menu\MenuLinkTreeInterface 724 * The menu tree. 725 */ 726 public static function menuTree() { 727 return static::getContainer()->get('menu.link_tree'); 728 } 729 730 /** 731 * Returns the path validator. 732 * 733 * @return \Drupal\Core\Path\PathValidatorInterface 734 */ 735 public static function pathValidator() { 736 return static::getContainer()->get('path.validator'); 737 } 738 739 /** 740 * Returns the access manager service. 741 * 742 * @return \Drupal\Core\Access\AccessManagerInterface 743 * The access manager service. 744 */ 745 public static function accessManager() { 746 return static::getContainer()->get('access_manager'); 747 } 748 749 /** 750 * Returns the redirect destination helper. 751 * 752 * @return \Drupal\Core\Routing\RedirectDestinationInterface 753 * The redirect destination helper. 754 */ 755 public static function destination() { 756 return static::getContainer()->get('redirect.destination'); 757 } 758 759 /** 760 * Returns the entity definition update manager. 761 * 762 * @return \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface 763 * The entity definition update manager. 764 */ 765 public static function entityDefinitionUpdateManager() { 766 return static::getContainer()->get('entity.definition_update_manager'); 767 } 768 769 /** 770 * Returns the time service. 771 * 772 * @return \Drupal\Component\Datetime\TimeInterface 773 * The time service. 774 */ 775 public static function time() { 776 return static::getContainer()->get('datetime.time'); 777 } 778 779 /** 780 * Returns the messenger. 781 * 782 * @return \Drupal\Core\Messenger\MessengerInterface 783 * The messenger. 784 */ 785 public static function messenger() { 786 // @todo Replace with service once LegacyMessenger is removed in 9.0.0. 787 // @see https://www.drupal.org/node/2928994 788 return new LegacyMessenger(); 789 } 790 791} 792