-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DependencyInjection] Autowire tagged iterators using doc blocks #46253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In all static analyzers, |
@stof indeed it's much better. Patch and PR description updated to use |
I don't see the value of having this configuration: # config/services.yaml
services:
_instanceof:
App\RoomInterface:
tags: ['app.room'] Since there is no tag information in the doc block, tagging the interface feels weird, at least to me. |
@alanpoulain this is an existing feature: https://symfony.com/doc/current/service_container/tags.html#define-services-with-a-custom-tag This patch just adds some syntactic sugar on top of this feature, to remove some verbose and useless configuration or attributes in the common case. I discussed with @nicolas-grekas off-GitHub on a way to remove the config block you pointed out, but this will be for a follow-up PR (and may have edge cases). |
I don't think this is a good idea as it removes the relation between the tag name and the iterator as already pointed out by @alanpoulain . If you search for the tag name, you won't find anything. That's really bad developer experience. |
@Tobion @alanpoulain what we need is just a new convention: use the interface name if you want to inject all services implementing it, as we use the class name if there is only one instance of it registered as a service: # config/services.yaml
services:
_instanceof:
App\RoomInterface:
- tags: ['app.room']
+ tags: ['App\RoomInterface'] This would fix this DX issue isn't it? I'm working on a follow-up PR to simplify/remove the need for this configuration snippet. |
Actually, it's already supported: namespace App;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
#[AutoconfigureTag]
interface RoomInterface
{
public function getBeds(): int;
}
class Hospital
{
/** @param iterable<RoomInterface> $rooms */
public function __construct(private iterable $rooms) {}
} That's all you need. |
It's quite common that the service taking the tagged iterator as dependency implements the same interface as the services included in the iterator, so that each method iterates over these services until it finds the right one and delegates the call to it. e.g: class ChainRoomProvider implements RoomProviderInterface
{
/** @param iterable<RoomProviderInterface> $roomProviders */
public function __construct(private iterable $roomProviders) {}
public function findRoom(): Room {
foreach ($this->roomProviders as $roomProvider) {
if ($roomProvider->supports($someRuntimeCriteria)) {
return $this->roomProvider->findRoom();
}
}
}
} That wouldn't work with the proposed approach since the delegating implementation would end up being part of the iterator, right? |
This is exactly the same situation as currently. This works as long as you don't enable autoconfiguration on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second though, I fear this might have a too big impact on the compile-time of the container, since this is now going to parse all doc-blocks of all autowired methods. We should double check this aspect before considering this change.
Note that adding #[TaggedIterator(FooInterface::class)]
next to the @param
already works so this is just a way to write less declarative code next to an argument.
Feature idea: allow doing this with an attribute? |
Trying to help moving forward here: Given the limitations, the potential perf cost and the fact we already have an attribute for that (and using this feature implies to use an attribut anyway) I'm not convinced this is worth it. |
Closing as discussed. Thanks for proposing. |
This patch allows the Dependency Injection component to autowire basic tagged iterators:
(edited: simplified example removing the need for a YAML config)
Tadam! This just works 🎉
This follows discussions about @GregoireHebert's article "Inject a tagged iterator in a more natural way".
This patch has the following limitations:
phpdocumentor/reflection-docblock
must be installed#[TaggedIterator]
to handle these cases