made the DI config validation more strict to catch errors early
This commit is contained in:
parent
4408cbc9fa
commit
f29a5f74a1
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* This pass validates each definition individually only taking the information
|
||||
* into account which is contained in the definition itself.
|
||||
*
|
||||
* Later passes can rely on the following, and specifically do not need to
|
||||
* perform these checks themself:
|
||||
*
|
||||
* - non synthetic services always have a class set
|
||||
* - synthetic services are always public
|
||||
* - synthetic services are always of non-prototype scope
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckDefinitionValidityPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
// synthetic service is public
|
||||
if ($definition->isSynthetic() && !$definition->isPublic()) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'A synthetic service ("%s") must be public.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
// synthetic service has non-prototype scope
|
||||
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'A synthetic service ("%s") cannot be of scope "prototype".',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
// non-synthetic service has class
|
||||
if (!$definition->isSynthetic() && !$definition->getClass()) {
|
||||
if ($definition->getFactoryService()) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Please add the class to service "%s" even if it is constructed '
|
||||
.'by a factory since we might need to add method calls based on '
|
||||
.'interface injection, or other compile-time checks.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf(
|
||||
'The definition for "%s" has no class. If you intend to inject '
|
||||
.'this service dynamically at runtime, please mark it as synthetic=true, '
|
||||
.'otherwise specify a class to get rid of this error.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -44,6 +44,10 @@ class CheckReferenceScopePass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->currentId = $id;
|
||||
$this->currentScope = $scope = $definition->getScope();
|
||||
|
||||
|
@ -43,6 +43,7 @@ class PassConfig
|
||||
|
||||
$this->optimizationPasses = array(
|
||||
new ResolveParameterPlaceHoldersPass(),
|
||||
new CheckDefinitionValidityPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInterfaceInjectorsPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
|
@ -26,6 +26,10 @@ class ResolveInterfaceInjectorsPass implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if ($definition->isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$loaded = false;
|
||||
foreach ($container->getInterfaceInjectors() as $injector) {
|
||||
if (null !== $definition->getFactoryService()) {
|
||||
@ -38,7 +42,7 @@ class ResolveInterfaceInjectorsPass implements CompilerPassInterface
|
||||
require_once $definition->getFile();
|
||||
}
|
||||
|
||||
if (null !== $definition->getClass() && $injector->supports($definition->getClass())) {
|
||||
if ($injector->supports($definition->getClass())) {
|
||||
$injector->processDefinition($definition);
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ class ResolveInvalidReferencesPass implements CompilerPassInterface
|
||||
{
|
||||
$this->container = $container;
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if ($definition->isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition->setArguments(
|
||||
$this->processArguments($definition->getArguments())
|
||||
);
|
||||
|
@ -61,8 +61,8 @@ class ResolveReferencesToAliasesPass implements CompilerPassInterface
|
||||
|
||||
protected function getDefinitionId($id)
|
||||
{
|
||||
if ($this->container->hasAlias($id)) {
|
||||
return $this->getDefinitionId((string) $this->container->getAlias($id));
|
||||
while ($this->container->hasAlias($id)) {
|
||||
$id = (string) $this->container->getAlias($id);
|
||||
}
|
||||
|
||||
return $id;
|
||||
|
@ -32,18 +32,18 @@ class IntegrationTest extends \PHPUnit_Framework_TestCase
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container
|
||||
->register('a')
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
;
|
||||
|
||||
$b = $container
|
||||
->register('b')
|
||||
->register('b', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$c = $container
|
||||
->register('c')
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
@ -61,14 +61,14 @@ class IntegrationTest extends \PHPUnit_Framework_TestCase
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container
|
||||
->register('a')
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
;
|
||||
|
||||
$container->setAlias('b', new Alias('c', false));
|
||||
|
||||
$c = $container
|
||||
->register('c')
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
@ -86,19 +86,19 @@ class IntegrationTest extends \PHPUnit_Framework_TestCase
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a')
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
->addMethodCall('setC', array(new Reference('c')))
|
||||
;
|
||||
|
||||
$container
|
||||
->register('b')
|
||||
->register('b', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container
|
||||
->register('c')
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
|
Reference in New Issue
Block a user