This repository has been archived by the owner on Feb 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
6 changed files
with
339 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<?php | ||
/** | ||
* Zend Framework (http://framework.zend.com/) | ||
* | ||
* @link http://github.com/zendframework/zf2 for the canonical source repository | ||
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) | ||
* @license http://framework.zend.com/license/new-bsd New BSD License | ||
*/ | ||
|
||
namespace Zend\ServiceManager\Exception; | ||
|
||
class CyclicAliasException extends InvalidArgumentException | ||
{ | ||
/** | ||
* @param string[] $aliases map of referenced services, indexed by alias name (string) | ||
* | ||
* @return self | ||
*/ | ||
public static function fromAliasesMap(array $aliases) | ||
{ | ||
$detectedCycles = array_filter(array_map( | ||
function ($alias) use ($aliases) { | ||
return self::getCycleFor($aliases, $alias); | ||
}, | ||
array_keys($aliases) | ||
)); | ||
|
||
if (! $detectedCycles) { | ||
return new self(sprintf( | ||
"A cycle was detected within the following aliases map:\n\n%s", | ||
self::printReferencesMap($aliases) | ||
)); | ||
} | ||
|
||
return new self(sprintf( | ||
"Cycles were detected within the provided aliases:\n\n%s\n\n" | ||
. "The cycle was detected in the following alias map:\n\n%s", | ||
self::printCycles(self::deDuplicateDetectedCycles($detectedCycles)), | ||
self::printReferencesMap($aliases) | ||
)); | ||
} | ||
|
||
/** | ||
* Retrieves the cycle detected for the given $alias, or `null` if no cycle was detected | ||
* | ||
* @param string[] $aliases | ||
* @param string $alias | ||
* | ||
* @return array|null | ||
*/ | ||
private static function getCycleFor(array $aliases, $alias) | ||
{ | ||
$cycleCandidate = []; | ||
$targetName = $alias; | ||
|
||
while (isset($aliases[$targetName])) { | ||
if (isset($cycleCandidate[$targetName])) { | ||
return $cycleCandidate; | ||
} | ||
|
||
$cycleCandidate[$targetName] = true; | ||
|
||
$targetName = $aliases[$targetName]; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* @param string[] $aliases | ||
* | ||
* @return string | ||
*/ | ||
private static function printReferencesMap(array $aliases) | ||
{ | ||
$map = []; | ||
|
||
foreach ($aliases as $alias => $reference) { | ||
$map[] = '"' . $alias . '" => "' . $reference . '"'; | ||
} | ||
|
||
return "[\n" . implode("\n", $map) . "\n]"; | ||
} | ||
|
||
/** | ||
* @param string[][] $detectedCycles | ||
* | ||
* @return string | ||
*/ | ||
private static function printCycles(array $detectedCycles) | ||
{ | ||
return "[\n" . implode("\n", array_map([__CLASS__, 'printCycle'], $detectedCycles)) . "\n]"; | ||
} | ||
|
||
/** | ||
* @param string[] $detectedCycle | ||
* | ||
* @return string | ||
*/ | ||
private static function printCycle(array $detectedCycle) | ||
{ | ||
$fullCycle = array_keys($detectedCycle); | ||
$fullCycle[] = reset($fullCycle); | ||
|
||
return implode( | ||
' => ', | ||
array_map( | ||
function ($cycle) { | ||
return '"' . $cycle . '"'; | ||
}, | ||
$fullCycle | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* @param bool[][] $detectedCycles | ||
* | ||
* @return bool[][] de-duplicated | ||
*/ | ||
private static function deDuplicateDetectedCycles(array $detectedCycles) | ||
{ | ||
$detectedCyclesByHash = []; | ||
|
||
foreach ($detectedCycles as $detectedCycle) { | ||
$cycleAliases = array_keys($detectedCycle); | ||
|
||
sort($cycleAliases); | ||
|
||
$hash = serialize(array_values($cycleAliases)); | ||
|
||
$detectedCyclesByHash[$hash] = isset($detectedCyclesByHash[$hash]) | ||
? $detectedCyclesByHash[$hash] | ||
: $detectedCycle; | ||
} | ||
|
||
return array_values($detectedCyclesByHash); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
<?php | ||
/** | ||
* Zend Framework (http://framework.zend.com/) | ||
* | ||
* @link http://github.com/zendframework/zf2 for the canonical source repository | ||
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) | ||
* @license http://framework.zend.com/license/new-bsd New BSD License | ||
*/ | ||
|
||
namespace ZendTest\ServiceManager\Exception; | ||
|
||
use PHPUnit_Framework_TestCase as TestCase; | ||
use ProxyManager\Autoloader\AutoloaderInterface; | ||
use RecursiveDirectoryIterator; | ||
use RecursiveIteratorIterator; | ||
use RecursiveRegexIterator; | ||
use RegexIterator; | ||
use stdClass; | ||
use Zend\ServiceManager\Exception\CyclicAliasException; | ||
use Zend\ServiceManager\Exception\ServiceNotCreatedException; | ||
use Zend\ServiceManager\Exception\ServiceNotFoundException; | ||
use Zend\ServiceManager\Factory\InvokableFactory; | ||
use Zend\ServiceManager\Proxy\LazyServiceFactory; | ||
use Zend\ServiceManager\ServiceManager; | ||
use ZendTest\ServiceManager\TestAsset\InvokableObject; | ||
|
||
/** | ||
* @covers \Zend\ServiceManager\Exception\CyclicAliasException | ||
*/ | ||
class CyclicAliasExceptionTest extends TestCase | ||
{ | ||
/** | ||
* @dataProvider aliasesProvider | ||
* | ||
* @param string[] $aliases | ||
* @param string $expectedMessage | ||
* | ||
* @return void | ||
*/ | ||
public function testFromAliasesMap(array $aliases, $expectedMessage) | ||
{ | ||
$exception = CyclicAliasException::fromAliasesMap($aliases); | ||
|
||
self::assertInstanceOf(CyclicAliasException::class, $exception); | ||
self::assertSame($expectedMessage, $exception->getMessage()); | ||
} | ||
|
||
/** | ||
* @return string[][]|string[][][] | ||
*/ | ||
public function aliasesProvider() | ||
{ | ||
return [ | ||
'empty set' => [ | ||
[], | ||
'A cycle was detected within the following aliases map: | ||
[ | ||
]' | ||
], | ||
'acyclic set' => [ | ||
[ | ||
'b' => 'a', | ||
'd' => 'c', | ||
], | ||
'A cycle was detected within the following aliases map: | ||
[ | ||
"b" => "a" | ||
"d" => "c" | ||
]' | ||
], | ||
'acyclic self-referencing set' => [ | ||
[ | ||
'b' => 'a', | ||
'c' => 'b', | ||
'd' => 'c', | ||
], | ||
'A cycle was detected within the following aliases map: | ||
[ | ||
"b" => "a" | ||
"c" => "b" | ||
"d" => "c" | ||
]' | ||
], | ||
'cyclic set' => [ | ||
[ | ||
'b' => 'a', | ||
'a' => 'b', | ||
], | ||
'Cycles were detected within the provided aliases: | ||
[ | ||
"b" => "a" => "b" | ||
] | ||
The cycle was detected in the following alias map: | ||
[ | ||
"b" => "a" | ||
"a" => "b" | ||
]' | ||
], | ||
'cyclic set (indirect)' => [ | ||
[ | ||
'b' => 'a', | ||
'c' => 'b', | ||
'a' => 'c', | ||
], | ||
'Cycles were detected within the provided aliases: | ||
[ | ||
"b" => "a" => "c" => "b" | ||
] | ||
The cycle was detected in the following alias map: | ||
[ | ||
"b" => "a" | ||
"c" => "b" | ||
"a" => "c" | ||
]' | ||
], | ||
'cyclic set + acyclic set' => [ | ||
[ | ||
'b' => 'a', | ||
'a' => 'b', | ||
'd' => 'c', | ||
], | ||
'Cycles were detected within the provided aliases: | ||
[ | ||
"b" => "a" => "b" | ||
] | ||
The cycle was detected in the following alias map: | ||
[ | ||
"b" => "a" | ||
"a" => "b" | ||
"d" => "c" | ||
]' | ||
], | ||
'cyclic set + reference to cyclic set' => [ | ||
[ | ||
'b' => 'a', | ||
'a' => 'b', | ||
'c' => 'a', | ||
], | ||
'Cycles were detected within the provided aliases: | ||
[ | ||
"b" => "a" => "b" | ||
"c" => "a" => "b" => "c" | ||
] | ||
The cycle was detected in the following alias map: | ||
[ | ||
"b" => "a" | ||
"a" => "b" | ||
"c" => "a" | ||
]' | ||
], | ||
]; | ||
} | ||
} |
Oops, something went wrong.