Skip to content

Commit 6daa624

Browse files
Merge branch '7.3' into 7.4
* 7.3: [DependencyInjection] Call default index method when index is not provided by tag [Cache] Recognize commit events as writes in `CacheDataCollector`
2 parents b59a54f + 5bb81bd commit 6daa624

File tree

2 files changed

+206
-18
lines changed

2 files changed

+206
-18
lines changed

Compiler/PriorityTaggedServiceTrait.php

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,12 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
5959
continue;
6060
}
6161

62-
$defaultPriority = null;
63-
$defaultIndex = null;
62+
$defaultPriority = $defaultAttributePriority = null;
63+
$defaultIndex = $defaultAttributeIndex = null;
6464
$definition = $container->getDefinition($serviceId);
6565
$class = $definition->getClass();
6666
$class = $container->getParameterBag()->resolveValue($class) ?: null;
6767
$reflector = null !== $class ? $container->getReflectionClass($class) : null;
68-
$loadFromDefaultMethods = $reflector && null !== $defaultPriorityMethod;
6968
$phpAttributes = $definition->isAutoconfigured() && !$definition->hasTag('container.ignore_attributes') ? $reflector?->getAttributes(AsTaggedItem::class) : [];
7069

7170
foreach ($phpAttributes ??= [] as $i => $attribute) {
@@ -74,9 +73,9 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
7473
'priority' => $attribute->priority,
7574
$indexAttribute ?? '' => $attribute->index,
7675
];
77-
if (null === $defaultPriority) {
78-
$defaultPriority = $attribute->priority ?? 0;
79-
$defaultIndex = $attribute->index;
76+
if (null === $defaultAttributePriority) {
77+
$defaultAttributePriority = $attribute->priority ?? 0;
78+
$defaultAttributeIndex = $attribute->index;
8079
}
8180
}
8281
if (1 >= \count($phpAttributes)) {
@@ -93,10 +92,8 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
9392

9493
if (isset($attribute['priority'])) {
9594
$priority = $attribute['priority'];
96-
} elseif ($loadFromDefaultMethods) {
97-
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultPriority;
98-
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute) ?? $defaultIndex;
99-
$loadFromDefaultMethods = false;
95+
} elseif (null === $defaultPriority && $defaultPriorityMethod && $reflector) {
96+
$defaultPriority = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultPriorityMethod, $tagName, 'priority') ?? $defaultAttributePriority;
10097
}
10198
$priority ??= $defaultPriority ??= 0;
10299

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

