annotate vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\DependencyInjection\Compiler;
Chris@0 13
Chris@14 14 use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
Chris@17 15 use Symfony\Component\DependencyInjection\ContainerBuilder;
Chris@14 16 use Symfony\Component\DependencyInjection\ContainerInterface;
Chris@0 17 use Symfony\Component\DependencyInjection\Definition;
Chris@14 18 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
Chris@12 19 use Symfony\Component\DependencyInjection\ExpressionLanguage;
Chris@0 20 use Symfony\Component\DependencyInjection\Reference;
Chris@12 21 use Symfony\Component\ExpressionLanguage\Expression;
Chris@0 22
Chris@0 23 /**
Chris@0 24 * Run this pass before passes that need to know more about the relation of
Chris@0 25 * your services.
Chris@0 26 *
Chris@0 27 * This class will populate the ServiceReferenceGraph with information. You can
Chris@0 28 * retrieve the graph in other passes from the compiler.
Chris@0 29 *
Chris@0 30 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
Chris@0 31 */
Chris@14 32 class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface
Chris@0 33 {
Chris@0 34 private $graph;
Chris@0 35 private $currentDefinition;
Chris@0 36 private $onlyConstructorArguments;
Chris@17 37 private $hasProxyDumper;
Chris@14 38 private $lazy;
Chris@12 39 private $expressionLanguage;
Chris@17 40 private $byConstructor;
Chris@0 41
Chris@0 42 /**
Chris@0 43 * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
Chris@0 44 */
Chris@17 45 public function __construct($onlyConstructorArguments = false, $hasProxyDumper = true)
Chris@0 46 {
Chris@0 47 $this->onlyConstructorArguments = (bool) $onlyConstructorArguments;
Chris@17 48 $this->hasProxyDumper = (bool) $hasProxyDumper;
Chris@0 49 }
Chris@0 50
Chris@0 51 /**
Chris@0 52 * {@inheritdoc}
Chris@0 53 */
Chris@0 54 public function setRepeatedPass(RepeatedPass $repeatedPass)
Chris@0 55 {
Chris@14 56 // no-op for BC
Chris@0 57 }
Chris@0 58
Chris@0 59 /**
Chris@0 60 * Processes a ContainerBuilder object to populate the service reference graph.
Chris@0 61 */
Chris@0 62 public function process(ContainerBuilder $container)
Chris@0 63 {
Chris@0 64 $this->container = $container;
Chris@0 65 $this->graph = $container->getCompiler()->getServiceReferenceGraph();
Chris@0 66 $this->graph->clear();
Chris@14 67 $this->lazy = false;
Chris@17 68 $this->byConstructor = false;
Chris@0 69
Chris@14 70 foreach ($container->getAliases() as $id => $alias) {
Chris@14 71 $targetId = $this->getDefinitionId((string) $alias);
Chris@14 72 $this->graph->connect($id, $alias, $targetId, $this->getDefinition($targetId), null);
Chris@0 73 }
Chris@0 74
Chris@14 75 parent::process($container);
Chris@0 76 }
Chris@0 77
Chris@14 78 protected function processValue($value, $isRoot = false)
Chris@0 79 {
Chris@14 80 $lazy = $this->lazy;
Chris@0 81
Chris@14 82 if ($value instanceof ArgumentInterface) {
Chris@14 83 $this->lazy = true;
Chris@14 84 parent::processValue($value->getValues());
Chris@14 85 $this->lazy = $lazy;
Chris@14 86
Chris@14 87 return $value;
Chris@14 88 }
Chris@14 89 if ($value instanceof Expression) {
Chris@17 90 $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']);
Chris@14 91
Chris@14 92 return $value;
Chris@14 93 }
Chris@14 94 if ($value instanceof Reference) {
Chris@14 95 $targetId = $this->getDefinitionId((string) $value);
Chris@14 96 $targetDefinition = $this->getDefinition($targetId);
Chris@14 97
Chris@14 98 $this->graph->connect(
Chris@14 99 $this->currentId,
Chris@14 100 $this->currentDefinition,
Chris@14 101 $targetId,
Chris@14 102 $targetDefinition,
Chris@14 103 $value,
Chris@17 104 $this->lazy || ($this->hasProxyDumper && $targetDefinition && $targetDefinition->isLazy()),
Chris@17 105 ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior(),
Chris@17 106 $this->byConstructor
Chris@14 107 );
Chris@14 108
Chris@14 109 return $value;
Chris@14 110 }
Chris@14 111 if (!$value instanceof Definition) {
Chris@14 112 return parent::processValue($value, $isRoot);
Chris@14 113 }
Chris@14 114 if ($isRoot) {
Chris@14 115 if ($value->isSynthetic() || $value->isAbstract()) {
Chris@14 116 return $value;
Chris@0 117 }
Chris@14 118 $this->currentDefinition = $value;
Chris@17 119 } elseif ($this->currentDefinition === $value) {
Chris@17 120 return $value;
Chris@0 121 }
Chris@14 122 $this->lazy = false;
Chris@14 123
Chris@17 124 $byConstructor = $this->byConstructor;
Chris@17 125 $this->byConstructor = true;
Chris@14 126 $this->processValue($value->getFactory());
Chris@14 127 $this->processValue($value->getArguments());
Chris@17 128 $this->byConstructor = $byConstructor;
Chris@14 129
Chris@14 130 if (!$this->onlyConstructorArguments) {
Chris@14 131 $this->processValue($value->getProperties());
Chris@14 132 $this->processValue($value->getMethodCalls());
Chris@14 133 $this->processValue($value->getConfigurator());
Chris@14 134 }
Chris@14 135 $this->lazy = $lazy;
Chris@14 136
Chris@14 137 return $value;
Chris@0 138 }
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Returns a service definition given the full name or an alias.
Chris@0 142 *
Chris@0 143 * @param string $id A full id or alias for a service definition
Chris@0 144 *
Chris@0 145 * @return Definition|null The definition related to the supplied id
Chris@0 146 */
Chris@0 147 private function getDefinition($id)
Chris@0 148 {
Chris@0 149 return null === $id ? null : $this->container->getDefinition($id);
Chris@0 150 }
Chris@0 151
Chris@0 152 private function getDefinitionId($id)
Chris@0 153 {
Chris@0 154 while ($this->container->hasAlias($id)) {
Chris@0 155 $id = (string) $this->container->getAlias($id);
Chris@0 156 }
Chris@0 157
Chris@0 158 if (!$this->container->hasDefinition($id)) {
Chris@0 159 return;
Chris@0 160 }
Chris@0 161
Chris@14 162 return $this->container->normalizeId($id);
Chris@0 163 }
Chris@12 164
Chris@12 165 private function getExpressionLanguage()
Chris@12 166 {
Chris@12 167 if (null === $this->expressionLanguage) {
Chris@14 168 if (!class_exists(ExpressionLanguage::class)) {
Chris@14 169 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
Chris@14 170 }
Chris@14 171
Chris@12 172 $providers = $this->container->getExpressionLanguageProviders();
Chris@12 173 $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
Chris@12 174 if ('""' === substr_replace($arg, '', 1, -1)) {
Chris@12 175 $id = stripcslashes(substr($arg, 1, -1));
Chris@14 176 $id = $this->getDefinitionId($id);
Chris@12 177
Chris@12 178 $this->graph->connect(
Chris@12 179 $this->currentId,
Chris@12 180 $this->currentDefinition,
Chris@14 181 $id,
Chris@12 182 $this->getDefinition($id)
Chris@12 183 );
Chris@12 184 }
Chris@12 185
Chris@12 186 return sprintf('$this->get(%s)', $arg);
Chris@12 187 });
Chris@12 188 }
Chris@12 189
Chris@12 190 return $this->expressionLanguage;
Chris@12 191 }
Chris@0 192 }