4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Compiler;
14 use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
15 use Symfony\Component\DependencyInjection\ContainerInterface;
16 use Symfony\Component\DependencyInjection\Definition;
17 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18 use Symfony\Component\DependencyInjection\ExpressionLanguage;
19 use Symfony\Component\DependencyInjection\Reference;
20 use Symfony\Component\DependencyInjection\ContainerBuilder;
21 use Symfony\Component\ExpressionLanguage\Expression;
24 * Run this pass before passes that need to know more about the relation of
27 * This class will populate the ServiceReferenceGraph with information. You can
28 * retrieve the graph in other passes from the compiler.
30 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
32 class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface
35 private $currentDefinition;
36 private $onlyConstructorArguments;
38 private $expressionLanguage;
41 * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
43 public function __construct($onlyConstructorArguments = false)
45 $this->onlyConstructorArguments = (bool) $onlyConstructorArguments;
51 public function setRepeatedPass(RepeatedPass $repeatedPass)
57 * Processes a ContainerBuilder object to populate the service reference graph.
59 public function process(ContainerBuilder $container)
61 $this->container = $container;
62 $this->graph = $container->getCompiler()->getServiceReferenceGraph();
63 $this->graph->clear();
66 foreach ($container->getAliases() as $id => $alias) {
67 $targetId = $this->getDefinitionId((string) $alias);
68 $this->graph->connect($id, $alias, $targetId, $this->getDefinition($targetId), null);
71 parent::process($container);
74 protected function processValue($value, $isRoot = false)
78 if ($value instanceof ArgumentInterface) {
80 parent::processValue($value->getValues());
85 if ($value instanceof Expression) {
86 $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
90 if ($value instanceof Reference) {
91 $targetId = $this->getDefinitionId((string) $value);
92 $targetDefinition = $this->getDefinition($targetId);
94 $this->graph->connect(
96 $this->currentDefinition,
100 $this->lazy || ($targetDefinition && $targetDefinition->isLazy()),
101 ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior()
106 if (!$value instanceof Definition) {
107 return parent::processValue($value, $isRoot);
110 if ($value->isSynthetic() || $value->isAbstract()) {
113 $this->currentDefinition = $value;
117 $this->processValue($value->getFactory());
118 $this->processValue($value->getArguments());
120 if (!$this->onlyConstructorArguments) {
121 $this->processValue($value->getProperties());
122 $this->processValue($value->getMethodCalls());
123 $this->processValue($value->getConfigurator());
131 * Returns a service definition given the full name or an alias.
133 * @param string $id A full id or alias for a service definition
135 * @return Definition|null The definition related to the supplied id
137 private function getDefinition($id)
139 return null === $id ? null : $this->container->getDefinition($id);
142 private function getDefinitionId($id)
144 while ($this->container->hasAlias($id)) {
145 $id = (string) $this->container->getAlias($id);
148 if (!$this->container->hasDefinition($id)) {
152 return $this->container->normalizeId($id);
155 private function getExpressionLanguage()
157 if (null === $this->expressionLanguage) {
158 if (!class_exists(ExpressionLanguage::class)) {
159 throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
162 $providers = $this->container->getExpressionLanguageProviders();
163 $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) {
164 if ('""' === substr_replace($arg, '', 1, -1)) {
165 $id = stripcslashes(substr($arg, 1, -1));
166 $id = $this->getDefinitionId($id);
168 $this->graph->connect(
170 $this->currentDefinition,
172 $this->getDefinition($id)
176 return sprintf('$this->get(%s)', $arg);
180 return $this->expressionLanguage;