Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[DependencyInjection] Autowiring: add setter injection support#17608
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
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.
() around the var def should be removed.
fabpot commentedJan 31, 2016
This feature is indeed a must have to better support the uses cases described in the linked issue. |
sstok commentedJan 31, 2016
What if someone wants to use autowiring but only wants to use constructor autowire and not setter autowire? Or not for all methods (in that case setter autowiring should not be used). |
dunglas commentedJan 31, 2016
@sstok If a Supporting only constructor autowiring or both setter and constructor using a new flag in |
dunglas commentedFeb 5, 2016
@fabpot support for |
weaverryan commentedFeb 6, 2016
@dunglas I love it! I just tried the code, here are the issues / concerns I found:
Thanks! |
fabpot commentedFeb 18, 2016
@dunglas any feedback on@weaverryan comments? |
dunglas commentedFeb 18, 2016
They are all relevants, I need to find some time to work on this. |
dunglas commentedFeb 18, 2016
For the BC break, as@sstok has the same concern, I'll introduce a new |
weaverryan commentedFeb 18, 2016
@dunglas That will fix BC, but I'm concerned about usability - e.g.: services:spring_weather_manager:class:...autowire:trueautowire_setter:true If it weren't for the BC problem, my opinion would be: always do setter injection - after all, if it causes you any issues, don't use it. For that reason, I'd prefer a global flag to turn this on/off that goes away in 4.0. |
dunglas commentedFeb 18, 2016
On the other hand, the BC break is very limited: it will only impact people using autowiring (just a few), having classes with setters for services (unlikely, because it wasn't supported in the first version of the autowiring system), and having a setter that broke the class when triggered (very very unlikely). Maybe can we say that this "BC break" is acceptable, as it's more an edge case than a BC break. |
weaverryan commentedFeb 18, 2016
Honestly, I'm inclined to agree. This is a "magic" feature you're opting into, it's only 1 version it's been available, it won't affect many people, and if it causes an issue, it'll happen at build time (very easy to debug). |
fabpot commentedFeb 18, 2016
👍 for the small BC break instead of yet another configuration setting. |
stof commentedFeb 18, 2016
I agree with you about accepting this small BC break (but we need to document it clearly in changelog files) |
weaverryan commentedFeb 29, 2016
Ok, so BC break is ok. This leaves items 2-4#17608 (comment), when you have some time :) |
fabpot commentedMar 2, 2016
@dunglas Any idea when you will be able to finish this one? |
dunglas commentedMar 2, 2016
Before the end of this week. |
dunglas commentedMar 3, 2016
All issues fixed. Can you review@weaverryan? |
weaverryan commentedMar 4, 2016
Hi Dunglas! I need a few more days to get back a full report - I will make a very clear explanation of the functionality so that everyone is clear how it works (a few cases are almost subjective, so I want it to be clear to everyone). The only issue I've found is that if we cannot autowire because the type-hint is for a non-existent class, it simply doesn't call the method. That's different than the constructor where it throws an exception. Also, I think we (probably me, as I've had some recent PR's merged) may have introduced a bug into the master branch. I'm too short on time to look further right this moment, but I'm getting weird results if I type-hint something like I think we're getting quite close to mastering the exact behavior we want. We need to get it right for 3.1, because whatever we end up with will probably stay with us due to BC. |
| * | ||
| * @throws RuntimeException | ||
| */ | ||
| privatefunctionautowireMethod($id,Definition$definition,\ReflectionMethod$reflectionMethod,$constructor) |
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 do you think about renaming$constructor to$isConstructor to be clearer?
weaverryan commentedApr 1, 2016
I think this PR is ready. The question is: do we want it? It's opinionated (but so is autowiring in general, and it's opt-in). Some of the new autowiring features/uses (like those in DunglasActionBundle) are quite radical, and I think they need to be tested before considering moving further forward (in the core) in that direction. However, if this were merged, it allows more of these ideas to be tested out in the wild - like using traits e.g. I'm 👍, but I don't feel as confidently about this as I have other things in the past. @symfony/deciders |
xabbuh commentedApr 5, 2016
👍 LGTM |
dunglas commentedApr 18, 2016
Rebased. Can be merged. |
dunglas commentedJun 7, 2016
@symfony/deciders what do we do of this PR? Should I close it or merge it? |
fabpot commentedJul 1, 2016
Re-read everything here.@weaverryan and@dunglas did a great job at defining exactly what we should do and what is out of scope. I agree with everything@weaverryan said and as this is what@dunglas implemented, I'm 👍 (I would not advocate its usage for everything but as this is an opt-in feature anyway, this looks good to me). |
fabpot commentedJul 1, 2016
@dunglas Looks like it needs a rebase |
dunglas commentedJul 1, 2016
Rebased. |
fabpot commentedJul 1, 2016
@dunglas I didn't notice but history is really ugly but as there are 2 contribs, gh won't be able to squash commits. Can you do that for me? |
dunglas commentedJul 1, 2016
Should I merge all commits in 1 or should I keep the commit of@weaverryan? |
fabpot commentedJul 1, 2016
I think you can merge everything into 1 commit as@weaverryan contrib is not huge. |
dunglas commentedJul 1, 2016
Done. |
fabpot commentedJul 1, 2016
Thank you@dunglas. |
fabpot commentedJul 1, 2016
@dunglas Can you take care of the docs? |
… support (dunglas)This PR was merged into the 3.2-dev branch.Discussion----------[DependencyInjection] Autowiring: add setter injection support| Q | A| ------------- | ---| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | n/a| License | MIT| Doc PR | todoAdd support for setter injection in the Dependency Injection Component.Setter injection should be avoided when possible. However, there is some legitimate use cases for it. This PR follows a proposal of@weaverryan to ease using [DunglasActionBundle](https://github.com/dunglas/DunglasActionBundle) with#16863. The basic idea is to include a setter for the required service in the trait and let the DependencyInjection Component autowire the dependency using the setter.This way, a newcomer can use the trait without having to create or modify the constructor of the action./cc@derrabusCommits-------a0d7cbe [DependencyInjection] Autowiring: add setter injection support
dunglas commentedJul 1, 2016
Yes, I've a lot of docs to write... |
… add setter injection support (dunglas)" (nicolas-grekas)This PR was merged into the 3.2-dev branch.Discussion----------Revert "feature#17608 [DependencyInjection] Autowiring: add setter injection support (dunglas)"| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets | -| License | MIT| Doc PR | -This reverts commit7eab6b9, reversingchanges made to35f201f.As discussed in#20167Commits-------bf91eda Revert "feature#17608 [DependencyInjection] Autowiring: add setter injection support (dunglas)"
…t (dunglas)This PR was squashed before being merged into the 3.3-dev branch (closes#18193).Discussion----------[FrameworkBundle] Introduce autowirable ControllerTrait| Q | A || --- | --- || Branch | master || Bug fix? | no || New feature? | yes || BC breaks? | no || Deprecations? | no || Tests pass? | yes || Fixed tickets |#16863 || License | MIT || Doc PR | todo |This is the missing part of the new controller system and it's fully BC with the old one.Used together with the existing autowiring system,#17608 and [DunglasActionBundle](https://github.com/dunglas/DunglasActionBundle) it permits to inject explicit dependencies in controllers with 0 line of config. It's a great DX improvement for Symfony.It also has a lot of another advantages including enabling to reuse controller accros frameworks and make them easier to test. Seehttps://dunglas.fr/2016/01/dunglasactionbundle-symfony-controllers-redesigned/ for all arguments.Magic methods of old controllers are still available if you use this new trait in actions.For instance, the [`BlogController::newAction`](https://github.com/symfony/symfony-demo/blob/master/src/AppBundle/Controller/Admin/BlogController.php#L70) form the `symfony-demo` can now looks like:``` phpnamespace AppBundle\Action\Admin;use AppBundle\Form\PostType;use AppBundle\Utils\Slugger;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\Form\Extension\Core\Type\SubmitType;class NewAction { use ControllerTrait; private $slugger; public function __construct(Slugger $slugger) { $this->slugger = $slugger; } /** *@route("/new", name="admin_post_new") */ public function __invoke(Request $request) { $post = new Post(); $post->setAuthorEmail($this->getUser()->getEmail()); $form = $this->createForm(PostType::class, $post)->add('saveAndCreateNew', SubmitType::class); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $post->setSlug($this->slugger->slugify($post->getTitle())); $entityManager = $this->getDoctrine()->getManager(); $entityManager->persist($post); $entityManager->flush(); $this->addFlash('success', 'post.created_successfully'); if ($form->get('saveAndCreateNew')->isClicked()) { return $this->redirectToRoute('admin_post_new'); } return $this->redirectToRoute('admin_post_index'); } return $this->render('admin/blog/new.html.twig', array( 'post' => $post, 'form' => $form->createView(), )); }}```As you can see, there is no need to register the `slugger` service in `services.yml` anymore and the dependency is explicitly injected. In fact the container is not injected in controllers anymore.Convenience methods still work if the `ControllerTrait` is used (of course it's not mandatory). Here I've made the choice to use an invokable class but this is 100% optional, a class can still contain several actions if wanted.Annotations like `@Route` still work too. The old `abstract` controller isn't deprecated. There is no valid reason to deprecate it IMO. People liking using the "old" way still can.Unless in#16863, there is only one trait. This trait/class is basically a bunch of proxy methods to help newcomers. If you want to use only some methods, or want explicit dependencies (better), just inject the service you need in the constructor and don't use the trait.I'll create open a PR on the standard edition soon to include ActionBundle and provide a dev version of the standard edition to be able to play with this new system.I'll also backport tests added to the old controller test in 2.3+.**Edit:** It now uses getter injection to benefit from lazy service loading by default.Commits-------1f2521e [FrameworkBundle] Introduce autowirable ControllerTrait
Add support for setter injection in the Dependency Injection Component.
Setter injection should be avoided when possible. However, there is some legitimate use cases for it. This PR follows a proposal of@weaverryan to ease usingDunglasActionBundle with#16863. The basic idea is to include a setter for the required service in the trait and let the DependencyInjection Component autowire the dependency using the setter.
This way, a newcomer can use the trait without having to create or modify the constructor of the action.
/cc@derrabus