Coder Social home page Coder Social logo

[2.1] Method Injection about symfony HOT 20 CLOSED

symfony avatar symfony commented on May 22, 2024
[2.1] Method Injection

from symfony.

Comments (20)

kriswallsmith avatar kriswallsmith commented on May 22, 2024

I'm not sure how I feel about this. It strikes me that classes built with this annotation would be bound to the DIC, which isn't want we want.

If the issue you're trying to address is circular dependencies, is there anyway to we can tweak setter injection to prevent this loop? For instance, this is possible when bootstrapping by hand, but not possible in the DIC:

<?php

$a = new A();
$b = new B($a);
$a->setB($b);

If the issue is lazy dependencies, have you considered adding a lazy option to Reference and generating something like a Doctrine proxy object for that reference?

<?php

class Lazy_MyDependency extends MyDependency
{
    private $__symfonyContainer;
    private $__symfonyObject;
    private $__symfonyLoaded = false;

    private function __symfonyLoad()
    {
        $this->__symfonyObject = $this->__symfonyContainer->get('my_dependency');
        $this->__symfonyLoaded = true;
        unset($this->__symfonyContainer);
    }

    // proxy public methods...
}

from symfony.

marijn avatar marijn commented on May 22, 2024

I prefer auto wiring, over this solution.

from symfony.

kriswallsmith avatar kriswallsmith commented on May 22, 2024

I'm still not convinced. This would require you design your classes for vertical reuse, and awkwardly at that.

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

I think the amount of code saved is minimal, especially since you could also do the assignment inside the constructor at which point you are not even saving lines anymore. Furthermore this would lead to cases where you get errors on lines that do not match your original code.

-1

from symfony.

stof avatar stof commented on May 22, 2024

You cannot do this in the constructor as you get the container through as setter when extending ContainerAware.

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

Ah, right of course. Even still I think the lines saved is minimal and the debugging confusion makes this a no go for me. Debugging generated code is just a nightmare.

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

i am fine with generated PHP code for routes and the container since i usually shouldnt debug them, but for a controller its just not a good idea .. even if the line number if just off by a few lines its annoying. also it doesnt solve everything i am trying to solve ..

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

yes they will .. i was more talking about the final class .. but i guess one can just ignore that generated controller in stack traces, since actual errors should only occur on the abstract class.

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

OK, just to clarify things:

  1. yes the original class stays intact and it can be expected that any bugs will be in the original class and not the generated one. so the concerns i raised where largely irrelevant

  2. the ContainerWrapperBundle addresses two issues of which this approach only solves the first one: the first issue is being able to prevent hardcoding of the service id, the second is preventing uncontrolled access to the container in order to maintain an overview of what dependencies a service actually has. so as long as the entire container is still exposed within the service the second issue is not solved by this.

That being said, the ContainerWrapperBundle does provide a mode that in case there are no mappings of services can optionally remove the wrapper based on a configuration setting. This enables using the wrapper only during development and relying on the actual Container in production to reduce overhead. Now since this approach does solve the mapping, this "optimization" becomes even more feasible.

That being said, somehow I still have a negative gut feeling, but its not a full -1 anymore :)

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

Continuing my monolog. One thing that seems to be missing is a way to define a default service id, this would make this viable for non service Controllers

abstract class MyController
{
    /**
     * @MethodInjection(default="request")
     * @return Symfony\Component\HttpFoundation\Request
     */
    abstract function getRequest();
}

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

return Request::fromGlobals(); not sure what use case you are trying to illustrate here ..?

from symfony.

lsmith77 avatar lsmith77 commented on May 22, 2024

One question more, what makes this better than simple property injection? I mean is the "advantage" just that it uses the injected container? If so I would say the main use case are "lazy people" that dont really care at all about the concept of the DIC etc and therefore would probably just as well or even better be served via property injection with similar capabilities for defining a default service in an annotation + ability to redefine the actual dep via a service definition.

from symfony.

kriswallsmith avatar kriswallsmith commented on May 22, 2024

Defining an abstract method that provides a dependency is the opposite of dependency injection. We should not be encouraging people to design their classes in this way; it's not practical outside of this feature.

from symfony.

simensen avatar simensen commented on May 22, 2024

If I am reading this correctly it sounds like this would require generating code for Controllers. It also sounds like this wasn't happening before. If this is the case, would code be generated for all Controllers or would it only be generated for Controllers that need Method Injection?

What effect would this have on other services that may try to do Method Injection? Would they get base classes created for them as well?

from symfony.

joshiausdemwald avatar joshiausdemwald commented on May 22, 2024

