ContainerBuilder.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. // @codingStandardsIgnoreFile
  3. namespace Drupal\Core\DependencyInjection;
  4. use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder;
  5. use Symfony\Component\DependencyInjection\Container as SymfonyContainer;
  6. use Symfony\Component\DependencyInjection\Definition;
  7. use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
  8. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  9. /**
  10. * Drupal's dependency injection container builder.
  11. *
  12. * @todo Submit upstream patches to Symfony to not require these overrides.
  13. *
  14. * @ingroup container
  15. */
  16. class ContainerBuilder extends SymfonyContainerBuilder {
  17. /**
  18. * @var \Doctrine\Instantiator\InstantiatorInterface|null
  19. */
  20. private $proxyInstantiator;
  21. /**
  22. * {@inheritdoc}
  23. */
  24. public function __construct(ParameterBagInterface $parameterBag = NULL) {
  25. parent::__construct($parameterBag);
  26. $this->setResourceTracking(FALSE);
  27. }
  28. /**
  29. * Retrieves the currently set proxy instantiator or instantiates one.
  30. *
  31. * @return InstantiatorInterface
  32. */
  33. private function getProxyInstantiator()
  34. {
  35. if (!$this->proxyInstantiator) {
  36. $this->proxyInstantiator = new RealServiceInstantiator();
  37. }
  38. return $this->proxyInstantiator;
  39. }
  40. /**
  41. * A 1to1 copy of parent::shareService.
  42. *
  43. * @todo https://www.drupal.org/project/drupal/issues/2937010 Since Symfony
  44. * 3.4 this is not a 1to1 copy.
  45. */
  46. protected function shareService(Definition $definition, $service, $id, array &$inlineServices)
  47. {
  48. if ($definition->isShared()) {
  49. $this->services[$lowerId = strtolower($id)] = $service;
  50. }
  51. }
  52. /**
  53. * Overrides Symfony\Component\DependencyInjection\ContainerBuilder::set().
  54. *
  55. * Drupal's container builder can be used at runtime after compilation, so we
  56. * override Symfony's ContainerBuilder's restriction on setting services in a
  57. * frozen builder.
  58. *
  59. * @todo Restrict this to synthetic services only. Ideally, the upstream
  60. * ContainerBuilder class should be fixed to allow setting synthetic
  61. * services in a frozen builder.
  62. */
  63. public function set($id, $service) {
  64. if (strtolower($id) !== $id) {
  65. throw new \InvalidArgumentException("Service ID names must be lowercase: $id");
  66. }
  67. SymfonyContainer::set($id, $service);
  68. // Ensure that the _serviceId property is set on synthetic services as well.
  69. if (isset($this->services[$id]) && is_object($this->services[$id]) && !isset($this->services[$id]->_serviceId)) {
  70. $this->services[$id]->_serviceId = $id;
  71. }
  72. }
  73. /**
  74. * {@inheritdoc}
  75. */
  76. public function register($id, $class = null) {
  77. if (strtolower($id) !== $id) {
  78. throw new \InvalidArgumentException("Service ID names must be lowercase: $id");
  79. }
  80. return parent::register($id, $class);
  81. }
  82. /**
  83. * {@inheritdoc}
  84. */
  85. public function setAlias($alias, $id) {
  86. $alias = parent::setAlias($alias, $id);
  87. // As of Symfony 3.4 all aliases are private by default.
  88. $alias->setPublic(TRUE);
  89. return $alias;
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function setDefinition($id, Definition $definition) {
  95. $definition = parent::setDefinition($id, $definition);
  96. // As of Symfony 3.4 all definitions are private by default.
  97. // \Symfony\Component\DependencyInjection\Compiler\ResolvePrivatesPassOnly
  98. // removes services marked as private from the container even if they are
  99. // also marked as public. Drupal requires services that are public to
  100. // remain in the container and not be removed.
  101. if ($definition->isPublic()) {
  102. $definition->setPrivate(FALSE);
  103. }
  104. return $definition;
  105. }
  106. /**
  107. * {@inheritdoc}
  108. */
  109. public function setParameter($name, $value) {
  110. if (strtolower($name) !== $name) {
  111. throw new \InvalidArgumentException("Parameter names must be lowercase: $name");
  112. }
  113. parent::setParameter($name, $value);
  114. }
  115. /**
  116. * A 1to1 copy of parent::callMethod.
  117. *
  118. * @todo https://www.drupal.org/project/drupal/issues/2937010 Since Symfony
  119. * 3.4 this is not a 1to1 copy.
  120. */
  121. protected function callMethod($service, $call, array &$inlineServices = array()) {
  122. $services = self::getServiceConditionals($call[1]);
  123. foreach ($services as $s) {
  124. if (!$this->has($s)) {
  125. return;
  126. }
  127. }
  128. call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1])));
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function __sleep() {
  134. assert(FALSE, 'The container was serialized.');
  135. return array_keys(get_object_vars($this));
  136. }
  137. }