Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[WIP] Annotation support for Services#21376
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
| */ | ||
| public function process(ContainerBuilder $container) | ||
| { | ||
| if (class_exists(AnnotationReader::class)) { |
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.
if (!class_exists(AnnotationReader::class)) ?
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.
thanks :)
| */ | ||
| class Service | ||
| { | ||
| private $shared; |
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.
Should we addautowired too?
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.
Definitely - it's one of my todos :)
| } | ||
| } | ||
| private function augmentServiceDefinition(Definition $definition) |
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.
It should read recursively annotations from parent classes and implemented interfaces.
| $onInvalid = $arg->getOnInvalid(); | ||
| $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | ||
| if ('ignore' == $onInvalid) { |
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.
===
| $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; | ||
| if ('ignore' == $onInvalid) { | ||
| $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; | ||
| } elseif ('null' == $onInvalid) { |
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.
===
| { | ||
| $arguments = array(); | ||
| $i = 0; | ||
| foreach ($method->getParameters() as $parameter) { |
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.
Why not using the key instead of the$i variable?
foreach($method->getParameters()as$i =>$parameter) {$arguments[$parameter->getName()] =$i;}
It should do the same thing:https://3v4l.org/Zpq4W
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.
Updated!
dunglas commentedJan 23, 2017
I'm still not a fond of having (non-standard) annotations for DI. I've explained my reasons in depth here:#21103 (comment) However I recognize that it is practical for parameters injection. I've proposed a less intrusive alternative in#20738, but I'm not very convinced by it either. Maybe should we keep with the current solution for now: _defaults:autowire:trueparameters:mandrill_api_key:XXXXXXXXXservices:App\NewsletterManager:['', '', '%mandrill_api_key%']# This is already working |
ogizanagi commentedJan 23, 2017
weaverryan commentedJan 23, 2017
@dunglas I agree with much of what you are saying :), and I see that we're both after trying to solve the "parameter" problem in some decent way. I'm also not convinced by#20738, so we could either stay with the current YAML solution or use annotations (or maybe there's a 3rd option). About your comments (#21103 (comment)), I don't see these as a significant problem. Overall, the fact that this feature would be meant for end-users - and not library authors - puts most of those concerns to rest. And in app code, coupling your code to your framework isn't a problem (actually, I see it as an advantage for speed and clarity). Also, it mayhelp the container to be seen as simply an "internal detail" to end-users. If auto-wiring were perfect, then life would be good. But since there will always be edge-cases (parameters being the big one), with annotations, the user could avoid needing to suddenly (and strangely) go into But, we'll see what others think - I wanted to get some real code to help with this exact discussion! Cheers! |
GuilhemN commentedJan 23, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
This made me think, can't we have named arguments in yaml? (e.g. services:Foo:arguments:mandrillApiKey:%mandrill_api_key% ). Having annotations look huge to me if this is the only motivation, don't you think ? |
dunglas commentedJan 23, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@GuilhemN I've proposed this exact solution to@nicolas-grekas today and I'm working on a PR to implement it 🙌 |
weaverryan commentedJan 23, 2017
dunglas commentedJan 23, 2017
Alternative proposal:#21383 |
nicolas-grekas commentedJan 24, 2017
Note that to me, this PR and#21383 do not compete. We could very well have both onboard. |
| return; | ||
| } | ||
| $this->reader = new AnnotationReader(); |
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.
what about using$container->get('annotation_reader') instead? this service is already used at compile time by some other extensions.
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.
and it already causes issues regarding incomplete service configuration (remember the burden when switching the cache configuration in 3.2 ?). We always documented that getting service instances during a compiler pass is an unsupported usage of the container (and so you are on your own and it may break in weird ways), so we should not do it in Symfony itself (especially when it can still break because of a change done by another bundle)
nicolas-grekasJan 24, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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 more than remember since I worked on that again in#21381.
Yet it allowed to fix a core issue, which is that there should be no cache enabled at build time.
Thus, usingannotation_reader could be also seen as a way for us to support using it at compile time a first class citizen - which we have to anyway, as history proved us.
| private $lazy; | ||
| public function __construct(array $data) |
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.
why not removing the constructor and using public properties, letting the annotation parser validate properties itself ? This is the recommended usage of doctrine/annotations when annnotation classes don't need to be reused for other purposes (which is why we don't do in the validator component: constraints themselves are used as annotations, but they are not only annotations)
…(dunglas, nicolas-grekas)This PR was merged into the 3.3-dev branch.Discussion----------[DependencyInjection] Add support for named arguments| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | yes| Tests pass? | yes| Fixed tickets | -| License | MIT| Doc PR | todoThis PR introduces named arguments for services definitions. It's especially useful to inject parameters in an autowired service. It is (at least partially) an alternative to#21376 and#20738.Usage:```ymlservices: _defaults: { autowire: true } Acme\NewsletterManager: { $apiKey: "%mandrill_api_key%" }# Alternative (traditional) syntaxservices: newsletter_manager: class: Acme\NewsletterManager arguments: $apiKey: "%mandrill_api_key%" autowire: true``````phpuse Doctrine\ORM\EntityManager;use Psr\Log\LoggerInterface;namespace Acme;class NewsletterManager{ private $logger; private $em; private $apiKey; public function __construct(LoggerInterface $logger, EntityManager $em, $apiKey) { $this->logger = $logger; $this->em = $em; $this->apiKey = $apiKey; }}```Commits-------8a126c8 [DI] Deprecate string keys in arguments2ce36a6 [DependencyInjection] Add a new pass to check arguments validity6e50129 [DependencyInjection] Add support for named arguments
weaverryan commentedFeb 13, 2017
I'll close this for now (thanks to#21383). We may still want this in the future, to avoid needing to touch a YAML file once you need to map a custom, non-autowired arg... but let's see how this all sorts out. |
Uh oh!
There was an error while loading.Please reload this page.
Hi guys!
This is a WIP solution for adding annotations to services, and is similar to some proposals in#21103. Notice, this does NOT include a "discovery" mechanism for services: you must still register your service like normal (e.g. in YML or XML file), but then the annotations in the service are used to augment the service Definition. But, if#21289 is merged, then that'll cover automatic "discovery" for these services :).
For me, the BIG motivation is to augment autowiring, when you have just one argument that can't be autowired. Annotations read much better than, for example, setting the index "2" argument in YAML.
Pretty much anything that you can set in YAML would be supported (most is still a TODO). The feature is currently activated by a tag... which is really ugly (though
_defaultsat least helps this). We could add this to theDefinitionobject (like we did withautowire) if we want.In#22103, there was some talk of following a Spring standard. While I think it IS important to look and learn from them, this keeps very close toour existing standard: effectively re-using all our existing terminology, but in YAML. The
@Argumentannotation re-uses all the options from the<argument>tag in XML service config.Cheers!
TODOS
@Tagannotation