@@ -147,13 +142,10 @@ class PriorityTaggedServiceUtil
147142
{
148143
public static function getDefault(string $serviceId, \ReflectionClass $r, string $defaultMethod, string $tagName, ?string $indexAttribute): string|int|null
149144
{
150-
if (!$r->hasMethod($defaultMethod)) {
145+
if ($r->isInterface() || !$r->hasMethod($defaultMethod)) {
151146
return null;
152147
}
153148

154-
if ($r->isInterface()) {
155-
return null;
156-
}
157149
$class = $r->name;
158150

159151
if (null !== $indexAttribute) {

Tests/Compiler/PriorityTaggedServiceTraitTest.php

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,145 @@ public function testAttributesAreFallbacks()
309309

310310
$this->assertEquals(['z' => new TypedReference('service_attr_first', MultiTagHelloNamedService::class)], $services);
311311
}
312+
313+
public function testTaggedIteratorWithDefaultNameMethod()
314+
{
315+
$container = new ContainerBuilder();
316+
$container->register('service', ClassWithDefaultNameMethod::class)->addTag('my_custom_tag');
317+
318+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
319+
320+
$tag = new TaggedIteratorArgument('my_custom_tag');
321+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
322+
$this->assertEquals([new Reference('service')], $services);
323+
}
324+
325+
public function testIndexedIteratorUsesTagAttributeOverDefaultMethod()
326+
{
327+
$container = new ContainerBuilder();
328+
$container->register('service.a', ServiceWithStaticGetType::class)
329+
->addTag('my_tag', ['type' => 'from_tag']);
330+
331+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
332+
333+
$tag = new TaggedIteratorArgument('my_tag', 'type', 'getType');
334+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
335+
336+
$this->assertArrayHasKey('from_tag', $services);
337+
$this->assertArrayNotHasKey('from_static_method', $services);
338+
$this->assertInstanceOf(TypedReference::class, $services['from_tag']);
339+
$this->assertSame('service.a', (string) $services['from_tag']);
340+
}
341+
342+
public function testIndexedIteratorUsesDefaultMethodAsFallback()
343+
{
344+
$container = new ContainerBuilder();
345+
$container->register('service.a', ServiceWithStaticGetType::class)
346+
->addTag('my_tag');
347+
348+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
349+
350+
$tag = new TaggedIteratorArgument('my_tag', 'type', 'getType');
351+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
352+
353+
$this->assertArrayHasKey('from_static_method', $services);
354+
$this->assertArrayNotHasKey('from_tag', $services);
355+
$this->assertInstanceOf(TypedReference::class, $services['from_static_method']);
356+
}
357+
358+
public function testIndexedIteratorUsesTagIndexAndDefaultPriorityMethod()
359+
{
360+
$container = new ContainerBuilder();
361+
362+
$container->register('service.a', ServiceWithStaticPriority::class)
363+
->addTag('my_tag', ['type' => 'tag_index']);
364+
365+
$container->register('service.b', \stdClass::class)
366+
->addTag('my_tag', ['type' => 'another_index']);
367+
368+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
369+
370+
$tag = new TaggedIteratorArgument('my_tag', 'type', null, 'getPriority');
371+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
372+
373+
$this->assertArrayHasKey('tag_index', $services);
374+
$this->assertSame('service.a', (string) $services['tag_index']);
375+
376+
$this->assertSame(['tag_index', 'another_index'], array_keys($services));
377+
}
378+
379+
public function testTaggedLocatorWithProvidedIndexAttributeAndNonStaticDefaultIndexMethod()
380+
{
381+
$container = new ContainerBuilder();
382+
$container->register('service', NonStaticDefaultIndexClass::class)
383+
->addTag('my_custom_tag', ['type' => 'foo']);
384+
385+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
386+
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');
387+
388+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
389+
$this->assertEquals(['foo' => new TypedReference('service', NonStaticDefaultIndexClass::class)], $services);
390+
}
391+
392+
public function testTaggedLocatorWithoutIndexAttributeAndNonStaticDefaultIndexMethod()
393+
{
394+
$this->expectException(InvalidArgumentException::class);
395+
$this->expectExceptionMessage(\sprintf('Either method "%s::getType()" should be static or tag "my_custom_tag" on service "service" is missing attribute "type".', NonStaticDefaultIndexClass::class));
396+
397+
$container = new ContainerBuilder();
398+
$container->register('service', NonStaticDefaultIndexClass::class)
399+
->addTag('my_custom_tag');
400+
401+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
402+
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');
403+
404+
$priorityTaggedServiceTraitImplementation->test($tag, $container);
405+
}
406+
407+
public function testMergingAsTaggedItemWithEmptyTagAndNonStaticBusinessMethod()
408+
{
409+
$container = new ContainerBuilder();
410+
$container->register('service', AsTaggedItemClassWithBusinessMethod::class)
411+
->setAutoconfigured(true)
412+
->addTag('my_custom_tag');
413+
414+
(new ResolveInstanceofConditionalsPass())->process($container);
415+
416+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
417+
$tag = new TaggedIteratorArgument('my_custom_tag', 'index');
418+
419+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
420+
$this->assertEquals(['bar' => new TypedReference('service', AsTaggedItemClassWithBusinessMethod::class)], $services);
421+
}
422+
423+
public function testPriorityFallbackWithoutIndexAndStaticPriorityMethod()
424+
{
425+
$container = new ContainerBuilder();
426+
$container->register('service', StaticPriorityClass::class)
427+
->addTag('my_custom_tag');
428+
429+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
430+
$tag = new TaggedIteratorArgument('my_custom_tag', null, null, false, 'getDefaultPriority');
431+
432+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
433+
$this->assertEquals([new Reference('service')], $services);
434+
}
435+
436+
public function testMultiTagsWithMixedAttributesAndNonStaticDefault()
437+
{
438+
$container = new ContainerBuilder();
439+
$container->register('service', MultiTagNonStaticClass::class)
440+
->addTag('my_custom_tag', ['type' => 'foo'])
441+
->addTag('my_custom_tag');
442+
443+
$priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation();
444+
$tag = new TaggedIteratorArgument('my_custom_tag', 'type', 'getType');
445+
446+
$services = $priorityTaggedServiceTraitImplementation->test($tag, $container);
447+
$this->assertCount(2, $services);
448+
$this->assertArrayHasKey('foo', $services);
449+
$this->assertArrayHasKey('default', $services);
450+
}
312451
}
313452

314453
class PriorityTaggedServiceTraitImplementation
@@ -342,3 +481,60 @@ interface HelloInterface
342481
{
343482
public static function getFooBar(): string;
344483
}
484+
485+
class ClassWithDefaultNameMethod
486+
{
487+
public function getDefaultName(): string
488+
{
489+
return 'foo';
490+
}
491+
}
492+
493+
class ServiceWithStaticGetType
494+
{
495+
public static function getType(): string
496+
{
497+
return 'from_static_method';
498+
}
499+
}
500+
501+
class ServiceWithStaticPriority
502+
{
503+
public static function getPriority(): int
504+
{
505+
return 10;
506+
}
507+
}
508+
509+
class NonStaticDefaultIndexClass
510+
{
511+
public function getType(): string
512+
{
513+
return 'foo';
514+
}
515+
}
516+
517+
#[AsTaggedItem(index: 'bar')]
518+
class AsTaggedItemClassWithBusinessMethod
519+
{
520+
public function getDefaultName(): string
521+
{
522+
return 'ignored';
523+
}
524+
}
525+
526+
class StaticPriorityClass
527+
{
528+
public static function getDefaultPriority(): int
529+
{
530+
return 10;
531+
}
532+
}
533+
534+
class MultiTagNonStaticClass
535+
{
536+
public static function getType(): string
537+
{
538+
return 'default';
539+
}
540+
}

0 commit comments

Comments
 (0)