Skip to content
This repository has been archived by the owner on Feb 6, 2020. It is now read-only.

Commit

Permalink
Merge branch 'feature/230' into develop
Browse files Browse the repository at this point in the history
Close #230
  • Loading branch information
weierophinney committed Jan 22, 2018
2 parents fdc7a27 + 9db343d commit aea63ce
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
31 changes: 28 additions & 3 deletions src/ServiceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,12 @@ private function mapAliasToTarget($alias, $target)
*
* This function maps $this->aliases in place.
*
* 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 is fast for mass updates through configure().
* It is not appropriate if just a single alias is added.
*
Expand All @@ -881,16 +887,35 @@ 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;
}

$stack = [];

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;

foreach ($stack as $alias) {
if ($alias === $tCursor) {
throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases);
}
$this->aliases[$alias] = $tCursor;
$tagged[$alias] = true;
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions test/CommonServiceLocatorBehaviorsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
}
}

0 comments on commit aea63ce

Please sign in to comment.