Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

[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

Merged
fabpot merged 1 commit intosymfony:masterfromdunglas:autowiring-setter
Jul 1, 2016

Conversation

@dunglas
Copy link
Member

QA
Bug fix?no
New feature?yes
BC breaks?no
Deprecations?no
Tests pass?yes
Fixed ticketsn/a
LicenseMIT
Doc PRtodo

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

Copy link
Member

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
Copy link
Member

This feature is indeed a must have to better support the uses cases described in the linked issue.

@sstok
Copy link
Contributor

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
Copy link
MemberAuthor

@sstok If acall is explicitly defined for a method, the autowiring system will ignore this method.

Supporting only constructor autowiring or both setter and constructor using a new flag inDefinition should be possible but it looks overkill too me. If you have such edge case for a service, the clean way is just to not use autowiring at all for this service. What do you think?

@dunglas
Copy link
MemberAuthor

@fabpot support forfunction setDependencies(RouterInterface $router, Twig $twig) style added.

@weaverryan
Copy link
Member

@dunglas I love it! I just tried the code, here are the issues / concerns I found:

  1. The fact that would we start auto-wiring setters is a behavior change - it could be a BC break (setters are suddenly called that weren't before). Question: is this a BC break?

  2. If I create a setter withno arguments, the setter is called. I don't think it should: in this case, there's nothing to inject.

  3. If a setterdoes have an argument, but its optional and we can't autowire it, : I think we should do nothing, instead of calling the setter withnull.

  4. If a setterdoes have an argument and it'srequired, but we can't auto-wire it (e.g. no type-hint), I think we should do nothing (don't call the method, but don't throw an exception - the user may manually add acalls for this).

Thanks!

@fabpot
Copy link
Member

@dunglas any feedback on@weaverryan comments?

@dunglas
Copy link
MemberAuthor

They are all relevants, I need to find some time to work on this.

@dunglas
Copy link
MemberAuthor

For the BC break, as@sstok has the same concern, I'll introduce a newaurowireSetter property inDefinition that will befalse by default and set it totrue in action services created by DunglasActionBundle.

@weaverryan
Copy link
Member

@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
Copy link
MemberAuthor

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
Copy link
Member

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
Copy link
Member

👍 for the small BC break instead of yet another configuration setting.

@stof
Copy link
Member

I agree with you about accepting this small BC break (but we need to document it clearly in changelog files)

@weaverryan
Copy link
Member

Ok, so BC break is ok. This leaves items 2-4#17608 (comment), when you have some time :)

@fabpot
Copy link
Member

@dunglas Any idea when you will be able to finish this one?

@dunglas
Copy link
MemberAuthor

Before the end of this week.

@dunglas
Copy link
MemberAuthor

All issues fixed. Can you review@weaverryan?

@weaverryan
Copy link
Member

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 likeDataCollector orEventSusbcribterInterface. These are items that shouldnot be autowireable (as there are multiple services for them), but on master locally right now, theyare autowiring - withone of the matching services. This does not happen on 3.0.1. If someone else can verify this, awesome. Otherwise, I'll look more soon.

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)
Copy link
Contributor

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?

derrabus reacted with thumbs up emoji
@weaverryan
Copy link
Member

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.RouterTrait) to automatically setter-inject services+shortcuts into your services.

I'm 👍, but I don't feel as confidently about this as I have other things in the past.

@symfony/deciders

@xabbuh
Copy link
Member

👍 LGTM

@dunglas
Copy link
MemberAuthor

Rebased. Can be merged.

@dunglas
Copy link
MemberAuthor

@symfony/deciders what do we do of this PR? Should I close it or merge it?

@fabpot
Copy link
Member

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
Copy link
Member

@dunglas Looks like it needs a rebase

@dunglas
Copy link
MemberAuthor

Rebased.

@fabpot
Copy link
Member

@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
Copy link
MemberAuthor

Should I merge all commits in 1 or should I keep the commit of@weaverryan?

@fabpot
Copy link
Member

I think you can merge everything into 1 commit as@weaverryan contrib is not huge.

@dunglas
Copy link
MemberAuthor

Done.

@fabpot
Copy link
Member

Thank you@dunglas.

@fabpot
Copy link
Member

@dunglas Can you take care of the docs?

@fabpotfabpot merged commita0d7cbe intosymfony:masterJul 1, 2016
fabpot added a commit that referenced this pull requestJul 1, 2016
… 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
@dunglasdunglas deleted the autowiring-setter branchJuly 1, 2016 09:02
@dunglas
Copy link
MemberAuthor

Yes, I've a lot of docs to write...

soyuka and theofidry reacted with laugh emojimickaelandrieu, weaverryan, and bocharsky-bw reacted with heart emoji

nicolas-grekas added a commit to nicolas-grekas/symfony that referenced this pull requestNov 2, 2016
…etter injection support (dunglas)"This reverts commit7eab6b9, reversingchanges made to35f201f.
dunglas added a commit that referenced this pull requestNov 2, 2016
… 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)"
fabpot added a commit that referenced this pull requestMar 2, 2017
…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
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

9 participants

@dunglas@fabpot@sstok@weaverryan@stof@GuilhemN@xabbuh@javiereguiluz@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp