feature #22200 [DI] Reference tagged services in config (ro0NL)
This PR was merged into the 3.4 branch.
Discussion
----------
[DI] Reference tagged services in config
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #12269
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/issues/8404
This is a proof of concept to reference a sequence of tagged services.
The problem bugs me for some time, and at first i thought the solution was to have some super generic compiler pass. If it could replace a lot of compilers in core.. perhaps worth it, but eventually each tag comes with it's own logic, including how to deal with tag attributes.
However, writing the passes over and over again becomes tedious for the most basic usecase. So given the recent developments, this idea came to mind.
```yml
services:
a:
class: stdClass
properties: { a: true }
tags: [foo]
b:
class: stdClass
properties: { b: true }
tags: [foo]
c:
class: stdClass
properties:
#stds: !tagged_services foo (see #22198)
stds: !tagged_services
foo
```
```
dump(iterator_to_array($this->get('c')->stds));
```
```
array:2 [▼
0 => {#5052 ▼
+"a": true
}
1 => {#4667 ▼
+"b": true
}
]
```
Given the _basic_ example at https://symfony.com/doc/current/service_container/tags.html, this could replace that.
Any thoughts?
Commits
-------
979e58f
[DI] Reference tagged services in config
This commit is contained in:
commit
648a8953dd
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Argument;
|
||||
|
||||
/**
|
||||
* Represents a collection of services found by tag name to lazily iterate over.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class TaggedIteratorArgument extends IteratorArgument
|
||||
{
|
||||
private $tag;
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*/
|
||||
public function __construct($tag)
|
||||
{
|
||||
parent::__construct(array());
|
||||
|
||||
$this->tag = (string) $tag;
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ CHANGELOG
|
||||
* deprecated support for top-level anonymous services in XML
|
||||
* deprecated case insensitivity of parameter names
|
||||
* deprecated the `ResolveDefinitionTemplatesPass` class in favor of `ResolveChildDefinitionsPass`
|
||||
* added `TaggedIteratorArgument` with YAML (`!tagged foo`) and XML (`<service type="tagged"/>`) support
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
@ -61,6 +61,7 @@ class PassConfig
|
||||
new AutowireRequiredMethodsPass(),
|
||||
new ResolveBindingsPass(),
|
||||
new AutowirePass(false),
|
||||
new ResolveTaggedIteratorArgumentPass(),
|
||||
new ResolveServiceSubscribersPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
|
||||
/**
|
||||
* Resolves all TaggedIteratorArgument arguments.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function processValue($value, $isRoot = false)
|
||||
{
|
||||
if (!$value instanceof TaggedIteratorArgument) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -298,6 +299,9 @@ class XmlDumper extends Dumper
|
||||
if (is_array($value)) {
|
||||
$element->setAttribute('type', 'collection');
|
||||
$this->convertParameters($value, $type, $element, 'key');
|
||||
} elseif ($value instanceof TaggedIteratorArgument) {
|
||||
$element->setAttribute('type', 'tagged');
|
||||
$element->setAttribute('tag', $value->getTag());
|
||||
} elseif ($value instanceof IteratorArgument) {
|
||||
$element->setAttribute('type', 'iterator');
|
||||
$this->convertParameters($value->getValues(), $type, $element, 'key');
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
@ -263,6 +264,9 @@ class YamlDumper extends Dumper
|
||||
$value = $value->getValues()[0];
|
||||
}
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
if ($value instanceof TaggedIteratorArgument) {
|
||||
return new TaggedValue('tagged', $value->getTag());
|
||||
}
|
||||
if ($value instanceof IteratorArgument) {
|
||||
$tag = 'iterator';
|
||||
} else {
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
@ -115,6 +116,18 @@ function iterator(array $values)
|
||||
return new IteratorArgument(AbstractConfigurator::processValue($values, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lazy iterator by tag name.
|
||||
*
|
||||
* @param string $tag
|
||||
*
|
||||
* @return TaggedIteratorArgument
|
||||
*/
|
||||
function tagged($tag)
|
||||
{
|
||||
return new TaggedIteratorArgument($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an expression.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
@ -518,6 +519,12 @@ class XmlFileLoader extends FileLoader
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
|
||||
}
|
||||
break;
|
||||
case 'tagged':
|
||||
if (!$arg->getAttribute('tag')) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file));
|
||||
}
|
||||
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'));
|
||||
break;
|
||||
case 'string':
|
||||
$arguments[$key] = $arg->nodeValue;
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
@ -726,6 +727,13 @@ class YamlFileLoader extends FileLoader
|
||||
throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
|
||||
}
|
||||
}
|
||||
if ('tagged' === $value->getTag()) {
|
||||
if (!is_string($argument) || !$argument) {
|
||||
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
|
||||
}
|
||||
|
||||
return new TaggedIteratorArgument($argument);
|
||||
}
|
||||
if ('service' === $value->getTag()) {
|
||||
if ($isParameter) {
|
||||
throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file));
|
||||
|
@ -208,6 +208,7 @@
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="on-invalid" type="invalid_sequence" />
|
||||
<xsd:attribute name="strict" type="boolean" />
|
||||
<xsd:attribute name="tag" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="bind" mixed="true">
|
||||
@ -233,6 +234,7 @@
|
||||
<xsd:attribute name="index" type="xsd:integer" />
|
||||
<xsd:attribute name="on-invalid" type="invalid_sequence" />
|
||||
<xsd:attribute name="strict" type="boolean" />
|
||||
<xsd:attribute name="tag" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="call">
|
||||
@ -258,6 +260,7 @@
|
||||
<xsd:enumeration value="string" />
|
||||
<xsd:enumeration value="constant" />
|
||||
<xsd:enumeration value="iterator" />
|
||||
<xsd:enumeration value="tagged" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveTaggedIteratorArgumentPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ResolveTaggedIteratorArgumentPassTest extends TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a', 'stdClass')->addTag('foo');
|
||||
$container->register('b', 'stdClass')->addTag('foo', array('priority' => 20));
|
||||
$container->register('c', 'stdClass')->addTag('foo', array('priority' => 10));
|
||||
$container->register('d', 'stdClass')->setProperty('foos', new TaggedIteratorArgument('foo'));
|
||||
|
||||
(new ResolveTaggedIteratorArgumentPass())->process($container);
|
||||
|
||||
$properties = $container->getDefinition('d')->getProperties();
|
||||
$expected = new TaggedIteratorArgument('foo');
|
||||
$expected->setValues(array(new Reference('b'), new Reference('c'), new Reference('a')));
|
||||
$this->assertEquals($expected, $properties['foos']);
|
||||
}
|
||||
}
|
@ -5,9 +5,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use App\BarService;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$s = $c->services();
|
||||
$s->set(BarService::class)
|
||||
->args(array(inline('FooClass')));
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use App\BarService;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->services()
|
||||
->set('bar', 'Class1')
|
||||
->set(BarService::class)
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
->parent('bar')
|
||||
->parent(BarService::class)
|
||||
;
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->import('basic.php');
|
||||
|
||||
$s = $c->services()->defaults()
|
||||
@ -19,5 +18,4 @@ return function (ContainerConfigurator $c) {
|
||||
|
||||
$s->set(Foo::class)->args(array(ref('bar')))->public();
|
||||
$s->set('bar', Foo::class)->call('setFoo')->autoconfigure(false);
|
||||
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ use App\FooService;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$s = $c->services();
|
||||
$s->instanceof(Prototype\Foo::class)
|
||||
->property('p', 0)
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
$s->load(Prototype::class.'\\', '../Prototype')->exclude('../Prototype/*/*');
|
||||
|
||||
$s->set('foo', FooService::class);
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->parameters()
|
||||
('foo', 'Foo')
|
||||
('bar', 'Bar')
|
||||
@ -17,5 +16,4 @@ return function (ContainerConfigurator $c) {
|
||||
('bar', Foo::class)
|
||||
->call('setFoo')
|
||||
;
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$di = $c->services()->defaults()
|
||||
->tag('baz');
|
||||
$di->load(Prototype::class.'\\', '../Prototype')
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
->parent('foo');
|
||||
$di->set('foo')->lazy()->abstract();
|
||||
$di->get(Prototype\Foo::class)->lazy(false);
|
||||
|
||||
};
|
||||
|
@ -9,7 +9,6 @@ require_once __DIR__.'/../includes/classes.php';
|
||||
require_once __DIR__.'/../includes/foo.php';
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$p = $c->parameters();
|
||||
$p->set('baz_class', 'BazClass');
|
||||
$p->set('foo_class', FooClass::class)
|
||||
@ -119,4 +118,11 @@ return function (ContainerConfigurator $c) {
|
||||
$s->set('lazy_context_ignore_invalid_ref', 'LazyContext')
|
||||
->args(array(iterator(array(ref('foo.baz'), ref('invalid')->ignoreOnInvalid())), iterator(array())));
|
||||
|
||||
$s->set('tagged_iterator_foo', 'Bar')
|
||||
->private()
|
||||
->tag('foo');
|
||||
|
||||
$s->set('tagged_iterator', 'Bar')
|
||||
->public()
|
||||
->args(array(tagged('foo')));
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ require_once __DIR__.'/../includes/classes.php';
|
||||
require_once __DIR__.'/../includes/foo.php';
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -161,5 +162,15 @@ $container
|
||||
->setArguments(array(new IteratorArgument(array(new Reference('foo.baz'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))), new IteratorArgument(array())))
|
||||
->setPublic(true)
|
||||
;
|
||||
$container
|
||||
->register('tagged_iterator_foo', 'Bar')
|
||||
->addTag('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('tagged_iterator', 'Bar')
|
||||
->addArgument(new TaggedIteratorArgument('foo'))
|
||||
->setPublic(true)
|
||||
;
|
||||
|
||||
return $container;
|
||||
|
@ -29,6 +29,8 @@ digraph sc {
|
||||
node_factory_service_simple [label="factory_service_simple\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_lazy_context [label="lazy_context\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_lazy_context_ignore_invalid_ref [label="lazy_context_ignore_invalid_ref\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_tagged_iterator_foo [label="tagged_iterator_foo\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_tagged_iterator [label="tagged_iterator\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
|
@ -56,6 +56,8 @@ class ProjectServiceContainer extends Container
|
||||
'new_factory' => 'getNewFactoryService',
|
||||
'new_factory_service' => 'getNewFactoryServiceService',
|
||||
'service_from_static_method' => 'getServiceFromStaticMethodService',
|
||||
'tagged_iterator' => 'getTaggedIteratorService',
|
||||
'tagged_iterator_foo' => 'getTaggedIteratorFooService',
|
||||
);
|
||||
$this->privates = array(
|
||||
'configurator_service' => true,
|
||||
@ -63,6 +65,7 @@ class ProjectServiceContainer extends Container
|
||||
'factory_simple' => true,
|
||||
'inlined' => true,
|
||||
'new_factory' => true,
|
||||
'tagged_iterator_foo' => true,
|
||||
);
|
||||
$this->aliases = array(
|
||||
'Psr\\Container\\ContainerInterface' => 'service_container',
|
||||
@ -337,6 +340,18 @@ class ProjectServiceContainer extends Container
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the public 'tagged_iterator' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorService()
|
||||
{
|
||||
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
|
||||
return new \EmptyIterator();
|
||||
}, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'configurator_service' shared service.
|
||||
*
|
||||
@ -404,6 +419,16 @@ class ProjectServiceContainer extends Container
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'tagged_iterator_foo' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorFooService()
|
||||
{
|
||||
return $this->services['tagged_iterator_foo'] = new \Bar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default parameters.
|
||||
*
|
||||
|
@ -235,6 +235,27 @@ use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
|
||||
[Container%s/getTaggedIteratorService.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
|
||||
// Returns the public 'tagged_iterator' shared service.
|
||||
|
||||
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
|
||||
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load(__DIR__.'/getFooService.php')) && false ?: '_'};
|
||||
yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
|
||||
}, 2));
|
||||
|
||||
[Container%s/getTaggedIteratorFooService.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
|
||||
// Returns the private 'tagged_iterator_foo' shared service.
|
||||
|
||||
return $this->services['tagged_iterator_foo'] = new \Bar();
|
||||
|
||||
[Container%s/Container.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
@ -292,9 +313,12 @@ class Container%s extends Container
|
||||
'method_call1' => __DIR__.'/getMethodCall1Service.php',
|
||||
'new_factory_service' => __DIR__.'/getNewFactoryServiceService.php',
|
||||
'service_from_static_method' => __DIR__.'/getServiceFromStaticMethodService.php',
|
||||
'tagged_iterator' => __DIR__.'/getTaggedIteratorService.php',
|
||||
'tagged_iterator_foo' => __DIR__.'/getTaggedIteratorFooService.php',
|
||||
);
|
||||
$this->privates = array(
|
||||
'factory_simple' => true,
|
||||
'tagged_iterator_foo' => true,
|
||||
);
|
||||
$this->aliases = array(
|
||||
'alias_for_alias' => 'foo',
|
||||
|
@ -49,9 +49,12 @@ class ProjectServiceContainer extends Container
|
||||
'method_call1' => 'getMethodCall1Service',
|
||||
'new_factory_service' => 'getNewFactoryServiceService',
|
||||
'service_from_static_method' => 'getServiceFromStaticMethodService',
|
||||
'tagged_iterator' => 'getTaggedIteratorService',
|
||||
'tagged_iterator_foo' => 'getTaggedIteratorFooService',
|
||||
);
|
||||
$this->privates = array(
|
||||
'factory_simple' => true,
|
||||
'tagged_iterator_foo' => true,
|
||||
);
|
||||
$this->aliases = array(
|
||||
'alias_for_alias' => 'foo',
|
||||
@ -339,6 +342,19 @@ class ProjectServiceContainer extends Container
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the public 'tagged_iterator' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorService()
|
||||
{
|
||||
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
|
||||
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'};
|
||||
yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
|
||||
}, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'factory_simple' shared service.
|
||||
*
|
||||
@ -353,6 +369,16 @@ class ProjectServiceContainer extends Container
|
||||
return $this->services['factory_simple'] = new \SimpleFactoryClass('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'tagged_iterator_foo' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorFooService()
|
||||
{
|
||||
return $this->services['tagged_iterator_foo'] = new \Bar();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -133,6 +133,12 @@
|
||||
</argument>
|
||||
<argument type="iterator"/>
|
||||
</service>
|
||||
<service id="tagged_iterator_foo" class="Bar" public="false">
|
||||
<tag name="foo"/>
|
||||
</service>
|
||||
<service id="tagged_iterator" class="Bar" public="true">
|
||||
<argument type="tagged" tag="foo"/>
|
||||
</service>
|
||||
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
|
||||
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
|
||||
<service id="alias_for_foo" alias="foo" public="true"/>
|
||||
|
@ -145,6 +145,16 @@ services:
|
||||
alias_for_alias:
|
||||
alias: 'foo'
|
||||
public: true
|
||||
tagged_iterator_foo:
|
||||
class: Bar
|
||||
tags:
|
||||
- { name: foo }
|
||||
public: false
|
||||
tagged_iterator:
|
||||
class: Bar
|
||||
arguments:
|
||||
- !tagged foo
|
||||
public: true
|
||||
Psr\Container\ContainerInterface:
|
||||
alias: service_container
|
||||
public: false
|
||||
|
@ -774,8 +774,8 @@ class Inline
|
||||
$nextOffset += strspn($value, ' ', $nextOffset);
|
||||
|
||||
// Is followed by a scalar
|
||||
if (!isset($value[$nextOffset]) || !in_array($value[$nextOffset], array('[', '{'), true)) {
|
||||
// Manage scalars in {@link self::evaluateScalar()}
|
||||
if ((!isset($value[$nextOffset]) || !in_array($value[$nextOffset], array('[', '{'), true)) && 'tagged' !== $tag) {
|
||||
// Manage non-whitelisted scalars in {@link self::evaluateScalar()}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -698,6 +698,8 @@ class Parser
|
||||
if ('' !== $matches['tag']) {
|
||||
if ('!!binary' === $matches['tag']) {
|
||||
return Inline::evaluateBinaryScalar($data);
|
||||
} elseif ('tagged' === $matches['tag']) {
|
||||
return new TaggedValue(substr($matches['tag'], 1), $data);
|
||||
} elseif ('!' !== $matches['tag']) {
|
||||
@trigger_error($this->getDeprecationMessage(sprintf('Using the custom tag "%s" for the value "%s" is deprecated since version 3.3. It will be replaced by an instance of %s in 4.0.', $matches['tag'], $data, TaggedValue::class)), E_USER_DEPRECATED);
|
||||
}
|
||||
|
Reference in New Issue
Block a user