[DI] Restrict autowired registration to "same-vendor" namespaces
This commit is contained in:
parent
ab93feae3f
commit
9c53b3deb0
@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
/**
|
||||
@ -76,9 +75,9 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*/
|
||||
protected function processValue($value, $isRoot = false)
|
||||
{
|
||||
if ($value instanceof TypedReference && !$this->container->has((string) $value)) {
|
||||
if ($ref = $this->getAutowiredReference($value->getType(), $value->canBeAutoregistered())) {
|
||||
$value = new TypedReference((string) $ref, $value->getType(), $value->getInvalidBehavior(), $value->canBeAutoregistered());
|
||||
if ($value instanceof TypedReference) {
|
||||
if ($ref = $this->getAutowiredReference($value)) {
|
||||
$value = $ref;
|
||||
} else {
|
||||
$this->container->log($this, $this->createTypeNotFoundMessage($value->getType(), 'typed reference'));
|
||||
}
|
||||
@ -242,7 +241,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$value = $this->getAutowiredReference($type, !$parameter->isOptional())) {
|
||||
if (!$value = $this->getAutowiredReference(new TypedReference($type, $type, !$parameter->isOptional() ? $class : ''))) {
|
||||
$failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
|
||||
|
||||
if ($parameter->isDefaultValueAvailable()) {
|
||||
@ -276,16 +275,14 @@ class AutowirePass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Reference|null A reference to the service matching the given type, if any
|
||||
* @return TypedReference|null A reference to the service matching the given type, if any
|
||||
*/
|
||||
private function getAutowiredReference($type, $autoRegister)
|
||||
private function getAutowiredReference(TypedReference $reference)
|
||||
{
|
||||
if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
|
||||
return new Reference($type);
|
||||
}
|
||||
$type = $reference->getType();
|
||||
|
||||
if (isset($this->autowired[$type])) {
|
||||
return $this->autowired[$type] ? new Reference($this->autowired[$type]) : null;
|
||||
if ($type !== (string) $reference || ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract())) {
|
||||
return $reference;
|
||||
}
|
||||
|
||||
if (null === $this->types) {
|
||||
@ -293,12 +290,18 @@ class AutowirePass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
if (isset($this->definedTypes[$type])) {
|
||||
return new Reference($this->types[$type]);
|
||||
return new TypedReference($this->types[$type], $type);
|
||||
}
|
||||
|
||||
if ($autoRegister && !isset($this->types[$type]) && !isset($this->ambiguousServiceTypes[$type])) {
|
||||
return $this->createAutowiredDefinition($type);
|
||||
if (!$reference->canBeAutoregistered() || isset($this->types[$type]) || isset($this->ambiguousServiceTypes[$type])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->autowired[$type])) {
|
||||
return $this->autowired[$type] ? new TypedReference($this->autowired[$type], $type) : null;
|
||||
}
|
||||
|
||||
return $this->createAutowiredDefinition($type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -384,7 +387,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Reference|null A reference to the registered definition
|
||||
* @return TypedReference|null A reference to the registered definition
|
||||
*/
|
||||
private function createAutowiredDefinition($type)
|
||||
{
|
||||
@ -412,7 +415,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
|
||||
|
||||
return new Reference($argumentId);
|
||||
return new TypedReference($argumentId, $type);
|
||||
}
|
||||
|
||||
private function createTypeNotFoundMessage($type, $label)
|
||||
|
@ -71,10 +71,11 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
}
|
||||
$this->container->addObjectResource($class);
|
||||
$subscriberMap = array();
|
||||
$declaringClass = (new \ReflectionMethod($class, 'getSubscribedServices'))->class;
|
||||
|
||||
foreach ($class::getSubscribedServices() as $key => $type) {
|
||||
if (!is_string($type) || !preg_match('/^\??[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $type)) {
|
||||
throw new InvalidArgumentException(sprintf('%s::getSubscribedServices() must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $this->currentId, $key, is_string($type) ? $type : gettype($type)));
|
||||
throw new InvalidArgumentException(sprintf('"%s::getSubscribedServices()" must return valid PHP types for service "%s" key "%s", "%s" returned.', $class, $this->currentId, $key, is_string($type) ? $type : gettype($type)));
|
||||
}
|
||||
if ($optionalBehavior = '?' === $type[0]) {
|
||||
$type = substr($type, 1);
|
||||
@ -85,18 +86,18 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
}
|
||||
if (!isset($serviceMap[$key])) {
|
||||
if (!$autowire) {
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by %s::getSubscribedServices().', $this->currentId, $key, $class));
|
||||
throw new InvalidArgumentException(sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by "%s::getSubscribedServices()".', $this->currentId, $key, $class));
|
||||
}
|
||||
$serviceMap[$key] = new Reference($type);
|
||||
}
|
||||
|
||||
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $declaringClass, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
unset($serviceMap[$key]);
|
||||
}
|
||||
|
||||
if ($serviceMap = array_keys($serviceMap)) {
|
||||
$message = sprintf(1 < count($serviceMap) ? 'keys "%s" do' : 'key "%s" does', str_replace('%', '%%', implode('", "', $serviceMap)));
|
||||
throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by %s::getSubscribedServices() for service "%s".', $message, $class, $this->currentId));
|
||||
throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId));
|
||||
}
|
||||
|
||||
$serviceLocator = $this->serviceLocator;
|
||||
|
@ -368,9 +368,9 @@ class AutowirePassTest extends TestCase
|
||||
$definition = $container->getDefinition('multiple');
|
||||
$this->assertEquals(
|
||||
array(
|
||||
new Reference(A::class),
|
||||
new TypedReference(A::class, A::class, MultipleArguments::class),
|
||||
new Reference('foo'),
|
||||
new Reference(Dunglas::class),
|
||||
new TypedReference(Dunglas::class, Dunglas::class, MultipleArguments::class),
|
||||
),
|
||||
$definition->getArguments()
|
||||
);
|
||||
@ -423,10 +423,10 @@ class AutowirePassTest extends TestCase
|
||||
$definition = $container->getDefinition('with_optional_scalar');
|
||||
$this->assertEquals(
|
||||
array(
|
||||
new Reference(A::class),
|
||||
new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class),
|
||||
// use the default value
|
||||
'default_val',
|
||||
new Reference(Lille::class),
|
||||
new TypedReference(Lille::class, Lille::class),
|
||||
),
|
||||
$definition->getArguments()
|
||||
);
|
||||
@ -447,8 +447,8 @@ class AutowirePassTest extends TestCase
|
||||
$definition = $container->getDefinition('with_optional_scalar_last');
|
||||
$this->assertEquals(
|
||||
array(
|
||||
new Reference(A::class),
|
||||
new Reference(Lille::class),
|
||||
new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalarLast::class),
|
||||
new TypedReference(Lille::class, Lille::class, MultipleArgumentsOptionalScalarLast::class),
|
||||
),
|
||||
$definition->getArguments()
|
||||
);
|
||||
@ -486,7 +486,7 @@ class AutowirePassTest extends TestCase
|
||||
);
|
||||
// test setFoo args
|
||||
$this->assertEquals(
|
||||
array(new Reference(Foo::class)),
|
||||
array(new TypedReference(Foo::class, Foo::class, SetterInjection::class)),
|
||||
$methodCalls[1][1]
|
||||
);
|
||||
}
|
||||
@ -515,7 +515,7 @@ class AutowirePassTest extends TestCase
|
||||
array_column($methodCalls, 0)
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(new Reference(A::class)),
|
||||
array(new TypedReference(A::class, A::class, SetterInjection::class)),
|
||||
$methodCalls[0][1]
|
||||
);
|
||||
}
|
||||
@ -526,7 +526,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
$container
|
||||
->register('bar', Bar::class)
|
||||
->setProperty('a', array(new TypedReference(A::class, A::class)))
|
||||
->setProperty('a', array(new TypedReference(A::class, A::class, Bar::class)))
|
||||
;
|
||||
|
||||
$pass = new AutowirePass();
|
||||
@ -629,7 +629,7 @@ class AutowirePassTest extends TestCase
|
||||
(new ResolveClassPass())->process($container);
|
||||
(new AutowirePass())->process($container);
|
||||
|
||||
$this->assertEquals(array(new Reference(A::class), '', new Reference(Lille::class)), $container->getDefinition('foo')->getArguments());
|
||||
$this->assertEquals(array(new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class), '', new TypedReference(Lille::class, Lille::class)), $container->getDefinition('foo')->getArguments());
|
||||
}
|
||||
|
||||
public function testWithFactory()
|
||||
@ -644,7 +644,7 @@ class AutowirePassTest extends TestCase
|
||||
(new ResolveClassPass())->process($container);
|
||||
(new AutowirePass())->process($container);
|
||||
|
||||
$this->assertEquals(array(new Reference(Foo::class)), $definition->getArguments());
|
||||
$this->assertEquals(array(new TypedReference(Foo::class, Foo::class, A::class)), $definition->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
require_once __DIR__.'/../Fixtures/includes/classes.php';
|
||||
@ -32,7 +34,7 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', 'stdClass')
|
||||
$container->register('foo', CustomDefinition::class)
|
||||
->addTag('container.service_subscriber')
|
||||
;
|
||||
|
||||
@ -48,7 +50,7 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', 'TestServiceSubscriber')
|
||||
$container->register('foo', TestServiceSubscriber::class)
|
||||
->addTag('container.service_subscriber', array('bar' => '123'))
|
||||
;
|
||||
|
||||
@ -60,7 +62,7 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', 'TestServiceSubscriber')
|
||||
$container->register('foo', TestServiceSubscriber::class)
|
||||
->addArgument(new Reference('container'))
|
||||
->addTag('container.service_subscriber')
|
||||
;
|
||||
@ -75,10 +77,10 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
$this->assertSame(ServiceLocator::class, $locator->getClass());
|
||||
|
||||
$expected = array(
|
||||
'TestServiceSubscriber' => new ServiceClosureArgument(new TypedReference('TestServiceSubscriber', 'TestServiceSubscriber')),
|
||||
'stdClass' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
'bar' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass')),
|
||||
'baz' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class, TestServiceSubscriber::class)),
|
||||
CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
'bar' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class)),
|
||||
'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
@ -88,7 +90,7 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', 'TestServiceSubscriber')
|
||||
$container->register('foo', TestServiceSubscriber::class)
|
||||
->setAutowired(true)
|
||||
->addArgument(new Reference('container'))
|
||||
->addTag('container.service_subscriber', array('key' => 'bar', 'id' => 'bar'))
|
||||
@ -105,10 +107,10 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
$this->assertSame(ServiceLocator::class, $locator->getClass());
|
||||
|
||||
$expected = array(
|
||||
'TestServiceSubscriber' => new ServiceClosureArgument(new TypedReference('TestServiceSubscriber', 'TestServiceSubscriber')),
|
||||
'stdClass' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
'bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass')),
|
||||
'baz' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class, TestServiceSubscriber::class)),
|
||||
CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
'bar' => new ServiceClosureArgument(new TypedReference('bar', CustomDefinition::class, TestServiceSubscriber::class)),
|
||||
'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
@ -116,20 +118,20 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage Service key "test" does not exist in the map returned by TestServiceSubscriber::getSubscribedServices() for service "foo_service".
|
||||
* @expectedExceptionMessage Service key "test" does not exist in the map returned by "Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber::getSubscribedServices()" for service "foo_service".
|
||||
*/
|
||||
public function testExtraServiceSubscriber()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo_service', 'TestServiceSubscriber')
|
||||
$container->register('foo_service', TestServiceSubscriber::class)
|
||||
->setAutowired(true)
|
||||
->addArgument(new Reference('container'))
|
||||
->addTag('container.service_subscriber', array(
|
||||
'key' => 'test',
|
||||
'id' => 'TestServiceSubscriber',
|
||||
'id' => TestServiceSubscriber::class,
|
||||
))
|
||||
;
|
||||
$container->register('TestServiceSubscriber', 'TestServiceSubscriber');
|
||||
$container->register(TestServiceSubscriber::class, TestServiceSubscriber::class);
|
||||
$container->compile();
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
|
||||
use Symfony\Component\DependencyInjection\Variable;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
||||
@ -557,15 +558,15 @@ class PhpDumperTest extends TestCase
|
||||
public function testServiceSubscriber()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo_service', 'TestServiceSubscriber')
|
||||
$container->register('foo_service', TestServiceSubscriber::class)
|
||||
->setAutowired(true)
|
||||
->addArgument(new Reference('container'))
|
||||
->addTag('container.service_subscriber', array(
|
||||
'key' => 'bar',
|
||||
'id' => 'TestServiceSubscriber',
|
||||
'id' => TestServiceSubscriber::class,
|
||||
))
|
||||
;
|
||||
$container->register('TestServiceSubscriber', 'TestServiceSubscriber');
|
||||
$container->register(TestServiceSubscriber::class, TestServiceSubscriber::class);
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
||||
|
||||
class TestServiceSubscriber implements ServiceSubscriberInterface
|
||||
{
|
||||
public function __construct($container)
|
||||
{
|
||||
}
|
||||
|
||||
public static function getSubscribedServices()
|
||||
{
|
||||
return array(
|
||||
__CLASS__,
|
||||
'?'.CustomDefinition::class,
|
||||
'bar' => CustomDefinition::class,
|
||||
'baz' => '?'.CustomDefinition::class,
|
||||
);
|
||||
}
|
||||
}
|
@ -108,20 +108,3 @@ class LazyContext
|
||||
$this->lazyValues = $lazyValues;
|
||||
}
|
||||
}
|
||||
|
||||
class TestServiceSubscriber implements ServiceSubscriberInterface
|
||||
{
|
||||
public function __construct($container)
|
||||
{
|
||||
}
|
||||
|
||||
public static function getSubscribedServices()
|
||||
{
|
||||
return array(
|
||||
__CLASS__,
|
||||
'?stdClass',
|
||||
'bar' => 'stdClass',
|
||||
'baz' => '?stdClass',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -28,19 +28,19 @@ class ProjectServiceContainer extends Container
|
||||
{
|
||||
$this->services = array();
|
||||
$this->normalizedIds = array(
|
||||
'autowired.stdclass' => 'autowired.stdClass',
|
||||
'autowired.symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
|
||||
'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface',
|
||||
'stdclass' => 'stdClass',
|
||||
'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface',
|
||||
'testservicesubscriber' => 'TestServiceSubscriber',
|
||||
'symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
|
||||
'symfony\\component\\dependencyinjection\\tests\\fixtures\\testservicesubscriber' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber',
|
||||
);
|
||||
$this->methodMap = array(
|
||||
'TestServiceSubscriber' => 'getTestServiceSubscriberService',
|
||||
'autowired.stdClass' => 'getAutowired_StdClassService',
|
||||
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService',
|
||||
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getAutowired_Symfony_Component_DependencyInjection_Tests_Fixtures_CustomDefinitionService',
|
||||
'foo_service' => 'getFooServiceService',
|
||||
);
|
||||
$this->privates = array(
|
||||
'autowired.stdClass' => true,
|
||||
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true,
|
||||
);
|
||||
|
||||
$this->aliases = array();
|
||||
@ -73,16 +73,16 @@ class ProjectServiceContainer extends Container
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'TestServiceSubscriber' service.
|
||||
* Gets the 'Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber' service.
|
||||
*
|
||||
* This service is shared.
|
||||
* This method always returns the same instance of the service.
|
||||
*
|
||||
* @return \TestServiceSubscriber A TestServiceSubscriber instance
|
||||
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber A Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber instance
|
||||
*/
|
||||
protected function getTestServiceSubscriberService()
|
||||
protected function getSymfony_Component_DependencyInjection_Tests_Fixtures_TestServiceSubscriberService()
|
||||
{
|
||||
return $this->services['TestServiceSubscriber'] = new \TestServiceSubscriber();
|
||||
return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,23 +93,23 @@ class ProjectServiceContainer extends Container
|
||||
*
|
||||
* This service is autowired.
|
||||
*
|
||||
* @return \TestServiceSubscriber A TestServiceSubscriber instance
|
||||
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber A Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber instance
|
||||
*/
|
||||
protected function getFooServiceService()
|
||||
{
|
||||
return $this->services['foo_service'] = new \TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('TestServiceSubscriber' => function () {
|
||||
$f = function (\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['TestServiceSubscriber']) ? $this->services['TestServiceSubscriber'] : $this->get('TestServiceSubscriber')) && false ?: '_'});
|
||||
return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function () {
|
||||
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getAutowired_Symfony_Component_DependencyInjection_Tests_Fixtures_CustomDefinitionService()) && false ?: '_'});
|
||||
}, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function () {
|
||||
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
|
||||
}, 'bar' => function () {
|
||||
$f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['TestServiceSubscriber']) ? $this->services['TestServiceSubscriber'] : $this->get('TestServiceSubscriber')) && false ?: '_'});
|
||||
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
|
||||
}, 'baz' => function () {
|
||||
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
|
||||
}, 'stdClass' => function () {
|
||||
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
|
||||
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getAutowired_Symfony_Component_DependencyInjection_Tests_Fixtures_CustomDefinitionService()) && false ?: '_'});
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'autowired.stdClass' service.
|
||||
* Gets the 'autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' service.
|
||||
*
|
||||
* This service is shared.
|
||||
* This method always returns the same instance of the service.
|
||||
@ -120,10 +120,10 @@ class ProjectServiceContainer extends Container
|
||||
*
|
||||
* This service is autowired.
|
||||
*
|
||||
* @return \stdClass A stdClass instance
|
||||
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition A Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition instance
|
||||
*/
|
||||
protected function getAutowired_StdClassService()
|
||||
protected function getAutowired_Symfony_Component_DependencyInjection_Tests_Fixtures_CustomDefinitionService()
|
||||
{
|
||||
return $this->services['autowired.stdClass'] = new \stdClass();
|
||||
return $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition();
|
||||
}
|
||||
}
|
||||
|
@ -19,19 +19,19 @@ namespace Symfony\Component\DependencyInjection;
|
||||
class TypedReference extends Reference
|
||||
{
|
||||
private $type;
|
||||
private $canBeAutoregistered;
|
||||
private $requiringClass;
|
||||
|
||||
/**
|
||||
* @param string $id The service identifier
|
||||
* @param string $type The PHP type of the identified service
|
||||
* @param int $invalidBehavior The behavior when the service does not exist
|
||||
* @param bool $canBeAutoregistered Whether autowiring can autoregister the referenced service when it's a FQCN or not
|
||||
* @param string $id The service identifier
|
||||
* @param string $type The PHP type of the identified service
|
||||
* @param string $requiringClass The class of the service that requires the referenced type
|
||||
* @param int $invalidBehavior The behavior when the service does not exist
|
||||
*/
|
||||
public function __construct($id, $type, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $canBeAutoregistered = true)
|
||||
public function __construct($id, $type, $requiringClass = '', $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
parent::__construct($id, $invalidBehavior);
|
||||
$this->type = $type;
|
||||
$this->canBeAutoregistered = $canBeAutoregistered;
|
||||
$this->requiringClass = $requiringClass;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
@ -39,8 +39,13 @@ class TypedReference extends Reference
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getRequiringClass()
|
||||
{
|
||||
return $this->requiringClass;
|
||||
}
|
||||
|
||||
public function canBeAutoregistered()
|
||||
{
|
||||
return $this->canBeAutoregistered;
|
||||
return $this->requiringClass && (false !== $i = strpos($this->type, '\\')) && 0 === strncasecmp($this->type, $this->requiringClass, 1 + $i);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
continue;
|
||||
}
|
||||
$class = $def->getClass();
|
||||
$autowire = $def->isAutowired();
|
||||
|
||||
// resolve service class, taking parent definitions into account
|
||||
while (!$class && $def instanceof ChildDefinition) {
|
||||
@ -76,6 +77,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
// validate and collect explicit per-actions and per-arguments service references
|
||||
foreach ($tags as $attributes) {
|
||||
if (!isset($attributes['action']) && !isset($attributes['argument']) && !isset($attributes['id'])) {
|
||||
$autowire = true;
|
||||
continue;
|
||||
}
|
||||
foreach (array('action', 'argument', 'id') as $k) {
|
||||
@ -120,11 +122,11 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
} elseif ($p->allowsNull() && !$p->isOptional()) {
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
|
||||
}
|
||||
} elseif (!$type) {
|
||||
} elseif (!$type || !$autowire) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, false) : new Reference($target, $invalidBehavior);
|
||||
$args[$p->name] = $type ? new TypedReference($target, $type, $r->class, $invalidBehavior) : new Reference($target, $invalidBehavior);
|
||||
}
|
||||
// register the maps as a per-method service-locators
|
||||
if ($args) {
|
||||
|
@ -43,7 +43,7 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
|
||||
if (!$argumentLocator->getArgument(0)) {
|
||||
// remove empty argument locators
|
||||
$reason = sprintf('Removing service-argument-resolver for controller "%s": no corresponding definitions were found for the referenced services/types.%s', $controller, !$argumentLocator->isAutowired() ? ' Did you forget to enable autowiring?' : '');
|
||||
$reason = sprintf('Removing service-argument resolver for controller "%s": no corresponding services exist for the referenced types.', $controller);
|
||||
} else {
|
||||
// any methods listed for call-at-instantiation cannot be actions
|
||||
$reason = false;
|
||||
|
@ -145,7 +145,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$this->assertSame(ServiceLocator::class, $locator->getClass());
|
||||
$this->assertFalse($locator->isPublic());
|
||||
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE, false)));
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, RegisterTestController::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
$locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]);
|
||||
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false)));
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, RegisterTestController::class)));
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
}
|
||||
|
||||
@ -184,22 +184,26 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
$locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]);
|
||||
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE, false)));
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, RegisterTestController::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)));
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
||||
class RegisterTestController
|
||||
{
|
||||
public function __construct(\stdClass $bar)
|
||||
public function __construct(ControllerDummy $bar)
|
||||
{
|
||||
}
|
||||
|
||||
public function fooAction(\stdClass $bar)
|
||||
public function fooAction(ControllerDummy $bar)
|
||||
{
|
||||
}
|
||||
|
||||
protected function barAction(\stdClass $bar)
|
||||
protected function barAction(ControllerDummy $bar)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class ControllerDummy
|
||||
{
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
|
||||
$this->assertSame(array('bar'), array_keys($container->getDefinition((string) $controllers['c1:fooAction']->getValues()[0])->getArgument(0)));
|
||||
|
||||
$expectedLog = array(
|
||||
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument-resolver for controller "c2:fooAction": no corresponding definitions were found for the referenced services/types. Did you forget to enable autowiring?',
|
||||
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller "c2:fooAction": no corresponding services exist for the referenced types.',
|
||||
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.',
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user