🌐 AI搜索 & 代理 主页
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
continue;
}

$defaultPriority = null;
$defaultIndex = null;
$defaultPriority = $defaultAttributePriority = null;
$defaultIndex = $defaultAttributeIndex = null;
$definition = $container->getDefinition($serviceId);
$class = $definition->getClass();
$class = $container->getParameterBag()->resolveValue($class) ?: null;
$reflector = null !== $class ? $container->getReflectionClass($class) : null;
$loadFromDefaultMethods = $reflector && null !== $defaultPriorityMethod;
$phpAttributes = $definition->isAutoconfigured() && !$definition->hasTag('container.ignore_attributes') ? $reflector?->getAttributes(AsTaggedItem::class) : [];

foreach ($phpAttributes ??= [] as $i => $attribute) {
Expand All @@ -74,9 +73,9 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
'priority' => $attribute->priority,
$indexAttribute ?? '' => $attribute->index,
];
if (null === $defaultPriority) {
$defaultPriority = $attribute->priority ?? 0;
$defaultIndex = $attribute->index;
if (null === $defaultAttributePriority) {
$defaultAttributePriority = $attribute->priority ?? 0;
$defaultAttributeIndex = $attribute->index;
}
}
if (1 >= \count($phpAttributes)) {
Expand All @@ -93,10 +92,8 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam

if (isset($attribute['priority'])) {
$priority = $attribute['priority'];
} elseif ($loadFromDefaultMethods) {
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultPriority;
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute) ?? $defaultIndex;
$loadFromDefaultMethods = false;
} elseif (null === $defaultPriority && $defaultPriorityMethod && $reflector) {
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultAttributePriority;
}
$priority ??= $defaultPriority ??= 0;

Expand All @@ -108,10 +105,8 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
if (null !== $indexAttribute && isset($attribute[$indexAttribute])) {
$index = $parameterBag->resolveValue($attribute[$indexAttribute]);
}
if (null === $index && $loadFromDefaultMethods) {
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultPriority;
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute) ?? $defaultIndex;
$loadFromDefaultMethods = false;
if (null === $index && null === $defaultIndex && $defaultPriorityMethod && $reflector) {
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute) ?? $defaultAttributeIndex;
}
$index ??= $defaultIndex ??= $definition->getTag('container.decorator')[0]['id'] ?? $serviceId;

Expand Down Expand Up @@ -147,13 +142,10 @@ class PriorityTaggedServiceUtil
{
public static function getDefault(string $serviceId, \ReflectionClass $r, string $defaultMethod, string $tagName, ?string $indexAttribute): string|int|null
{
if (!$r->hasMethod($defaultMethod)) {
if ($r->isInterface() || !$r->hasMethod($defaultMethod)) {
return null;
}

if ($r->isInterface()) {
return null;
}
$class = $r->name;

if (null !== $indexAttribute) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,145 @@ public function testAttributesAreFallbacks()

$this->assertEquals(['z' => new TypedReference('service_attr_first', MultiTagHelloNamedService::class)], $services);
}

public function testTaggedIteratorWithDefaultNameMethod()
{
$container = new ContainerBuilder();
$container->register('service', ClassWithDefaultNameMethod::class)->addTag('my_custom_tag');

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();

$tag = new TaggedIteratorArgument('my_custom_tag');
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
$this->assertEquals([new Reference('service')], $services);
}

public function testIndexedIteratorUsesTagAttributeOverDefaultMethod()
{
$container = new ContainerBuilder();
$container->register('service.a', ServiceWithStaticGetType::class)
->addTag('my_tag', ['type' => 'from_tag']);

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();

$tag = new TaggedIteratorArgument('my_tag', 'type', 'getType');
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);

$this->assertArrayHasKey('from_tag', $services);
$this->assertArrayNotHasKey('from_static_method', $services);
$this->assertInstanceOf(TypedReference::class, $services['from_tag']);
$this->assertSame('service.a', (string) $services['from_tag']);
}

public function testIndexedIteratorUsesDefaultMethodAsFallback()
{
$container = new ContainerBuilder();
$container->register('service.a', ServiceWithStaticGetType::class)
->addTag('my_tag');

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();

$tag = new TaggedIteratorArgument('my_tag', 'type', 'getType');
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);

$this->assertArrayHasKey('from_static_method', $services);
$this->assertArrayNotHasKey('from_tag', $services);
$this->assertInstanceOf(TypedReference::class, $services['from_static_method']);
}

