Skip to content

Commit

Permalink
Allow to choose an index for tagged collection
Browse files Browse the repository at this point in the history
  • Loading branch information
deguif committed Dec 13, 2018
1 parent f2590d1 commit a2041eb
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,30 @@
class TaggedIteratorArgument extends IteratorArgument
{
private $tag;
private $indexAttribute;
private $defaultIndexMethod;

public function __construct(string $tag)
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null)
{
parent::__construct(array());

$this->tag = $tag;
$this->indexAttribute = $indexAttribute;
$this->defaultIndexMethod = $defaultIndexMethod;
}

public function getTag()
{
return $this->tag;
}

public function getIndexAttribute(): ?string
{
return $this->indexAttribute;
}

public function getDefaultIndexMethod(): ?string
{
return $this->defaultIndexMethod;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;

/**
Expand All @@ -36,13 +38,56 @@ trait PriorityTaggedServiceTrait
*
* @return Reference[]
*/
private function findAndSortTaggedServices($tagName, ContainerBuilder $container)
private function findAndSortTaggedServices($tagName, ContainerBuilder $container, string $indexAttribute = null, string $defaultIndexMethod = null)
{
$services = array();

if (null === $indexAttribute && null !== $defaultIndexMethod) {
throw new InvalidArgumentException('Default index method cannot be used without specifying a tag attribute.');
}

foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$services[$priority][] = new Reference($serviceId);

if (null === $indexAttribute && null === $defaultIndexMethod) {
$services[$priority][] = new Reference($serviceId);

continue;
}

if (isset($attributes[0][$indexAttribute])) {
$services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId);

continue;
}

if (null === $defaultIndexMethod) {
throw new LogicException(sprintf('Tag attribute with name "%s" for service "%s" cannot be found.', $indexAttribute, $serviceId));
}

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('Class "%s" used for service "%s" has no method "%s".', $class, $serviceId, $defaultIndexMethod));
}

if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
throw new InvalidArgumentException(sprintf('Method "%s" of class "%s" used for service "%s" must be static.', $defaultIndexMethod, $class, $serviceId));
}

if (!$rm->isPublic()) {
throw new InvalidArgumentException(sprintf('Method "%s" of class "%s" used for service "%s" must be public.', $defaultIndexMethod, $class, $serviceId));
}

$key = $rm->invoke(null);

if (!\is_string($key)) {
throw new LogicException(sprintf('Return value of method "%s" for class "%s" used for service "%s" must be of type string.', $class, $serviceId, $defaultIndexMethod));
}

$services[$priority][$key] = new Reference($serviceId);
}

if ($services) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected function processValue($value, $isRoot = false)
return parent::processValue($value, $isRoot);
}

$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container, $value->getIndexAttribute(), $value->getDefaultIndexMethod()));

return $value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument
/**
* 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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,11 +706,13 @@ private function resolveServices($value, $file, $isParameter = false)
}
}
if ('tagged' === $value->getTag()) {
if (!\is_string($argument) || !$argument) {
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
if (\is_string($argument) && $argument) {
return new TaggedIteratorArgument($argument);
} elseif (\is_array($argument) && isset($argument['name']) && $argument['name']) {
return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
} else {
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file));
}

return new TaggedIteratorArgument($argument);
}
if ('service' === $value->getTag()) {
if ($isParameter) {
Expand Down

0 comments on commit a2041eb

Please sign in to comment.