* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; /** * Replaces aliases with actual service definitions, effectively removing these * aliases. * * @author Johannes M. Schmitt */ class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface { private $compiler; private $formatter; private $sourceId; /** * Process the Container to replace aliases with service definitions. * * @param ContainerBuilder $container * * @throws InvalidArgumentException if the service definition does not exist */ public function process(ContainerBuilder $container) { $this->compiler = $container->getCompiler(); $this->formatter = $this->compiler->getLoggingFormatter(); foreach ($container->getAliases() as $id => $alias) { $aliasId = (string) $alias; if ('service_container' === $aliasId) { continue; } try { $definition = $container->getDefinition($aliasId); } catch (InvalidArgumentException $e) { throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $id, $alias), null, $e); } if ($definition->isPublic()) { continue; } $definition->setPublic(true); $container->setDefinition($id, $definition); $container->removeDefinition($aliasId); $this->updateReferences($container, $aliasId, $id); // we have to restart the process due to concurrent modification of // the container $this->process($container); break; } } /** * Updates references to remove aliases. * * @param ContainerBuilder $container The container * @param string $currentId The alias identifier being replaced * @param string $newId The id of the service the alias points to */ private function updateReferences($container, $currentId, $newId) { foreach ($container->getAliases() as $id => $alias) { if ($currentId === (string) $alias) { $container->setAlias($id, $newId); } } foreach ($container->getDefinitions() as $id => $definition) { $this->sourceId = $id; $definition->setArguments( $this->updateArgumentReferences($definition->getArguments(), $currentId, $newId) ); $definition->setMethodCalls( $this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId) ); $definition->setProperties( $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId) ); $definition->setFactoryService($this->updateFactoryServiceReference($definition->getFactoryService(false), $currentId, $newId), false); $definition->setFactory($this->updateFactoryReference($definition->getFactory(), $currentId, $newId)); } } /** * Updates argument references. * * @param array $arguments An array of Arguments * @param string $currentId The alias identifier * @param string $newId The identifier the alias points to * * @return array */ private function updateArgumentReferences(array $arguments, $currentId, $newId) { foreach ($arguments as $k => $argument) { if (is_array($argument)) { $arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId); } elseif ($argument instanceof Reference) { if ($currentId === (string) $argument) { $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior()); $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId)); } } } return $arguments; } private function updateFactoryServiceReference($factoryService, $currentId, $newId) { if (null === $factoryService) { return; } return $currentId === $factoryService ? $newId : $factoryService; } private function updateFactoryReference($factory, $currentId, $newId) { if (null === $factory || !is_array($factory) || !$factory[0] instanceof Reference) { return $factory; } if ($currentId === (string) $factory[0]) { $factory[0] = new Reference($newId, $factory[0]->getInvalidBehavior()); } return $factory; } }