public function testIndexedIteratorUsesTagIndexAndDefaultPriorityMethod()
{
$container = new ContainerBuilder();

$container->register('service.a', ServiceWithStaticPriority::class)
->addTag('my_tag', ['type' => 'tag_index']);

$container->register('service.b', \stdClass::class)
->addTag('my_tag', ['type' => 'another_index']);

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();

$tag = new TaggedIteratorArgument('my_tag', 'type', null, 'getPriority');
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);

$this->assertArrayHasKey('tag_index', $services);
$this->assertSame('service.a', (string) $services['tag_index']);

$this->assertSame(['tag_index', 'another_index'], array_keys($services));
}

public function testTaggedLocatorWithProvidedIndexAttributeAndNonStaticDefaultIndexMethod()
{
$container = new ContainerBuilder();
$container->register('service', NonStaticDefaultIndexClass::class)
->addTag('my_custom_tag', ['type' => 'foo']);

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');

$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
$this->assertEquals(['foo' => new TypedReference('service', NonStaticDefaultIndexClass::class)], $services);
}

public function testTaggedLocatorWithoutIndexAttributeAndNonStaticDefaultIndexMethod()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(\sprintf('Either method "%s::getType()" should be static or tag "my_custom_tag" on service "service" is missing attribute "type".', NonStaticDefaultIndexClass::class));

$container = new ContainerBuilder();
$container->register('service', NonStaticDefaultIndexClass::class)
->addTag('my_custom_tag');

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');

$priorityTaggedServiceTraitImplementation->test($tag, $container);
}

public function testMergingAsTaggedItemWithEmptyTagAndNonStaticBusinessMethod()
{
$container = new ContainerBuilder();
$container->register('service', AsTaggedItemClassWithBusinessMethod::class)
->setAutoconfigured(true)
->addTag('my_custom_tag');

(new ResolveInstanceofConditionalsPass())->process($container);

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
$tag = new TaggedIteratorArgument('my_custom_tag', 'index');

$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
$this->assertEquals(['bar' => new TypedReference('service', AsTaggedItemClassWithBusinessMethod::class)], $services);
}

public function testPriorityFallbackWithoutIndexAndStaticPriorityMethod()
{
$container = new ContainerBuilder();
$container->register('service', StaticPriorityClass::class)
->addTag('my_custom_tag');

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
$tag = new TaggedIteratorArgument('my_custom_tag', null, null, false, 'getDefaultPriority');

$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
$this->assertEquals([new Reference('service')], $services);
}

public function testMultiTagsWithMixedAttributesAndNonStaticDefault()
{
$container = new ContainerBuilder();
$container->register('service', MultiTagNonStaticClass::class)
->addTag('my_custom_tag', ['type' => 'foo'])
->addTag('my_custom_tag');

$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');

$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
$this->assertCount(2, $services);
$this->assertArrayHasKey('foo', $services);
$this->assertArrayHasKey('default', $services);
}
}

class PriorityTaggedServiceTraitImplementation
Expand Down Expand Up @@ -343,3 +482,60 @@ interface HelloInterface
{
public static function getFooBar(): string;
}

class ClassWithDefaultNameMethod
{
public function getDefaultName(): string
{
return 'foo';
}
}

class ServiceWithStaticGetType
{
public static function getType(): string
{
return 'from_static_method';
}
}

class ServiceWithStaticPriority
{
public static function getPriority(): int
{
return 10;
}
}

class NonStaticDefaultIndexClass
{
public function getType(): string
{
return 'foo';
}
}

#[AsTaggedItem(index: 'bar')]
class AsTaggedItemClassWithBusinessMethod
{
public function getDefaultName(): string
{
return 'ignored';
}
}

class StaticPriorityClass
{
public static function getDefaultPriority(): int
{
return 10;
}
}

class MultiTagNonStaticClass
{
public static function getType(): string
{
return 'default';
}
}
Loading