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