From 2413112de0c230e080c155dbecce487351ad5692 Mon Sep 17 00:00:00 2001 From: fhein Date: Thu, 18 Jan 2018 19:35:53 +0100 Subject: [PATCH 1/5] Tests and fix for mapAliasesToTargets as of #221. --- src/ServiceManager.php | 37 ++++++++++++++++++--- test/CommonServiceLocatorBehaviorsTrait.php | 24 +++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/ServiceManager.php b/src/ServiceManager.php index ad37788e..7ee07e12 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -868,7 +868,13 @@ private function mapAliasToTarget($alias, $target) * * This function maps $this->aliases in place. * - * This algorithm is fast for mass updates through configure(). + * This algorithm is an adaptated version of Tarjans Strongly + * Connected Components. Instead of returning the strongly + * connected components (i.e. cycles in our case), we throw. + * If nodes are not strongly connected (i.e. resolvable in + * our case), they get resolved. + * + * This algorithm fast for mass updates through configure(). * It is not appropriate if just a single alias is added. * * @see mapAliasToTarget above @@ -881,17 +887,40 @@ private function mapAliasesToTargets() if (isset($tagged[$alias])) { continue; } + $tCursor = $this->aliases[$alias]; $aCursor = $alias; + if ($aCursor === $tCursor) { + throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases); + } + if (! isset($this->aliases[$tCursor])) { + continue; + } + while (isset($this->aliases[$tCursor])) { - $tagged[$aCursor] = true; - $this->aliases[$aCursor] = $this->aliases[$tCursor]; + $stack[] = $aCursor; + if ($aCursor === $this->aliases[$tCursor]) { + throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases); + } $aCursor = $tCursor; $tCursor = $this->aliases[$tCursor]; - if ($aCursor === $tCursor) { + } + + $tagged[$aCursor] = true; + + if (! isset($stack)) { + continue; + } + + foreach ($stack as $_ => $alias) { + if ($alias === $tCursor) { throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases); } + $this->aliases[$alias] = $tCursor; + $tagged[$alias] = true; } + + unset($stack); } } diff --git a/test/CommonServiceLocatorBehaviorsTrait.php b/test/CommonServiceLocatorBehaviorsTrait.php index 375d1a92..639392b2 100644 --- a/test/CommonServiceLocatorBehaviorsTrait.php +++ b/test/CommonServiceLocatorBehaviorsTrait.php @@ -855,4 +855,28 @@ public function testCrashesOnCyclicAliases() ], ]); } + + public function testMinimalCyclicAliasDefinitionShouldThrow() + { + $sm = $this->createContainer([]); + + $this->expectException(CyclicAliasException::class); + $sm->setAlias('alias', 'alias'); + } + + public function testCoverageDepthFirstTaggingOnRecursiveAliasDefinitions() + { + $sm = $this->createContainer([ + 'factories' => [ + stdClass::class => InvokableFactory::class, + ], + 'aliases' => [ + 'alias1' => 'alias2', + 'alias2' => 'alias3', + 'alias3' => stdClass::class, + ], + ]); + $this->assertSame($sm->get('alias1'), $sm->get('alias2')); + $this->assertSame($sm->get(stdClass::class), $sm->get('alias1')); + } } From 7bf7b8aa5b88724ff1b804ef6f29fa3c0663572d Mon Sep 17 00:00:00 2001 From: fhein Date: Thu, 18 Jan 2018 20:02:47 +0100 Subject: [PATCH 2/5] Missing word in source doc. --- src/ServiceManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceManager.php b/src/ServiceManager.php index 7ee07e12..bcf683b1 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -874,7 +874,7 @@ private function mapAliasToTarget($alias, $target) * If nodes are not strongly connected (i.e. resolvable in * our case), they get resolved. * - * This algorithm fast for mass updates through configure(). + * This algorithm is fast for mass updates through configure(). * It is not appropriate if just a single alias is added. * * @see mapAliasToTarget above From a359426006cdf31d5971744bf6fbdc78e8441bb0 Mon Sep 17 00:00:00 2001 From: fhein Date: Thu, 18 Jan 2018 23:04:30 +0100 Subject: [PATCH 3/5] Removed $_. --- src/ServiceManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceManager.php b/src/ServiceManager.php index bcf683b1..25364aad 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -912,7 +912,7 @@ private function mapAliasesToTargets() continue; } - foreach ($stack as $_ => $alias) { + foreach ($stack as $alias) { if ($alias === $tCursor) { throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases); } From 886b6f97b14b266677f3f4bf65076de1e8070f44 Mon Sep 17 00:00:00 2001 From: fhein Date: Fri, 19 Jan 2018 16:11:15 +0100 Subject: [PATCH 4/5] Switched mapAliasesToTargets from isset() to empty() mechanics. --- src/ServiceManager.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ServiceManager.php b/src/ServiceManager.php index 25364aad..061d82f5 100644 --- a/src/ServiceManager.php +++ b/src/ServiceManager.php @@ -897,6 +897,8 @@ private function mapAliasesToTargets() continue; } + $stack = []; + while (isset($this->aliases[$tCursor])) { $stack[] = $aCursor; if ($aCursor === $this->aliases[$tCursor]) { @@ -908,10 +910,6 @@ private function mapAliasesToTargets() $tagged[$aCursor] = true; - if (! isset($stack)) { - continue; - } - foreach ($stack as $alias) { if ($alias === $tCursor) { throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases); @@ -919,8 +917,6 @@ private function mapAliasesToTargets() $this->aliases[$alias] = $tCursor; $tagged[$alias] = true; } - - unset($stack); } } From 9db343d7b92f08b7a75b404a2ad07d96f5462327 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 22 Jan 2018 16:57:35 -0600 Subject: [PATCH 5/5] Adds CHANGELOG entry for #230 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f60de1e2..cb533202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,8 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#230](https://github.com/zendframework/zend-servicemanager/pull/230) fixes a + problem in detecting cyclic aliases, ensuring they are detected correctly. ## 3.3.1 - 2017-11-27