Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
26666a2
commit 803dd58
Showing
24 changed files
with
744 additions
and
174 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
127 changes: 0 additions & 127 deletions
127
src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceScopePass.php
This file was deleted.
Oops, something went wrong.
145 changes: 145 additions & 0 deletions
145
src/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php
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,145 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\ContainerInterface; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
|
||
/** | ||
* Checks the validity of references | ||
* | ||
* The following checks are performed by this pass: | ||
* - target definitions are not abstract | ||
* - target definitions are of equal or wider scope | ||
* - target definitions are in the same scope hierarchy | ||
* | ||
* @author Johannes M. Schmitt <schmittjoh@gmail.com> | ||
*/ | ||
class CheckReferenceValidityPass implements CompilerPassInterface | ||
{ | ||
protected $container; | ||
protected $currentId; | ||
protected $currentDefinition; | ||
protected $currentScope; | ||
protected $currentScopeAncestors; | ||
protected $currentScopeChildren; | ||
|
||
public function process(ContainerBuilder $container) | ||
{ | ||
$this->container = $container; | ||
|
||
$children = $this->container->getScopeChildren(); | ||
$ancestors = array(); | ||
|
||
$scopes = $this->container->getScopes(); | ||
foreach ($scopes as $name => $parent) { | ||
$ancestors[$name] = array($parent); | ||
|
||
while (isset($scopes[$parent])) { | ||
$ancestors[$name][] = $parent = $scopes[$parent]; | ||
} | ||
} | ||
|
||
foreach ($container->getDefinitions() as $id => $definition) { | ||
if ($definition->isSynthetic() || $definition->isAbstract()) { | ||
continue; | ||
} | ||
|
||
$this->currentId = $id; | ||
$this->currentDefinition = $definition; | ||
$this->currentScope = $scope = $definition->getScope(); | ||
|
||
if (ContainerInterface::SCOPE_CONTAINER === $scope) { | ||
$this->currentScopeChildren = array_keys($scopes); | ||
$this->currentScopeAncestors = array(); | ||
} else if (ContainerInterface::SCOPE_PROTOTYPE !== $scope) { | ||
$this->currentScopeChildren = $children[$scope]; | ||
$this->currentScopeAncestors = $ancestors[$scope]; | ||
} | ||
|
||
$this->validateReferences($definition->getArguments()); | ||
$this->validateReferences($definition->getMethodCalls()); | ||
} | ||
} | ||
|
||
protected function validateReferences(array $arguments) | ||
{ | ||
foreach ($arguments as $argument) { | ||
if (is_array($argument)) { | ||
$this->validateReferences($argument); | ||
} elseif ($argument instanceof Reference) { | ||
$targetDefinition = $this->getDefinition((string) $argument); | ||
|
||
if (null !== $targetDefinition && $targetDefinition->isAbstract()) { | ||
throw new \RuntimeException(sprintf( | ||
'The definition "%s" has a reference to an abstract definition "%s". ' | ||
.'Abstract definitions cannot be the target of references.', | ||
$this->currentId, | ||
$argument | ||
)); | ||
} | ||
|
||
$this->validateScope($argument, $targetDefinition); | ||
} | ||
} | ||
} | ||
|
||
protected function validateScope(Reference $reference, Definition $definition = null) | ||
{ | ||
if (ContainerInterface::SCOPE_PROTOTYPE === $this->currentScope) { | ||
return; | ||
} | ||
|
||
if (!$reference->isStrict()) { | ||
return; | ||
} | ||
|
||
if (null === $definition) { | ||
return; | ||
} | ||
|
||
if ($this->currentScope === $scope = $definition->getScope()) { | ||
return; | ||
} | ||
|
||
$id = (string) $reference; | ||
|
||
if (in_array($scope, $this->currentScopeChildren, true)) { | ||
throw new \RuntimeException(sprintf( | ||
'Scope Widening Injection detected: The definition "%s" references the service "%s" which belongs to a narrower scope. ' | ||
.'Generally, it is safer to either move "%s" to scope "%s" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "%s" each time it is needed. ' | ||
.'In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.', | ||
$this->currentId, | ||
$id, | ||
$this->currentId, | ||
$scope, | ||
$id | ||
)); | ||
} | ||
|
||
if (!in_array($scope, $this->currentScopeAncestors, true)) { | ||
throw new \RuntimeException(sprintf( | ||
'Cross-Scope Injection detected: The definition "%s" references the service "%s" which belongs to another scope hierarchy. ' | ||
.'This service might not be available consistently. Generally, it is safer to either move the definition "%s" to scope "%s", or ' | ||
.'declare "%s" as a child scope of "%s". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.', | ||
$this->currentId, | ||
$id, | ||
$this->currentId, | ||
$scope, | ||
$this->currentScope, | ||
$scope | ||
)); | ||
} | ||
} | ||
|
||
protected function getDefinition($id) | ||
{ | ||
if (!$this->container->hasDefinition($id)) { | ||
return null; | ||
} | ||
|
||
return $this->container->getDefinition($id); | ||
} | ||
} |
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
17 changes: 17 additions & 0 deletions
17
src/Symfony/Component/DependencyInjection/Compiler/RemoveAbstractDefinitionsPass.php
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,17 @@ | ||
<?php | ||
|
||
namespace Symfony\Component\DependencyInjection\Compiler; | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
|
||
class RemoveAbstractDefinitionsPass implements CompilerPassInterface | ||
{ | ||
public function process(ContainerBuilder $container) | ||
{ | ||
foreach ($container->getDefinitions() as $id => $definition) { | ||
if ($definition->isAbstract()) { | ||
$container->remove($id); | ||
} | ||
} | ||
} | ||
} |
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 |
---|---|---|
|
@@ -57,4 +57,9 @@ public function setRepeat() | |
{ | ||
$this->repeat = true; | ||
} | ||
|
||
public function getPasses() | ||
{ | ||
return $this->passes; | ||
} | ||
} |
Oops, something went wrong.