-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DependencyInjection] Add Definition::addExcludedTag()
and ContainerBuilder::findExcludedServiceIds()
for auto-discovering value-objects
#59704
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
findTaggedServiceIds
, with a new parameterfindTaggedServiceIds
, with a new parameter
findTaggedServiceIds
, with a new parameterfindTaggedServiceIds
, with a new parameter
599c55d
to
b949891
Compare
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.
I'm not sure I like to have a method with "services" in its name return non-services things
this made me wonder if we should add another method instead like this?
findTaggedValueObjects($name, $autoExclude = true)
b949891
to
2cc8c75
Compare
findTaggedServiceIds
, with a new parameterContainerBuilder::findTaggedValueClasses()
for auto-discovering value-object classes
I added the method, that's a lot better and it allows to add the additional feature of automatically set the |
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.
But isn't it late in the CompilerPass workflow?
This depends on the stage the compiler pass runs, right?
Nothing related to this PR IIUC.
src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
Outdated
Show resolved
Hide resolved
I think I've got your point. A complimentary idea might be to add Tentatively: /**
* @return $this
*/
public function tagAsValueObject(string $name, array $attributes = []): static
{
return $this->addTag($name, $attributes)->addTag('container.excluded', ['source' => \sprintf('by tag "%s"', $name));
} |
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.
Closer to the sweet spot :)
Perfect, we have the full feature like this:
Now I wonder if we could skip de tag and delay the function registerAttributeForValueObject(Entity::class, static function (ContainerBuilder $container, array $classes) {
$container->setParameter('doctrine.entity_classes', $classes);
}); |
ContainerBuilder::findTaggedValueClasses()
for auto-discovering value-object classesDefinition::addValueObjectTag()
and ContainerBuilder::findTaggedValueObjects()
for auto-discovering value-objects
I get and support the use case this tries to solve, but I don't like the fact we are adding the concept of value objects to the DIC. Services vs non-services is all the container knows so far which makes sense. Also good part of the objects mentioned in the linked use cases do not match the definition of a value object actually: neither entity/models nor API resources are VO, both have identifiers. |
That's class definitions that contribute to the build of the DIC; even if this classes are not used for services. What do you think if we rename Then we could have a |
I don't like addClassTag / findTaggedClasses - it doesn't tell anything about those not being services. Also this returns identifiers, not classes (even if most of the time we equal both). If VO doesn't match, then what remains is that we want to exclude those definitions. What about:
|
Since it's the class names we're interested in here, we can group the result tags by class name and not by serviceId. This way, there's no need to call |
Class names are only one possible use case. Maybe the main one, but I don't see why we should optimize the design for this use case. |
We are creating a way to read attributes on classes and make this metadata available to inject in services. There is no point in having multiple definitions for the same class as attributes are defined on the class itself (we can merge them). |
Unless there is one. My point is that the design and the code are perfectly able to handle more than just lists of classes, and I don't see any reasons (but our current narrow vision) to restrict the capabilities of what we already have... |
A DIC is all about services. The concept of excluded services has been added to Symfony's DIC mostly for DX purpose following the introduction of autowiring/autodiscovery, and it is still mostly hidden today if we look at the component's public API.
Fact is that DI's low-level API is decoupled from classes through supporting any string as service identifier everywhere and allowing callables/factories for service construction, which is nice and fits PSR-11 perfectly also.
I agree. Trying to find a generic term for grouping some classes through the container then making them excluded looks like a dead end as there are many possible reasons for a class not to be registered as service and certainly ones we don't even imagine. Excluded services however is a concept we already have so let's build on it. Then Nicolas' proposal looks sensible. |
…constructor when autodiscovering (nicolas-grekas) This PR was merged into the 7.3 branch. Discussion ---------- [DependencyInjection] Don't skip classes with private constructor when autodiscovering | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | Fix #48392 | License | MIT With value objects auto-discovery becoming more mainstream (see #59704), it's time to fix registering classes with private constructors. Those are skipped today but with support for `#[Autoconfigure(constructor: 'createInstance')]` as introduced in #49665, this doesn't make sense anymore. Best reviewed [ignoring whitespace](https://github.com/symfony/symfony/pull/59712/files?w=1). Commits ------- 99830f6 [DependencyInjection] Don't skip classes with private constructor when autodiscovering
0bbbda4
to
1fcd764
Compare
I updated the methods with more generic names:
|
6cedb37
to
f2259e1
Compare
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.
LGTM, just minor wording things.
Definition::addValueObjectTag()
and ContainerBuilder::findTaggedValueObjects()
for auto-discovering value-objectsDefinition::addExcludedTag()
and ContainerBuilder::findExcludedServiceIds()
for auto-discovering value-objects
…erBuilder::findExcludedServiceIds()` for auto-discovering value-objects
a02b876
to
7a0443b
Compare
Thank you @GromNaN. |
…tag" (kbond) This PR was merged into the 7.3 branch. Discussion ---------- [DependencyInjection] Rename "exclude tag" to "resource tag" | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | Follow up to #59704 | License | MIT I find `$definition->addExcludedTag('app.model')` and `$containerBuilder->findExcludedServiceIds('app.model')` unintuitive. If feels like your excluding something from the DI container but in fact, your registering it, but in a "different way". The fact that it's an excluded service is just a side-effect. This is especially weird when the tag has attributes (`$definition->addExcludedTag('app.model', ['connection' => 'default'])`). Totally open for a name other than "resource". Commits ------- aa91936 [DI] Rename "exclude tag" to "resource tag"
We could not use the method
findTaggedServiceIds
in #59401 (comment), same for api-platform/core#6943.As "using the container loading tools to do resource discovery quite seamlessly" seems to be a good idea, this changes make it easier.
I'm not closed to alternative ideas if we want to go further with this use-case.
Usage
Let's create a
AppModel
attribute class and use it on any class of the project.In the extension class:
In a compiler pass:
And this parameter can be injected into a service, or directly update a service definition to inject this list of classes. The attribute parameters can be injected into the tag, and retrieved in the compiler pass, for more advanced configuration.