Hi all, sorry to participate to the discussion in a probably unqualified manner. I am a big fan of "magic" behaviours like autowiring, as mentioned in a blog post of mine a few days ago (which lsmith was so kind to writing an detailed answer for. Unfortunately available in german only due to my sinister english skills (http://bit.ly/jWOfvO).

Besides all pros and cons mentioned above which i will have to read again very carefully to understand the drawbacks and undesired side effects, i want to suggest a probably (really plain) solution to avoid potential flawy or hard-to-debug code generation: A way to assign dependencies from outside to protected/private members could be using the built-in Reflection API by calling the ReflectionMethod/Property::setAccessible() method. This would probably imply an extension to the DIC and a performance drawback for sure (approximately twice (correction: 5! :/) the time a "regular" instance tree initialization would take, according to this post: http://bit.ly/13za52 But understanding autowiring as what i consider it to be this should be no showstopper because it would only affect "a handful" of instances (in contrast to e.g. hundreds or thousands of Doctrine ORM entities that potentially) are instanciated at runtime).

Nevertheless a +1 from me in general for this feature, mainly to gain API transparency and out-of-the-box IDE code-completion (respectivly what is used to be called "out-of-the-box" when dealing with PHP :D)

Thank you all for your hard work and best regards!

from symfony.

simensen avatar simensen commented on May 22, 2024

How does this make code completion easier in an IDE vs. doing property injection? I've seen a couple of people mention this. It seems like it should be the same (I get code completion already from @var annotation).

Is it in the case that the property wants to be private and the concrete class shouldn't have access to the actual property? Or am I missing something else?

from symfony.

joshiausdemwald avatar joshiausdemwald commented on May 22, 2024

You are absolutely right, you can gain code-completion through the current mechanisms to by e.g. annotatin\g vars like this (this works for at least the netbeans IDE):

/** @var $em \Some\Entitiy\Manager\Implementation **/
$em = $this->get('some.really.long.service.identifier);

Correct me if i am wrong, but i consider the "default", de-facto-standard syntax for PHP Doccomments beeing like this:

/**

  • An entity manager
  • @var \An\Entity\Manager $em: This is my entity manager
    */
    private $em;

But this will not work at any scope, for local variables like the one fetched out of the DIC you'll have to use the special syntax.

With autowiring, you would have the "standard" confortable look-and-feel of members at any visibility, and even mutators may be annotated in a way so that they may be used "as usual":

/**

  • @resource(name="my.member.service")
  • @var \My\Member $myMember: A member
    */
    private $myMember;

/**

  • Does something.
    *
  • @Inject(resource="a.another.member.implementation")
  • @return \A\Returnvalue
    */
    public function setAnotherMember(\Another\Member $member)
    {
    return $member.getAReturnValue();
    }

This seems to be a clean way to wire my classes, and the dependencies stay "extensible" in the way that they can be easily replaced in the DIC definition.

I admit that the above mentioned "getter"-injection seems to be a bit complicated for me, its behaviour may be a little unforseenable. But setter injection is a well known pattern, or not?

With the proper "magic methods and brain fucking" DIC implementation, it probably may be possible to even inject into private and protected methods and properties - i don't see any dawbacks from there, because the DIC anyway is the "god of dependencies". What the DIC is allowed to do, the concrete API user must not be allowed to do.

But the bundle developer must be aware that the DIC may override private properties... May that be a problem?

//
Addendum: In the case of Property injection, you still have to know the service name - this is a slightly annoying thing for symfony beginners. But in the case of Setter-Injection, you even can analyze the method signature an compare the interface name to the concrete implementation of the service definition - so you'll have had a "real" java/spring like autowiring feature. And this would be a really amazing feature: You gain the ability to identify the dependency through the interface ("interface injection"), not through the service name.

And sorry - speaking about code-completion, but beeing to dumb to define markdown code-blocks :D

from symfony.

nfx avatar nfx commented on May 22, 2024

I have some ideas on Property Injection. Shall I elaborate?

from symfony.

loicfrering avatar loicfrering commented on May 22, 2024

Hello guys, I am also concerned with easy dependency injection and service definitions for advanced users who want to take full advantage of the power of the DIC, and that want to define their controllers as services (and not directly inject the container into their controllers). I have developed a bundle that enables annotation-based dependency injection for Symfony2 applications.

You can then come to this:

<?php
use LoSo\LosoBundle\DependencyInjection\Annotations as DI;

/** @DI\Controller */
class UserController
{
    /**
     * @var Doctrine\OROM\EntityManager $em
     */
    private $em;

    /** @DI\Inject("doctrine.orm.entity_manager") */
    public function __construct($em)
    {
        $this->em = $em;
    }

    // ....
}

You can check the code on my Github repository and have a look to the documentation to let me know what you think about this.

from symfony.

joshiausdemwald avatar joshiausdemwald commented on May 22, 2024

It did not leave me in peace, thus i had to give it a try by myself and spend a weekend. I am aware of the fact that the general discussion does not affect the current core-development team (or does it?) so i am not sure if this is the right platform for discussing it - so forgive me and ignore my post if you feel unconcerned. Perhaps - if anyone is interested - may we meet at another location to discuss this features?

@loicfrering i love the approach as it provides some neat shortcuts for defining controllers as services - luckily the framework´s routing system supports that. Thanks for your great work on that! I have chosen a similar solution to define services and injecting dependencies by annotations, but in contrast to your code i wanted it to be more "convention driven" - merly to get rid of recalling service ids.

It is only a prototype, and the rules to resolve dependencies are not elaborated well. But a tiny demo works (might be buggy as ...:(), and the documentation explains the possiblities and purposes. It must be seen as a case study for investigating use cases, not as a solution design document for "the greatest autowiring stuff that´s ever been seen".

// The link to the repo:
https://github.com/joshiausdemwald/AutowiringBundle

I would love to hear comments about it. Thank you!

from symfony.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.