Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\DependencyInjection\Compiler; Chris@0: Chris@0: use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; Chris@0: use Symfony\Component\DependencyInjection\ContainerBuilder; Chris@0: Chris@0: /** Chris@0: * Checks your services for circular references. Chris@0: * Chris@0: * References from method calls are ignored since we might be able to resolve Chris@0: * these references depending on the order in which services are called. Chris@0: * Chris@0: * Circular reference from method calls will only be detected at run-time. Chris@0: * Chris@0: * @author Johannes M. Schmitt Chris@0: */ Chris@0: class CheckCircularReferencesPass implements CompilerPassInterface Chris@0: { Chris@0: private $currentPath; Chris@0: private $checkedNodes; Chris@0: Chris@0: /** Chris@0: * Checks the ContainerBuilder object for circular references. Chris@0: * Chris@0: * @param ContainerBuilder $container The ContainerBuilder instances Chris@0: */ Chris@0: public function process(ContainerBuilder $container) Chris@0: { Chris@0: $graph = $container->getCompiler()->getServiceReferenceGraph(); Chris@0: Chris@0: $this->checkedNodes = array(); Chris@0: foreach ($graph->getNodes() as $id => $node) { Chris@0: $this->currentPath = array($id); Chris@0: Chris@0: $this->checkOutEdges($node->getOutEdges()); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Checks for circular references. Chris@0: * Chris@0: * @param ServiceReferenceGraphEdge[] $edges An array of Edges Chris@0: * Chris@0: * @throws ServiceCircularReferenceException When a circular reference is found. Chris@0: */ Chris@0: private function checkOutEdges(array $edges) Chris@0: { Chris@0: foreach ($edges as $edge) { Chris@0: $node = $edge->getDestNode(); Chris@0: $id = $node->getId(); Chris@0: Chris@0: if (empty($this->checkedNodes[$id])) { Chris@0: // don't check circular dependencies for lazy services Chris@0: if (!$node->getValue() || !$node->getValue()->isLazy()) { Chris@0: $searchKey = array_search($id, $this->currentPath); Chris@0: $this->currentPath[] = $id; Chris@0: Chris@0: if (false !== $searchKey) { Chris@0: throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey)); Chris@0: } Chris@0: Chris@0: $this->checkOutEdges($node->getOutEdges()); Chris@0: } Chris@0: Chris@0: $this->checkedNodes[$id] = true; Chris@0: array_pop($this->currentPath); Chris@0: } Chris@0: } Chris@0: } Chris@0: }