Конструктор виджетов

Обсуждаем разработку фреймворка: дизайн компонентов, API, пакеты

Какой способ вам нравится больше и почему?

Зависимость через конструктор
4
67%
Зависимость через сеттер
2
33%
 
Всего голосов: 6

Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Конструктор виджетов

Сообщение samdark »

Виджеты, как и в Yii 2, создаются наследованием от класса Widget. Так как у него есть события, ему нужен event dispatcher для их выкидывания. Сейчас есть два способа передачи его как зависимости.

Первый способ заключается в передаче event manager через конструктор. Наследник выглядит при этом так:

Код: Выделить всё

class MyWidget extends Widget
{
    private MyDependency $myDependency;

    public function __construct(MyDependency $myDependency, EventDispatcherInterface $eventDispatcher)
    {
        $this->myDependency = $myDependency;
        parent::__construct($eventDispatcher);
    }
}
Другой способ - передать зависимость через сеттер. Тогда получается более чистый конструктор:

Код: Выделить всё

class MyWidget extends Widget
{
    private MyDependency $myDependency;

    public function __construct(MyDependency $myDependency)
    {
        $this->myDependency = $myDependency;
    }
}
Но при этом, если dispatcher не передан через setDispatcher(), события вызываться не будут.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

Сразу отмечу что на конечный синтаксис это не влияет:

Код: Выделить всё

<?= MyWidget::widget() ?>
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Конструктор виджетов

Сообщение maleks »

samdark писал(а): 2020.01.21, 23:52 Сразу отмечу что на конечный синтаксис это не влияет:

Код: Выделить всё

<?= MyWidget::widget() ?>
А как оно может не влиять, если:
samdark писал(а): 2020.01.21, 23:52 Но при этом, если dispatcher не передан через setDispatcher()
я так понимаю вы предлагаете использовать

Код: Выделить всё

MyWidget::widget(['dispatcher' => объект])
Если вы в базовом виджете предполагаете обязательное выкидывание событий, то не логично будет - вызывать или не вызывать, если "передал или не передал".
Зависимость в конструктор, т.к. она обязательно надо, а в виджетах наследниках свои зависимости не так часто думаю используются чтобы конструктор часто переопределять
Yii2 universal module sceleton - for basic and advanced templates
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

maleks писал(а): 2020.01.23, 08:41 я так понимаю вы предлагаете использовать

Код: Выделить всё

MyWidget::widget(['dispatcher' => объект])
Нет, ::widget() - это фабричный метод, он создает экземпляр виджета через фабрику, которая в свою очередь внедряет зависимости.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

Там немножко грязных трюков... но по-другому будет совсем неприятный синтаксис, что в шаблонах view будет бесить.
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Конструктор виджетов

Сообщение maleks »

samdark писал(а): 2020.01.23, 14:30 Там немножко грязных трюков...
Я так и не понял как вы предлагаете передавать/не_передавать диспатчер виджету. Как я выше написал?
Yii2 universal module sceleton - for basic and advanced templates
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

samdark писал(а): 2020.01.23, 14:30 Там немножко грязных трюков... но по-другому будет совсем неприятный синтаксис, что в шаблонах view будет бесить.
Вроде предварительной установки экземпляра фабрики в WidgetFactory::$factory?
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

maleks писал(а): 2020.01.23, 15:08
samdark писал(а): 2020.01.23, 14:30 Там немножко грязных трюков...
Я так и не понял как вы предлагаете передавать/не_передавать диспатчер виджету. Как я выше написал?
Я же выше написал, по умолчанию (при вызове без параметров MyWidget::widget()) фабрика внедрит стандартный диспетчер, привязанный в контейнере к EventDispatcherInterface. Но можно переопределить свой MyWidget::widget(['__construct()' => [$myDispatcherObject]])
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Конструктор виджетов

Сообщение maleks »

yiiliveext писал(а): 2020.01.23, 15:46 Я же выше написал,
MyWidget::widget(['__construct()' => [$myDispatcherObject]])
Это мне не знакомый синтаксис, чтобы подразумевать это разумеющимся, плюс это не отвечает на вопрос:
Но при этом, если dispatcher не передан через setDispatcher()
Вот через эту кодинку но с null выше?
Yii2 universal module sceleton - for basic and advanced templates
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

