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\Definition;
16 use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
17 use Symfony\Component\DependencyInjection\Reference;
20 * Inline service definitions where this is possible.
22 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
24 class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface
26 private $cloningIds = array();
27 private $inlinedServiceIds = array();
32 public function setRepeatedPass(RepeatedPass $repeatedPass)
38 * Returns an array of all services inlined by this pass.
40 * The key is the inlined service id and its value is the list of services it was inlined into.
42 * @deprecated since version 3.4, to be removed in 4.0.
46 public function getInlinedServiceIds()
48 @trigger_error('Calling InlineServiceDefinitionsPass::getInlinedServiceIds() is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
50 return $this->inlinedServiceIds;
56 protected function processValue($value, $isRoot = false)
58 if ($value instanceof ArgumentInterface) {
59 // Reference found in ArgumentInterface::getValues() are not inlineable
63 if ($value instanceof Definition && $this->cloningIds) {
64 if ($value->isShared()) {
67 $value = clone $value;
70 if (!$value instanceof Reference || !$this->container->hasDefinition($id = $this->container->normalizeId($value))) {
71 return parent::processValue($value, $isRoot);
74 $definition = $this->container->getDefinition($id);
76 if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
80 $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
81 $this->inlinedServiceIds[$id][] = $this->currentId;
83 if ($definition->isShared()) {
87 if (isset($this->cloningIds[$id])) {
88 $ids = array_keys($this->cloningIds);
91 throw new ServiceCircularReferenceException($id, \array_slice($ids, array_search($id, $ids)));
94 $this->cloningIds[$id] = true;
96 return $this->processValue($definition);
98 unset($this->cloningIds[$id]);
103 * Checks if the definition is inlineable.
105 * @return bool If the definition is inlineable
107 private function isInlineableDefinition($id, Definition $definition, ServiceReferenceGraph $graph)
109 if ($definition->getErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) {
113 if (!$definition->isShared()) {
117 if ($definition->isPublic() || $definition->isPrivate()) {
121 if (!$graph->hasNode($id)) {
125 if ($this->currentId == $id) {
130 foreach ($graph->getNode($id)->getInEdges() as $edge) {
131 if ($edge->isWeak()) {
134 $ids[] = $edge->getSourceNode()->getId();
137 if (\count(array_unique($ids)) > 1) {
141 if (\count($ids) > 1 && \is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
145 return !$ids || $this->container->getDefinition($ids[0])->isShared();