Widget constructor signature

Widgets, same as in Yii 2 are created by inheriting from Widget class. Since it has events, it needs event dispatcher in order to raise them. We have two ways of passing it right now.

First, making event manager requirement explicit via constructor. Then child class would look like:

class MyWidget extends Widget
{
    private MyDependency $myDependency;

    public function __construct(MyDependency $myDependency, EventDispatcherInterface $eventDispatcher)
    {
        $this->myDependency = $myDependency;
        parent::__construct($eventDispatcher);
    }
}

Another way is to pass event manager via setter. Then the constructor becomes cleaner:

class MyWidget extends Widget
{
    private MyDependency $myDependency;

    public function __construct(MyDependency $myDependency)
    {
        $this->myDependency = $myDependency;
    }
}

But in case dispatcher isn’t passed via setDispatcher(), not events will be triggered at all.

Which way do you like more and why?

  • Cleaner dependency
  • Cleaner constructor

0 voters

class MyWidget extends Widget
{
    private MyDependency $myDependency;

    public function __construct(MyDependency $myDependency, EventDispatcherInterface $eventDispatcher)
    {
        $this->myDependency = $myDependency;
        parent::__construct($eventDispatcher);
    }
}

I particularly prefer the explicit requirement so when I see the class automatically I see what its dependencies are, and I know that I must inject it into the constructor, it is also more readable and easier to test.

1 Like

With clean constructor we can also make the EventDispatcherInterface dependency to required.
The widget is created through the factory, so required dependencies can easily be passed through setters.

As long as constructor is public, you can create widget using new keyword.

This makes no sense since the begin(), end(), and widget() methods are static.

The decision doesn’t affect widget usage syntax at all. It is still:

<?= MyWidget::widget() ?>

It makes perfect sense, for example for testing - it is easier to create instance specifying dependencies explicitly instead of relying on some factory magic. You can’t assume that every instance will be created using factory.

2 Likes

I’m for the variant with more clear synthax and univocal behaviour. I’m for a constructor dependency.

instead of relying on some factory magic

Do tests for the factory to be sure of factory

for example for testing

You also can create instance using new keyword and then specify dependencies using setter.
There is no difference for testing

I don’t want to test factory. I want to test widget.

There is a difference in API, testing is only an example. If EventDispatcherInterface is required dependency, then it should be clear that it is required. Constructor parameters is clean and common way to specify this requirements. Using setter and hiding it behind optional helper method is another tricky thing the user needs to learn (especially if we ignore missing EventDispatcherInterface dependency and do not handle events at all in this case).

Maybe we’ll have both: A use-case for global Widget events?

Events were removed. Now constructor is clean.