Вот так это предполагалось делать в случае необязательного диспетчера: https://github.com/yiisoft/widget/pull/ ... ba310585e4 Но от решения я отказался, поэтому в том, что попало в master, диспетчер обязателен.
roxblnfk
Сообщения: 6
Зарегистрирован: 2019.11.20, 21:16

Re: Конструктор виджетов

Сообщение roxblnfk »

> плюс это не отвечает на вопрос:
А там, собственно, два варианта.
1. Если зависимость не обязательная, то "нет диспетчера — нет к нему обращения".
2. Если зависимость обязательная, то она передаётся в конструктор фабрики, а фабрика уже собирает виджет со всеми зависимостями. Просто базовые зависимости передаются через сеттер. В случае, если виджет не получит диспетчер, то при обращении к нему вывалится исключение.
Уже большинством мнений решили, что диспетчер событий обязателен, даже если твоему виджету он не нужен. Поэтому вариант 1 отпадает. Это решение ведёт к другой проблеме, но сейчас не об этом.

Вообще суть голосования в том, что вроде бы правильно обязательную зависимость засовывать в конструктор, но тогда эти зависимости придётся тащить через все конструкторы наследников. Это не очень удобно, поскольку класс Widget является базовым.

Однако, в случае виджетов есть один нюанс: объекты виджетов в пользовательском коде собираются через фабрику. Не через конструктор. Это даёт возможность использовать особые правила сборки: можно передавать любые зависимости (обязательные и опциональные) через сеттеры, а не через конструктор. А почему бы и нет? У нас сразу появляется отличная возможность очистить конструкторы наследников, даже не надо будет вызывать в них конструктор родителя.

Давайте рассмотрим варинты сабжа:

Код твоего виджета
если зависимости базового класса передаются через конструктор:

Код: Выделить всё

class MyWidget extends Widget
{
    private MyDependency $myDependency;
    public function __construct(MyDependency $myDependency, EventDispatcherInterface $eventDispatcher)
    {
        $this->myDependency = $myDependency;
        parent::__construct($eventDispatcher);
    }
}
если зависимости базового класса передаются через сеттер:

Код: Выделить всё

class MyWidget extends Widget
{
    private MyDependency $myDependency;
    public function __construct(MyDependency $myDependency)
    {
        $this->myDependency = $myDependency;
    }
}
Как ты будешь это использовать во вьюшке
если зависимости базового класса передаются через конструктор:

Код: Выделить всё

MyWidget::begin($options);
    MyWidget::widget($options);
MyWidget::end();
если зависимости базового класса передаются через сеттер:

Код: Выделить всё

MyWidget::begin($options);
    MyWidget::widget($options);
MyWidget::end();
(одинаково, ведь begin() и widget() обращаются к фабрике виджетов)

Как ты будешь создавать виджет в обход фабрики
Не стоит этого делать, парень

Мнения в пользу конструктора вы можете посмотреть на англоязычном форуме https://forum.yiiframework.com/t/widget ... ure/128434

Итого
Один фиг уже смержили вариант с зависимостью в конструкторе. Теперь при написании виджетов придётся в наследниках описывать зависимости конструктора родителей.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

Вы уже и меня запутали.
Мы сейчас говорим о коде, котрый находится в мастере?
Для виджета нужен в обязательном порядке свой EventDispatcher?
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Готово ли уже демо-приложение, на котором все это можно потестировать?
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

Для виджета нужен в обязательном порядке свой EventDispatcher?
Да, нужен. В конструкторе он.
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Да, будет внедрён.
Готово ли уже демо-приложение, на котором все это можно потестировать?
Демо есть. yiisoft/demo. Виджетов так пока нет.
roxblnfk
Сообщения: 6
Зарегистрирован: 2019.11.20, 21:16

Re: Конструктор виджетов

Сообщение roxblnfk »

> Вы уже и меня запутали.
> Мы сейчас говорим о коде, котрый находится в мастере?
голосование было начато до того, как был слит первый PR
сейчас PR1 слит и в мастере есть набросок класса Widget, но всё ещё может кардинально поменяться. Каждый аргументный аргумент, высказанный здесь или на гитхабе, имеет вес и может повлиять на будущее виджетов :)

> Для виджета нужен в обязательном порядке свой EventDispatcher?
Сейчас да. Но это вопрос поднят тут https://github.com/yiisoft/widget/issues/5
EventDispatcher может стать необязательным или исчезнуть из класса Widget

> Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
сейчас да

---

samdark, опять вперёд меня ответил :evil:
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

Что-то мы ребята друг друга не понимаем. Вот поставил я демо-приложение и прикрутил туда yiisoft/widget dev-master.
Сделал свой виджет

Код: Выделить всё

<?php
declare(strict_types=1);

namespace App\Widgets;

use Yiisoft\Yiiwidget\Widget;

class MyWidget extends Widget
{

    protected function run(): string
    {
        return 'Hello yiiliveext';
    }
}
Неймспейс поменял на Yiisoft\Yiiwidget потому, что он конфликтовал с Yiisoft\Widget из компонента yiisoft/view. Что это за фигня, кстати?

в контроллере

Код: Выделить всё

public function index(ContainerInterface $container): ResponseInterface
    {
        $response = $this->responseFactory->createResponse();
        WidgetFactory::initialize($container);
        $output = $this->render('index');
        
        $response->getBody()->write($output);
        return $response;
    }
в представлении

Код: Выделить всё

<?php
echo \App\Widgets\MyWidget::widget()->render();
Результат
Изображение
Так где здесь
Да, нужен. В конструкторе он.
Конструктор прекрасно отнаследовался и диспетчер внедрился, как я и предполагал изначально.
Обрабочик события тоже нормально привязывется

Код: Выделить всё

public function index(ContainerInterface $container, ListenerProviderInterface $provider): ResponseInterface
    {
        $response = $this->responseFactory->createResponse();
        $provider->attach(function(\Yiisoft\Yiiwidget\Event\AfterRun $event) {
            $result = $event->getResult();
            die($result . ' AfterRun');
        });
        WidgetFactory::initialize($container);
        $output = $this->render('index');

        $response->getBody()->write($output);
        return $response;
    }
Тут другой вопрос возникает, а где эти события будут изпользоваться кроме самого виджета? Что-то я не припоминаю, чтобы такое использовал в Yii 2, хотя я виджетами мало пользуюсь.
roxblnfk
Сообщения: 6
Зарегистрирован: 2019.11.20, 21:16

Re: Конструктор виджетов

Сообщение roxblnfk »

yiiliveext писал(а): 2020.01.23, 21:05 Так где здесь
Да, нужен. В конструкторе он.
Конструктор прекрасно отнаследовался и диспетчер внедрился, как я и предполагал изначально.
Обрабочик события тоже нормально привязывется
Так samdark и написал, что всё будет автоматически внедрено:
samdark писал(а): 2020.01.23, 18:47
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Да, будет внедрён.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

Неймспейс поменял на Yiisoft\Yiiwidget потому, что он конфликтовал с Yiisoft\Widget из компонента yiisoft/view. Что это за фигня, кстати?
Уже норм. Виджет выехал из view.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

К вопросу о необходимости событий: viewtopic.php?f=39&t=54180
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Конструктор виджетов

Сообщение yiiliveext »

roxblnfk писал(а): 2020.01.24, 01:00 Так samdark и написал, что всё будет автоматически внедрено:
Вообще-то я отвечал на вопрос человека выше, надо ли вручную обязательно задавать EventDispatcher, и уточнял в этом контексте, потому как по коду в мастере на гитхабе выглядело, что не надо.
Ладно, проехали. Ответьте лучше на другой вопрос.
Почему этот код подменяет определения из конфига контейнера

Код: Выделить всё

    $provider = new \Yiisoft\EventDispatcher\Provider\Provider();
    $dispatcher = new \Yiisoft\EventDispatcher\Dispatcher($provider);
    $container->set(EventDispatcherInterface::class, $dispatcher);
    WidgetFactory::initialize($container);
а этот нет

Код: Выделить всё

    $provider = new \Yiisoft\EventDispatcher\Provider\Provider();
    $dispatcher = new \Yiisoft\EventDispatcher\Dispatcher($provider);
    WidgetFactory::initialize($container, [
        EventDispatcherInterface::class => $dispatcher
    ]);
Уточню вопрос, технически я вижу почему так, но зачем там вообще definitions?
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Конструктор виджетов

Сообщение samdark »

По задумке должен подменять. Я не вижу сходу почему это не случается. Если это так, то это баг factory. Если знаете как поправить, расскажите.
Ответить