Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 794b5e1

Browse filesBrowse files
committed
feature #42039 [DependencyInjection] Autoconfigurable attributes on methods, properties and parameters (ruudk)
This PR was merged into the 5.4 branch. Discussion ---------- [DependencyInjection] Autoconfigurable attributes on methods, properties and parameters | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? |no | New feature? | yes | Deprecations? |no | Tickets | | License | MIT | Doc PR | ## Introduction symfony/symfony#39897 introduced the possibility auto configure classes that were annotated with attributes: ```php $container->registerAttributeForAutoconfiguration( MyAttribute::class, static function (ChildDefinition $definition, MyAttribute $attribute, \ReflectionClass $reflector): void { $definition->addTag('my_tag', ['some_property' => $attribute->someProperty]); } ); ``` This works great. But it only works when the attribute is added on the class. With this PR, it's now possible to also auto configure methods, properties and parameters. ## How does it work? Let's say you have an attribute that targets classes and methods like this: ```php #[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY)] final class MyAttribute { } ``` You have two services that use them: ```php #[MyAttribute] class MyService { } class MyOtherService { #[MyAttribute] public function myMethod() {} } ``` You can now use `registerAttributeForAutoconfiguration` in your extension, together with a union of the types that you want to seach for. In this example, the extension only cares for classes and methods, so it uses `\ReflectionClass|\ReflectionMethod $reflector`: ```php final class MyBundleExtension extends Extension { public function load(array $configs, ContainerBuilder $container) : void { $container->registerAttributeForAutoconfiguration( MyAttribute::class, static function (ChildDefinition $definition, MyAttribute $attribute, \ReflectionClass|\ReflectionMethod $reflector) : void { $args = []; if ($reflector instanceof \ReflectionMethod) { $args['method'] = $reflector->getName(); } $definition->addTag('my.tag', $args); } ); } } ``` This will tag `MyService` with `my.tag` and it will tag `MyOtherService` with `my.tag, method: myMethod` If the extension also wants to target the properties that are annotated with attributes, it can either change the union to `\ReflectionClass|\ReflectionMethod|\ReflectionProperty $reflector` or it can just use `\Reflector $reflector` and do the switching in the callable. ## Another example Let's say you have an attribute like this: ```php #[Attribute(Attribute::TARGET_CLASS)] final class MyAttribute { } ``` and you use it like this: ```php $container->registerAttributeForAutoconfiguration( MyAttribute::class, static function (ChildDefinition $definition, MyAttribute $attribute, \ReflectionClass|\ReflectionMethod $reflector) : void { $definition->addTag('my.tag'); } ); ``` you'll get an error saying that `ReflectionMethod` is not possible as the attribute only targets classes. Commits ------- 917fcc09f7 [DependencyInjection] Autoconfigurable attributes on methods, properties and parameters
2 parents aa2bbd4 + 33748af commit 794b5e1
Copy full SHA for 794b5e1

File tree

Expand file treeCollapse file tree

1 file changed

+9
-2
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+9
-2
lines changed

‎DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: DependencyInjection/FrameworkExtension.php
+9-2Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,15 @@ public function load(array $configs, ContainerBuilder $container)
557557
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
558558
->addMethodCall('setLogger', [new Reference('logger')]);
559559

560-
$container->registerAttributeForAutoconfiguration(AsEventListener::class, static function (ChildDefinition $definition, AsEventListener $attribute): void {
561-
$definition->addTag('kernel.event_listener', get_object_vars($attribute));
560+
$container->registerAttributeForAutoconfiguration(AsEventListener::class, static function (ChildDefinition $definition, AsEventListener $attribute, \Reflector $reflector) {
561+
$tagAttributes = get_object_vars($attribute);
562+
if ($reflector instanceof \ReflectionMethod) {
563+
if (isset($tagAttributes['method'])) {
564+
throw new LogicException(sprintf('AsEventListener attribute cannot declare a method on "%s::%s()".', $reflector->class, $reflector->name));
565+
}
566+
$tagAttributes['method'] = $reflector->getName();
567+
}
568+
$definition->addTag('kernel.event_listener', $tagAttributes);
562569
});
563570
$container->registerAttributeForAutoconfiguration(AsController::class, static function (ChildDefinition $definition, AsController $attribute): void {
564571
$definition->addTag('controller.service_arguments');

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.