[DI] add ServiceLocatorTagPass::register() to share service locators
This commit is contained in:
parent
e3d99649aa
commit
8ff764be82
@ -11,11 +11,10 @@
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
|
||||
class TranslatorPass implements CompilerPassInterface
|
||||
{
|
||||
@ -46,7 +45,7 @@ class TranslatorPass implements CompilerPassInterface
|
||||
|
||||
$container
|
||||
->findDefinition('translator.default')
|
||||
->replaceArgument(0, (new Definition(ServiceLocator::class, array($loaderRefs)))->addTag('container.service_locator'))
|
||||
->replaceArgument(0, ServiceLocatorTagPass::register($container, $loaderRefs))
|
||||
->replaceArgument(3, $loaders)
|
||||
;
|
||||
}
|
||||
|
@ -41,11 +41,12 @@ class AddConstraintValidatorsPassTest extends TestCase
|
||||
$addConstraintValidatorsPass = new AddConstraintValidatorsPass();
|
||||
$addConstraintValidatorsPass->process($container);
|
||||
|
||||
$this->assertEquals((new Definition(ServiceLocator::class, array(array(
|
||||
$expected = (new Definition(ServiceLocator::class, array(array(
|
||||
Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
|
||||
'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
|
||||
Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')),
|
||||
))))->addTag('container.service_locator'), $validatorFactory->getArgument(0));
|
||||
))))->addTag('container.service_locator')->setPublic(false);
|
||||
$this->assertEquals($expected, $container->getDefinition((string) $validatorFactory->getArgument(0)));
|
||||
}
|
||||
|
||||
public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition()
|
||||
|
@ -53,7 +53,7 @@ class FormPassTest extends TestCase
|
||||
(new Definition(ServiceLocator::class, array(array(
|
||||
__CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')),
|
||||
__CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')),
|
||||
))))->addTag('container.service_locator'),
|
||||
))))->addTag('container.service_locator')->setPublic(false),
|
||||
$extDefinition->getArgument(0)
|
||||
);
|
||||
}
|
||||
|
@ -12,45 +12,39 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslatorPass;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
class TranslatorPassTest extends TestCase
|
||||
{
|
||||
public function testValidCollector()
|
||||
{
|
||||
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock();
|
||||
$definition->expects($this->at(0))
|
||||
->method('addMethodCall')
|
||||
->with('addLoader', array('xliff', new Reference('xliff')));
|
||||
$definition->expects($this->at(1))
|
||||
->method('addMethodCall')
|
||||
->with('addLoader', array('xlf', new Reference('xliff')));
|
||||
$loader = (new Definition())
|
||||
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'));
|
||||
|
||||
$translator = (new Definition())
|
||||
->setArguments(array(null, null, null, null));
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->setDefinition('translator.default', $translator);
|
||||
$container->setDefinition('translation.loader', $loader);
|
||||
|
||||
$container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')->setMethods(array('hasDefinition', 'getDefinition', 'findTaggedServiceIds', 'findDefinition'))->getMock();
|
||||
$container->expects($this->any())
|
||||
->method('hasDefinition')
|
||||
->will($this->returnValue(true));
|
||||
$container->expects($this->once())
|
||||
->method('getDefinition')
|
||||
->will($this->returnValue($definition));
|
||||
$container->expects($this->once())
|
||||
->method('findTaggedServiceIds')
|
||||
->will($this->returnValue(array('xliff' => array(array('alias' => 'xliff', 'legacy-alias' => 'xlf')))));
|
||||
$container->expects($this->once())
|
||||
->method('findDefinition')
|
||||
->will($this->returnValue($translator = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock()));
|
||||
$translator->expects($this->at(0))
|
||||
->method('replaceArgument')
|
||||
->with(0, $this->equalTo((new Definition(ServiceLocator::class, array(array('xliff' => new Reference('xliff')))))->addTag('container.service_locator')))
|
||||
->willReturn($translator);
|
||||
$translator->expects($this->at(1))
|
||||
->method('replaceArgument')
|
||||
->with(3, array('xliff' => array('xliff', 'xlf')))
|
||||
->willReturn($translator);
|
||||
$pass = new TranslatorPass();
|
||||
$pass->process($container);
|
||||
|
||||
$expected = (new Definition())
|
||||
->addTag('translation.loader', array('alias' => 'xliff', 'legacy-alias' => 'xlf'))
|
||||
->addMethodCall('addLoader', array('xliff', new Reference('translation.loader')))
|
||||
->addMethodCall('addLoader', array('xlf', new Reference('translation.loader')))
|
||||
;
|
||||
$this->assertEquals($expected, $loader);
|
||||
|
||||
$this->assertSame(array('translation.loader' => array('xliff', 'xlf')), $translator->getArgument(3));
|
||||
|
||||
$expected = array('translation.loader' => new ServiceClosureArgument(new Reference('translation.loader')));
|
||||
$this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
@ -17,14 +17,13 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
|
||||
|
||||
@ -262,10 +261,10 @@ class SecurityExtension extends Extension
|
||||
->replaceArgument(2, new Reference($configId))
|
||||
;
|
||||
|
||||
$contextRefs[$contextId] = new ServiceClosureArgument(new Reference($contextId));
|
||||
$contextRefs[$contextId] = new Reference($contextId);
|
||||
$map[$contextId] = $matcher;
|
||||
}
|
||||
$mapDef->replaceArgument(0, (new Definition(ServiceLocator::class, array($contextRefs)))->addTag('container.service_locator'));
|
||||
$mapDef->replaceArgument(0, ServiceLocatorTagPass::register($container, $contextRefs));
|
||||
$mapDef->replaceArgument(1, new IteratorArgument($map));
|
||||
|
||||
// add authentication providers to authentication manager
|
||||
|
@ -11,12 +11,10 @@
|
||||
|
||||
namespace Symfony\Bundle\TwigBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
/**
|
||||
* Registers Twig runtime services.
|
||||
@ -38,9 +36,9 @@ class RuntimeLoaderPass implements CompilerPassInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapping[$def->getClass()] = new ServiceClosureArgument(new Reference($id));
|
||||
$mapping[$def->getClass()] = new Reference($id);
|
||||
}
|
||||
|
||||
$definition->replaceArgument(0, (new Definition(ServiceLocator::class, array($mapping)))->addTag('container.service_locator'));
|
||||
$definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $mapping));
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ class TwigExtensionTest extends TestCase
|
||||
$container->compile();
|
||||
|
||||
$loader = $container->getDefinition('twig.runtime_loader');
|
||||
$args = $loader->getArgument(0)->getArgument(0);
|
||||
$args = $container->getDefinition((string) $loader->getArgument(0))->getArgument(0);
|
||||
$this->assertArrayHasKey('Symfony\Bridge\Twig\Form\TwigRenderer', $args);
|
||||
$this->assertArrayHasKey('FooClass', $args);
|
||||
$this->assertEquals('twig.form.renderer', $args['Symfony\Bridge\Twig\Form\TwigRenderer']->getValues()[0]);
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Argument;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Represents a service wrapped in a memoizing closure.
|
||||
@ -28,11 +28,17 @@ class ServiceClosureArgument implements ArgumentInterface
|
||||
$this->values = array($reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValues(array $values)
|
||||
{
|
||||
if (array(0) !== array_keys($values) || !($values[0] instanceof Reference || null === $values[0])) {
|
||||
|
@ -11,13 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
/**
|
||||
@ -87,7 +85,7 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
$serviceMap[$key] = new Reference($type);
|
||||
}
|
||||
|
||||
$subscriberMap[$key] = new ServiceClosureArgument(new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE));
|
||||
$subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
unset($serviceMap[$key]);
|
||||
}
|
||||
|
||||
@ -97,12 +95,7 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
$serviceLocator = $this->serviceLocator;
|
||||
$this->serviceLocator = 'container.'.$this->currentId.'.'.md5(serialize($value));
|
||||
$this->container->register($this->serviceLocator, ServiceLocator::class)
|
||||
->addArgument($subscriberMap)
|
||||
->setPublic(false)
|
||||
->setAutowired($value->isAutowired())
|
||||
->addTag('container.service_locator');
|
||||
$this->serviceLocator = (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $value->getAutowired());
|
||||
|
||||
try {
|
||||
return parent::processValue($value);
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -22,7 +24,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
final class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
{
|
||||
protected function processValue($value, $isRoot = false)
|
||||
{
|
||||
@ -48,7 +50,52 @@ class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
}
|
||||
$arguments[0][$k] = new ServiceClosureArgument($v);
|
||||
}
|
||||
ksort($arguments[0]);
|
||||
|
||||
return $value->setArguments($arguments);
|
||||
$value->setArguments($arguments);
|
||||
|
||||
if ($public = $value->isPublic()) {
|
||||
$value->setPublic(false);
|
||||
}
|
||||
$id = 'service_locator.'.md5(serialize($value));
|
||||
|
||||
if ($isRoot) {
|
||||
if ($id !== $this->currentId) {
|
||||
$this->container->setAlias($id, new Alias($this->currentId, $public));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
$this->container->setDefinition($id, $value);
|
||||
|
||||
return new Reference($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @param Reference[] $refMap
|
||||
* @param int|bool $autowired
|
||||
*
|
||||
* @return Reference
|
||||
*/
|
||||
public static function register(ContainerBuilder $container, array $refMap, $autowired = false)
|
||||
{
|
||||
foreach ($refMap as $id => $ref) {
|
||||
$refMap[$id] = new ServiceClosureArgument($ref);
|
||||
}
|
||||
ksort($refMap);
|
||||
|
||||
$locator = (new Definition(ServiceLocator::class))
|
||||
->addArgument($refMap)
|
||||
->setPublic(false)
|
||||
->setAutowired($autowired)
|
||||
->addTag('container.service_locator');
|
||||
|
||||
if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) {
|
||||
$container->setDefinition($id, $locator);
|
||||
}
|
||||
|
||||
return new Reference($id);
|
||||
}
|
||||
}
|
||||
|
@ -99,12 +99,12 @@ class ProjectServiceContainer extends Container
|
||||
{
|
||||
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 ?: '_'});
|
||||
}, 'stdClass' => function () {
|
||||
$f = function (\stdClass $v = null) { return $v; }; return $f(${($_ = isset($this->services['autowired.stdClass']) ? $this->services['autowired.stdClass'] : $this->getAutowired_StdClassService()) && false ?: '_'});
|
||||
}, 'bar' => function () {
|
||||
$f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['TestServiceSubscriber']) ? $this->services['TestServiceSubscriber'] : $this->get('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 ?: '_'});
|
||||
})));
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,13 @@
|
||||
namespace Symfony\Component\Form\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
/**
|
||||
* Adds all services with the tags "form.type", "form.type_extension" and
|
||||
@ -60,17 +59,16 @@ class FormPass implements CompilerPassInterface
|
||||
{
|
||||
// Get service locator argument
|
||||
$servicesMap = array();
|
||||
$locator = $definition->getArgument(0);
|
||||
|
||||
// Builds an array with fully-qualified type class names as keys and service IDs as values
|
||||
foreach ($container->findTaggedServiceIds($this->formTypeTag) as $serviceId => $tag) {
|
||||
$serviceDefinition = $container->getDefinition($serviceId);
|
||||
|
||||
// Add form type service to the service locator
|
||||
$servicesMap[$serviceDefinition->getClass()] = new ServiceClosureArgument(new Reference($serviceId));
|
||||
$servicesMap[$serviceDefinition->getClass()] = new Reference($serviceId);
|
||||
}
|
||||
|
||||
return (new Definition(ServiceLocator::class, array($servicesMap)))->addTag('container.service_locator');
|
||||
return ServiceLocatorTagPass::register($container, $servicesMap);
|
||||
}
|
||||
|
||||
private function processFormTypeExtensions(ContainerBuilder $container)
|
||||
|
@ -51,7 +51,7 @@ class FormPassTest extends TestCase
|
||||
(new Definition(ServiceLocator::class, array(array(
|
||||
__CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')),
|
||||
__CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')),
|
||||
))))->addTag('container.service_locator'),
|
||||
))))->addTag('container.service_locator')->setPublic(false),
|
||||
$extDefinition->getArgument(0)
|
||||
);
|
||||
}
|
||||
|
@ -11,13 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
|
||||
|
||||
/**
|
||||
@ -64,10 +62,10 @@ class FragmentRendererPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$renderers[$tag['alias']] = new ServiceClosureArgument(new Reference($id));
|
||||
$renderers[$tag['alias']] = new Reference($id);
|
||||
}
|
||||
}
|
||||
|
||||
$definition->replaceArgument(0, (new Definition(ServiceLocator::class, array($renderers)))->addTag('container.service_locator'));
|
||||
$definition->replaceArgument(0, ServiceLocatorTagPass::register($container, $renderers));
|
||||
}
|
||||
}
|
||||
|
@ -11,15 +11,13 @@
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\LazyProxy\ProxyHelper;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
/**
|
||||
@ -54,7 +52,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
continue;
|
||||
}
|
||||
$class = $def->getClass();
|
||||
$isAutowired = $def->isAutowired();
|
||||
$autowired = $def->getAutowired();
|
||||
|
||||
// resolve service class, taking parent definitions into account
|
||||
while (!$class && $def instanceof ChildDefinition) {
|
||||
@ -127,25 +125,16 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
$args[$p->name] = new ServiceClosureArgument($type ? new TypedReference($target, $type, $invalidBehavior, false) : new Reference($target, $invalidBehavior));
|
||||
$args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, false) : new Reference($target, $invalidBehavior);
|
||||
}
|
||||
// register the maps as a per-method service-locators
|
||||
if ($args) {
|
||||
$argsId = sprintf('arguments.%s:%s', $id, $r->name);
|
||||
$container->register($argsId, ServiceLocator::class)
|
||||
->addArgument($args)
|
||||
->setPublic(false)
|
||||
->setAutowired($isAutowired)
|
||||
->addTag('controller.arguments_locator', array($class, $id, $r->name));
|
||||
$controllers[$id.':'.$r->name] = new ServiceClosureArgument(new Reference($argsId));
|
||||
if ($id === $class) {
|
||||
$controllers[$id.'::'.$r->name] = new ServiceClosureArgument(new Reference($argsId));
|
||||
}
|
||||
$controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args, $autowired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$container->getDefinition($this->resolverServiceId)
|
||||
->replaceArgument(0, (new Definition(ServiceLocator::class, array($controllers)))->addTag('container.service_locator'));
|
||||
->replaceArgument(0, ServiceLocatorTagPass::register($container, $controllers));
|
||||
}
|
||||
}
|
||||
|
@ -35,37 +35,39 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
$serviceResolver = $container->getDefinition($this->resolverServiceId);
|
||||
$controllers = $serviceResolver->getArgument(0)->getArgument(0);
|
||||
$controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0));
|
||||
$controllers = $controllerLocator->getArgument(0);
|
||||
|
||||
foreach ($container->findTaggedServiceIds('controller.arguments_locator') as $id => $tags) {
|
||||
$argumentLocator = $container->getDefinition($id)->clearTag('controller.arguments_locator');
|
||||
list($class, $service, $action) = $tags[0];
|
||||
foreach ($controllers as $controller => $argumentRef) {
|
||||
$argumentLocator = $container->getDefinition((string) $argumentRef->getValues()[0]);
|
||||
|
||||
if (!$argumentLocator->getArgument(0)) {
|
||||
// remove empty argument locators
|
||||
$reason = sprintf('Removing service-argument-resolver for controller "%s:%s": no corresponding definitions were found for the referenced services/types.%s', $service, $action, !$argumentLocator->isAutowired() ? ' Did you forget to enable autowiring?' : '');
|
||||
$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?' : '');
|
||||
} else {
|
||||
// any methods listed for call-at-instantiation cannot be actions
|
||||
$reason = false;
|
||||
foreach ($container->getDefinition($service)->getMethodCalls() as list($method, $args)) {
|
||||
$action = substr(strrchr($controller, ':'), 1);
|
||||
$id = substr($controller, 0, -1 - strlen($action));
|
||||
$controllerDef = $container->getDefinition($id);
|
||||
foreach ($controllerDef->getMethodCalls() as list($method, $args)) {
|
||||
if (0 === strcasecmp($action, $method)) {
|
||||
$reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $service);
|
||||
$reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$reason) {
|
||||
if ($controllerDef->getClass() === $id) {
|
||||
$controllers[$id.'::'.$action] = $argumentRef;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$container->removeDefinition($id);
|
||||
unset($controllers[$service.':'.$action]);
|
||||
if ($service === $class) {
|
||||
unset($controllers[$service.'::'.$action]);
|
||||
}
|
||||
unset($controllers[$controller]);
|
||||
$container->log($this, $reason);
|
||||
}
|
||||
|
||||
$serviceResolver->getArgument(0)->replaceArgument(0, $controllers);
|
||||
$controllerLocator->replaceArgument(0, $controllers);
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,7 @@
|
||||
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
|
||||
@ -65,7 +62,7 @@ class FragmentRendererPassTest extends TestCase
|
||||
$renderer
|
||||
->expects($this->once())
|
||||
->method('replaceArgument')
|
||||
->with(0, $this->equalTo((new Definition(ServiceLocator::class, array(array('foo' => new ServiceClosureArgument(new Reference('my_content_renderer'))))))->addTag('container.service_locator')));
|
||||
->with(0, $this->equalTo(new Reference('service_locator.5ae0a401097c64ca63ed976c71bc9642')));
|
||||
|
||||
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock();
|
||||
$definition->expects($this->atLeastOnce())
|
||||
|
@ -15,7 +15,6 @@ use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
@ -128,7 +127,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
public function testAllActions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('argument_resolver.service')->addArgument(array());
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register('foo', RegisterTestController::class)
|
||||
->setAutowired(true)
|
||||
@ -138,12 +137,12 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$pass = new RegisterControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$expected = new Definition(ServiceLocator::class);
|
||||
$expected->addArgument(array('foo:fooAction' => new ServiceClosureArgument(new Reference('arguments.foo:fooAction'))));
|
||||
$expected->addTag('container.service_locator');
|
||||
$this->assertEquals($expected, $container->getDefinition('argument_resolver.service')->getArgument(0));
|
||||
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
|
||||
$this->assertEquals(array('foo:fooAction' => new ServiceClosureArgument(new Reference('service_locator.d964744f7278cba85dee823607f8c07f'))), $locator);
|
||||
|
||||
$locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]);
|
||||
|
||||
$locator = $container->getDefinition('arguments.foo:fooAction');
|
||||
$this->assertSame(ServiceLocator::class, $locator->getClass());
|
||||
$this->assertFalse($locator->isPublic());
|
||||
$this->assertTrue($locator->isAutowired());
|
||||
@ -155,7 +154,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
public function testExplicitArgument()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('argument_resolver.service')->addArgument(array());
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register('foo', RegisterTestController::class)
|
||||
->addTag('controller.service_arguments', array('action' => 'fooAction', 'argument' => 'bar', 'id' => 'bar'))
|
||||
@ -165,7 +164,8 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$pass = new RegisterControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$locator = $container->getDefinition('arguments.foo:fooAction');
|
||||
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
$locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]);
|
||||
$this->assertFalse($locator->isAutowired());
|
||||
|
||||
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false)));
|
||||
@ -175,7 +175,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
public function testOptionalArgument()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('argument_resolver.service')->addArgument(array());
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register('foo', RegisterTestController::class)
|
||||
->addTag('controller.service_arguments', array('action' => 'fooAction', 'argument' => 'bar', 'id' => '?bar'))
|
||||
@ -184,30 +184,12 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$pass = new RegisterControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$locator = $container->getDefinition('arguments.foo:fooAction');
|
||||
$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)));
|
||||
$this->assertEquals($expected, $locator->getArgument(0));
|
||||
}
|
||||
|
||||
public function testSameIdClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register(RegisterTestController::class, RegisterTestController::class)
|
||||
->addTag('controller.service_arguments')
|
||||
;
|
||||
|
||||
$pass = new RegisterControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$expected = array(
|
||||
RegisterTestController::class.':fooAction' => new ServiceClosureArgument(new Reference('arguments.'.RegisterTestController::class.':fooAction')),
|
||||
RegisterTestController::class.'::fooAction' => new ServiceClosureArgument(new Reference('arguments.'.RegisterTestController::class.':fooAction')),
|
||||
);
|
||||
$this->assertEquals($expected, $resolver->getArgument(0)->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
||||
class RegisterTestController
|
||||
|
@ -24,7 +24,7 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('argument_resolver.service')->addArgument(array());
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register('stdClass', 'stdClass');
|
||||
$container->register(parent::class, 'stdClass');
|
||||
@ -35,33 +35,49 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
|
||||
$pass = new RegisterControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(2, $container->getDefinition('arguments.c1:fooAction')->getArgument(0));
|
||||
$this->assertCount(1, $container->getDefinition('arguments.c2:setTestCase')->getArgument(0));
|
||||
$this->assertCount(1, $container->getDefinition('arguments.c2:fooAction')->getArgument(0));
|
||||
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
|
||||
$pass = new ResolveInvalidReferencesPass();
|
||||
$pass->process($container);
|
||||
$this->assertCount(2, $container->getDefinition((string) $controllers['c1:fooAction']->getValues()[0])->getArgument(0));
|
||||
$this->assertCount(1, $container->getDefinition((string) $controllers['c2:setTestCase']->getValues()[0])->getArgument(0));
|
||||
$this->assertCount(1, $container->getDefinition((string) $controllers['c2:fooAction']->getValues()[0])->getArgument(0));
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('arguments.c2:setTestCase')->getArgument(0));
|
||||
$this->assertSame(array(), $container->getDefinition('arguments.c2:fooAction')->getArgument(0));
|
||||
(new ResolveInvalidReferencesPass())->process($container);
|
||||
|
||||
$pass = new RemoveEmptyControllerArgumentLocatorsPass();
|
||||
$pass->process($container);
|
||||
$this->assertCount(1, $container->getDefinition((string) $controllers['c2:setTestCase']->getValues()[0])->getArgument(0));
|
||||
$this->assertSame(array(), $container->getDefinition((string) $controllers['c2:fooAction']->getValues()[0])->getArgument(0));
|
||||
|
||||
$this->assertFalse($container->hasDefinition('arguments.c2:setTestCase'));
|
||||
$this->assertFalse($container->hasDefinition('arguments.c2:fooAction'));
|
||||
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('arguments.c1:fooAction')->getArgument(0));
|
||||
$this->assertArrayHasKey('bar', $container->getDefinition('arguments.c1:fooAction')->getArgument(0));
|
||||
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
|
||||
|
||||
$this->assertSame(array('c1:fooAction'), array_keys($controllers));
|
||||
$this->assertSame(array('bar'), array_keys($container->getDefinition((string) $controllers['c1:fooAction']->getValues()[0])->getArgument(0)));
|
||||
|
||||
$expectedLog = array(
|
||||
'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.',
|
||||
'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 method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.',
|
||||
);
|
||||
|
||||
$this->assertSame($expectedLog, $container->getCompiler()->getLog());
|
||||
}
|
||||
|
||||
$this->assertEquals(array('c1:fooAction' => new ServiceClosureArgument(new Reference('arguments.c1:fooAction'))), $container->getDefinition('argument_resolver.service')->getArgument(0)->getArgument(0));
|
||||
public function testSameIdClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register(RegisterTestController::class, RegisterTestController::class)
|
||||
->addTag('controller.service_arguments')
|
||||
;
|
||||
|
||||
(new RegisterControllerArgumentLocatorsPass())->process($container);
|
||||
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
|
||||
|
||||
$expected = array(
|
||||
RegisterTestController::class.':fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')),
|
||||
RegisterTestController::class.'::fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')),
|
||||
);
|
||||
$this->assertEquals($expected, $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,12 +11,10 @@
|
||||
|
||||
namespace Symfony\Component\Validator\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
|
||||
/**
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
@ -48,15 +46,15 @@ class AddConstraintValidatorsPass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
if (isset($attributes[0]['alias'])) {
|
||||
$validators[$attributes[0]['alias']] = new ServiceClosureArgument(new Reference($id));
|
||||
$validators[$attributes[0]['alias']] = new Reference($id);
|
||||
}
|
||||
|
||||
$validators[$definition->getClass()] = new ServiceClosureArgument(new Reference($id));
|
||||
$validators[$definition->getClass()] = new Reference($id);
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('validator.validator_factory')
|
||||
->replaceArgument(0, (new Definition(ServiceLocator::class, array($validators)))->addTag('container.service_locator'))
|
||||
->replaceArgument(0, ServiceLocatorTagPass::register($container, $validators))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -38,11 +38,12 @@ class AddConstraintValidatorsPassTest extends TestCase
|
||||
$addConstraintValidatorsPass = new AddConstraintValidatorsPass();
|
||||
$addConstraintValidatorsPass->process($container);
|
||||
|
||||
$this->assertEquals((new Definition(ServiceLocator::class, array(array(
|
||||
$expected = (new Definition(ServiceLocator::class, array(array(
|
||||
Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
|
||||
'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')),
|
||||
Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')),
|
||||
))))->addTag('container.service_locator'), $validatorFactory->getArgument(0));
|
||||
))))->addTag('container.service_locator')->setPublic(false);
|
||||
$this->assertEquals($expected, $container->getDefinition((string) $validatorFactory->getArgument(0)));
|
||||
}
|
||||
|
||||
public function testThatCompilerPassIsIgnoredIfThereIsNoConstraintValidatorFactoryDefinition()
|
||||
|
Reference in New Issue
Block a user