4

I have been playing around with Magento 2. There are some things which I don't understand yet. As far as I know so far is that the object manager automatically inserts the right objects to the constuctor. I have some questions regarding this.

I have a controller which extends the following class:

\Magento\Framework\App\Action\Action

When I open this class I see that the __constuctor class has one argument and it expects to be an instance of the Context object.

Now for learning purposes i did this to see with is being injected (it doesn't take more then two arguments by default).

public function __construct($a, $b)
{
    var_dump(get_class($a));
    var_dump(get_class($b));
}

It outputs the following

string(34) "Magento\Backend\App\Action\Context"
string(41) "Magento\Framework\View\Result\PageFactory"

Why are these objects injected? Where can I see which objects I can pass in my constuctor. I couldn't findt any hints in the parent class. I suppose it is dependend on the class I extend?

What happens when I extends below class? And how does the system (and I) know what will be injected?

\Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction

What I am looking for in an answer is not a solution or explaination for this specific example. Moreover I am looking for an overall explaination how I can understand the system better and where I can lookup what I should or must pass as an argument.

4 Answers 4

5

I haven't actually tracked this down through code, but here's how I've come to reason about it, and the behavior described below appears to be true (even if the behind the scenes code used by the object manager is different). That said, your question leaves some important details out and is a little vague -- see comments below for some requested clarification that might clear things up.

When the object manager instantiates an object, it looks at your class's __construct method. If your class doesn't have a __construct method, then it looks at the next class's __construct method, etc. until it finds a class with a __construct. Once found, it uses those constructor parameters, and those paramaters only, to build a list of parameters to inject.

Put another way, the object manager will inject the parameters in the constructor PHP would normally call. Remember, PHP only calls one constructor. If you want a parent's constructor class to be called, you need to do parent::__construct(...). This means if the parent class needs a specific list of parameters, its your job to ensure they're also injected in your constructor (so that you can pass them on with parent::__construct).

Regarding your specific questions

Now for learning purposes i did this to see with is being injected (it doesn't take more then two arguments by default).

Your testing methodology seems like it might be a problem here. I tried creating a __construct method in a custom frontend controller that looked like this

public function __construct($a, $b)
{
    var_dump(get_class($a));
    var_dump(get_class($b));
}

And Magento/PHP yelled at me

Missing required argument $a of Pulsestorm\Commercebug\Controller\Lookup\Index

It's also unclear from your questions if these were frontend or backend controllers. If you include more specific code and expand on the steps you used to create your controller, someone may be able to help you understand why the constructor receives a Context object and a page factory object

Regarding the Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction class: If your class extends this class, Magento will inject what parameters are in your __construct method. If your class doesn't have a __construct method, they you don't need to worry about what's injected. Magento will handle it for you via the parent class.

1
  • This is actually been very helpful and helps me understand the system better. I have been reading over some important details in the error messages which Magento gave. The thing was when I passed the objects the right way into the constructor it would go on with the code and came across the parant constuctor which needed 2 arguments. I had only one argument which I passeed (from some sample code). Magento was outputing this as en error, but I thougt my intital constuctor was throwing this error. So I was very confused. Your constructor explaination was very usefull. Thanks again.
    – Akif
    Jan 30, 2016 at 14:07
3

I'd recommend to read Alan Storm's articles about Magento2 object system http://alanstorm.com/category/magento#magento_2_object_system

1
  • I followed allong these articles a while ago. It made allot clear, but my questions still stands. Which part specifically explains what I am asking?
    – Akif
    Jan 29, 2016 at 11:25
2

Here is documentation for Magento DI - http://devdocs.magento.com/guides/v2.0/extension-dev-guide/depend-inj.html

3
  • I read the manual (offcourse), since I didn't understand it fully I asked this question. The manual says: "Magento uses class constructor signatures, not doc-block annotations, to retrieve information about class dependencies; that is, to define what dependencies are to be passed to an object. Magento reads constructors using reflection." Can you explain what this means?
    – Akif
    Jan 29, 2016 at 11:21
  • 1
    Magento Object Manager uses reflection php.net/manual/en/book.reflection.php to read type of expected arguments. Then, applies DI configuration from di.xml files to replace any interfaces with their class preferences, to use values from configuration (if any), etc., and creates objects of the classes.
    – BuskaMuza
    Jan 29, 2016 at 17:47
  • Thanks! I took notice of reflection, read some explaination. But I still don't know how to check which arguments are passed into the constructor when I just extend a class like \Magento\Framework\App\Action\Action. Why are Context and PageFactory passed? Where is this set? How would I know this? Can I see that somewhere in the framework? I want to know this so I know what to pass myself. I couldn't find any di.xml in the according framework folders.
    – Akif
    Jan 29, 2016 at 23:09
1

I would suggest taking a look at the di.xml file located under app/etc/di.xml.

It contains most of the frameworks preferences as well as virtual types and type settings.

To follow the manual an Interface should always be injected and not an object and then set the preferred class in a di.xml preference. Magento does not follow this all the time.

As far as the Context classes go, I tread them as a local library that is needed in a certain class and it's children. Instead of injecting all the classes in all the constructors of all the children and having to keep track of their location and what is missing, you would create a Context that contains a library of needed classes and stores them in protected proprieties with public getters.

This way, in the constructors of your main parent class, you can use the Context getters to locally set proprieties that you need in that class. This avoids constructors maintenance in time and keeps the git history clean.

For instance, say you build a parent class that has 6 children classes nested, however you want. All child classes must maintain the parent class constructors signature (types and order). Now, a few weeks later, you inject another class in the main parent class, this means that you now need to alter the __construct signature of all children classes = PAIN , instead, you inject it in the Context and since that gets injected in all child classes you don't need to think of the __construct signature.

Also, if you do decide to change what gets injected in the constructor, you can then use a virtual type to extend the Context and then use type to change the arguments you want in the signature. Then use type again to change the constructor for just a specific class and you now have your altered Context.

This might get confusing at first but it does provide a great way to alter classes and functionality without too much effort.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.