So, the new dependency injection approach requires me to inject everything I need into the contructor of an object. I get that.
But how is this more flexible?
For instance…
I have my own Topmenu class in my own module. It extends \Magento\Theme\Block\Html\Topmenu.
In my custom code I am missing the DataObjectFactory. So I created my own constructor. There are two issues that really bug me:
- I have to copy the entire parent constructor into my own just to inject one additional object.
This is for real? It is not that I am stupid and did not get the point? I really have to do it this way? To me this is just tedious and extremely redundant. But if I don't do it, PHP just stops with an error. How is this an advantage?
- Now that I have copied the constructor…
public function __construct(
Template\Context $context,
NodeFactory $nodeFactory,
TreeFactory $treeFactory,
array $data = []
) {
parent::__construct($context, $data);
$this->nodeFactory = $nodeFactory;
$this->treeFactory = $treeFactory;
}
… I notice that $this->nodeFactory and $this->treeFactory are declared private. How am I supposed to extend a class/block this way?
And all this fuzz so I can have a simple dataobject that I can pass to an event I need to dispatch from my custom Topmenu.
Am I missing something here?
Best Answer
You're not stupid, you're just missing a few basic things here. But I think once you put them into practice you'll see that this is way more flexible.
Factory Classes Any class with
Factory
at the end, unless you explicity create a php file and class, will be automatically generated. For example, in your constructor, if you pass in\Vendorname\Modulename\Model\SomethingFactory
, that class will get generated automatically.In developer mode, the factory class gets created on script run/page load. In production mode, the factory class gets created during setup:di:compile.
A call to
$this->somethingFactory->create()
will return a new instance of\Vendorname\Modulename\Model\Something
.Now if you were not to pass a factory into your constructor but instead, just the class
\Vendorname\Modulename\Model\Something
, you would not be getting a new instance of that class but rather an instance that was already created. If you worked on M1 at all, you may remember Magento's singleton, its the same thing.Regarding passing your class into the constructor, I see an optional
$data = []
argument which is there for your convenience. So in your di.xml file, you could do something like:Then, in your class, depending on whether you've extended
\Magento\Theme\Block\Html\Topmenu
or you've created a plugin, you can either do$object = $this->getData('my_class_factory')->create()
OR
$object = $subject->getData('my_class_factory')->create()
This is only the tip of the iceberg. I would strongly recommend the the following:
Good luck and let me know if you have any questions!