Allow to choose an index for tagged collection
This commit is contained in:
parent
fec0475e8c
commit
845d3a681b
@ -19,16 +19,33 @@ namespace Symfony\Component\DependencyInjection\Argument;
|
|||||||
class TaggedIteratorArgument extends IteratorArgument
|
class TaggedIteratorArgument extends IteratorArgument
|
||||||
{
|
{
|
||||||
private $tag;
|
private $tag;
|
||||||
|
private $indexAttribute;
|
||||||
|
private $defaultIndexMethod;
|
||||||
|
|
||||||
public function __construct(string $tag)
|
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null)
|
||||||
{
|
{
|
||||||
parent::__construct([]);
|
parent::__construct([]);
|
||||||
|
|
||||||
$this->tag = $tag;
|
$this->tag = $tag;
|
||||||
|
$this->indexAttribute = $indexAttribute ?: null;
|
||||||
|
|
||||||
|
if ($indexAttribute) {
|
||||||
|
$this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTag()
|
public function getTag()
|
||||||
{
|
{
|
||||||
return $this->tag;
|
return $this->tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getIndexAttribute(): ?string
|
||||||
|
{
|
||||||
|
return $this->indexAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultIndexMethod(): ?string
|
||||||
|
{
|
||||||
|
return $this->defaultIndexMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,18 +33,59 @@ trait PriorityTaggedServiceTrait
|
|||||||
* @see https://bugs.php.net/bug.php?id=53710
|
* @see https://bugs.php.net/bug.php?id=53710
|
||||||
* @see https://bugs.php.net/bug.php?id=60926
|
* @see https://bugs.php.net/bug.php?id=60926
|
||||||
*
|
*
|
||||||
* @param string $tagName
|
* @param string|TaggedIteratorArgument $tagName
|
||||||
* @param ContainerBuilder $container
|
* @param ContainerBuilder $container
|
||||||
*
|
*
|
||||||
* @return Reference[]
|
* @return Reference[]
|
||||||
*/
|
*/
|
||||||
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
|
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
|
$indexAttribute = $defaultIndexMethod = null;
|
||||||
|
if ($tagName instanceof TaggedIteratorArgument) {
|
||||||
|
$indexAttribute = $tagName->getIndexAttribute();
|
||||||
|
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
|
||||||
|
$tagName = $tagName->getTag();
|
||||||
|
}
|
||||||
$services = [];
|
$services = [];
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
|
||||||
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
|
||||||
$services[$priority][] = new Reference($serviceId);
|
|
||||||
|
if (null === $indexAttribute) {
|
||||||
|
$services[$priority][] = new Reference($serviceId);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($attributes[0][$indexAttribute])) {
|
||||||
|
$services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$r->hasMethod($defaultIndexMethod)) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$rm->isPublic()) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $rm->invoke(null);
|
||||||
|
|
||||||
|
if (!\is_string($key)) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
$services[$priority][$key] = new Reference($serviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($services) {
|
if ($services) {
|
||||||
|
@ -31,7 +31,7 @@ class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass
|
|||||||
return parent::processValue($value, $isRoot);
|
return parent::processValue($value, $isRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
|
$value->setValues($this->findAndSortTaggedServices($value, $this->container));
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument
|
|||||||
/**
|
/**
|
||||||
* Creates a lazy iterator by tag name.
|
* Creates a lazy iterator by tag name.
|
||||||
*/
|
*/
|
||||||
function tagged(string $tag): TaggedIteratorArgument
|
function tagged(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): TaggedIteratorArgument
|
||||||
{
|
{
|
||||||
return new TaggedIteratorArgument($tag);
|
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -710,11 +710,17 @@ class YamlFileLoader extends FileLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ('tagged' === $value->getTag()) {
|
if ('tagged' === $value->getTag()) {
|
||||||
if (!\is_string($argument) || !$argument) {
|
if (\is_string($argument) && $argument) {
|
||||||
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
|
return new TaggedIteratorArgument($argument);
|
||||||
}
|
}
|
||||||
|
if (\is_array($argument) && isset($argument['name']) && $argument['name']) {
|
||||||
|
if (array_diff(array_keys($argument), ['name', 'index_by', 'default_index_method'])) {
|
||||||
|
throw new InvalidArgumentException('"!tagged" tag contains unsupported keys. Supported are: "name, index_by, default_index_method".');
|
||||||
|
}
|
||||||
|
|
||||||
return new TaggedIteratorArgument($argument);
|
return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
|
||||||
|
}
|
||||||
|
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file));
|
||||||
}
|
}
|
||||||
if ('service' === $value->getTag()) {
|
if ('service' === $value->getTag()) {
|
||||||
if ($isParameter) {
|
if ($isParameter) {
|
||||||
|
Reference in New Issue
Block a user