Страница 1 из 2
Конструктор виджетов
Добавлено: 2020.01.21, 23:51
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(), события вызываться не будут.
Re: Конструктор виджетов
Добавлено: 2020.01.21, 23:52
samdark
Сразу отмечу что на конечный синтаксис это не влияет:
Re: Конструктор виджетов
Добавлено: 2020.01.23, 08:41
maleks
samdark писал(а): ↑2020.01.21, 23:52
Сразу отмечу что на конечный синтаксис это не влияет:
А как оно может не влиять, если:
samdark писал(а): ↑2020.01.21, 23:52
Но при этом, если dispatcher не передан через setDispatcher()
я так понимаю вы предлагаете использовать
Если вы в базовом виджете предполагаете обязательное выкидывание событий, то не логично будет - вызывать или не вызывать, если "передал или не передал".
Зависимость в конструктор, т.к. она обязательно надо, а в виджетах наследниках свои зависимости не так часто думаю используются чтобы конструктор часто переопределять
Re: Конструктор виджетов
Добавлено: 2020.01.23, 14:20
yiiliveext
maleks писал(а): ↑2020.01.23, 08:41
я так понимаю вы предлагаете использовать
Нет, ::widget() - это фабричный метод, он создает экземпляр виджета через фабрику, которая в свою очередь внедряет зависимости.
Re: Конструктор виджетов
Добавлено: 2020.01.23, 14:30
samdark
Там немножко грязных трюков... но по-другому будет совсем неприятный синтаксис, что в шаблонах view будет бесить.
Re: Конструктор виджетов
Добавлено: 2020.01.23, 15:08
maleks
samdark писал(а): ↑2020.01.23, 14:30
Там немножко грязных трюков...
Я так и не понял как вы предлагаете передавать/не_передавать диспатчер виджету. Как я выше написал?
Re: Конструктор виджетов
Добавлено: 2020.01.23, 15:34
yiiliveext
samdark писал(а): ↑2020.01.23, 14:30
Там немножко грязных трюков... но по-другому будет совсем неприятный синтаксис, что в шаблонах view будет бесить.
Вроде предварительной установки экземпляра фабрики в WidgetFactory::$factory?
Re: Конструктор виджетов
Добавлено: 2020.01.23, 15:46
yiiliveext
maleks писал(а): ↑2020.01.23, 15:08
samdark писал(а): ↑2020.01.23, 14:30
Там немножко грязных трюков...
Я так и не понял как вы предлагаете передавать/не_передавать диспатчер виджету. Как я выше написал?
Я же выше написал, по умолчанию (при вызове без параметров MyWidget::widget()) фабрика внедрит стандартный диспетчер, привязанный в контейнере к EventDispatcherInterface. Но можно переопределить свой MyWidget::widget(['__construct()' => [$myDispatcherObject]])
Re: Конструктор виджетов
Добавлено: 2020.01.23, 16:11
maleks
yiiliveext писал(а): ↑2020.01.23, 15:46
Я же выше написал,
MyWidget::widget(['__construct()' => [$myDispatcherObject]])
Это мне не знакомый синтаксис, чтобы подразумевать это разумеющимся, плюс это не отвечает на вопрос:
Но при этом, если dispatcher не передан через setDispatcher()
Вот через эту кодинку но с null выше?
Re: Конструктор виджетов
Добавлено: 2020.01.23, 17:32
samdark
Вот так это предполагалось делать в случае необязательного диспетчера:
https://github.com/yiisoft/widget/pull/ ... ba310585e4 Но от решения я отказался, поэтому в том, что попало в master, диспетчер обязателен.
Re: Конструктор виджетов
Добавлено: 2020.01.23, 17:39
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
Итого
Один фиг уже смержили вариант с зависимостью в конструкторе. Теперь при написании виджетов придётся в наследниках описывать зависимости конструктора родителей.
Re: Конструктор виджетов
Добавлено: 2020.01.23, 18:38
yiiliveext
Вы уже и меня запутали.
Мы сейчас говорим о коде, котрый находится в мастере?
Для виджета нужен в обязательном порядке свой EventDispatcher?
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Готово ли уже демо-приложение, на котором все это можно потестировать?
Re: Конструктор виджетов
Добавлено: 2020.01.23, 18:47
samdark
Для виджета нужен в обязательном порядке свой EventDispatcher?
Да, нужен. В конструкторе он.
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Да, будет внедрён.
Готово ли уже демо-приложение, на котором все это можно потестировать?
Демо есть. yiisoft/demo. Виджетов так пока нет.
Re: Конструктор виджетов
Добавлено: 2020.01.23, 18:53
roxblnfk
> Вы уже и меня запутали.
> Мы сейчас говорим о коде, котрый находится в мастере?
голосование было начато до того, как был слит первый PR
сейчас PR1 слит и в мастере есть набросок класса Widget, но всё ещё может кардинально поменяться. Каждый аргументный аргумент, высказанный здесь или на гитхабе, имеет вес и может повлиять на будущее виджетов
> Для виджета нужен в обязательном порядке свой EventDispatcher?
Сейчас да. Но это вопрос поднят тут
https://github.com/yiisoft/widget/issues/5
EventDispatcher может стать необязательным или исчезнуть из класса Widget
> Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
сейчас да
---
samdark, опять вперёд меня ответил
Re: Конструктор виджетов
Добавлено: 2020.01.23, 21:05
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, хотя я виджетами мало пользуюсь.
Re: Конструктор виджетов
Добавлено: 2020.01.24, 01:00
roxblnfk
yiiliveext писал(а): ↑2020.01.23, 21:05
Так где здесь
Да, нужен. В конструкторе он.
Конструктор прекрасно отнаследовался и диспетчер внедрился, как я и предполагал изначально.
Обрабочик события тоже нормально привязывется
Так samdark и написал, что всё будет автоматически внедрено:
samdark писал(а): ↑2020.01.23, 18:47
Или он будет автоматически внедрен при вызове MyWidget::widget() без параметров, если привязан к интерфейсу в контейнере?
Да, будет внедрён.
Re: Конструктор виджетов
Добавлено: 2020.01.24, 01:48
samdark
Неймспейс поменял на Yiisoft\Yiiwidget потому, что он конфликтовал с Yiisoft\Widget из компонента yiisoft/view. Что это за фигня, кстати?
Уже норм. Виджет выехал из view.
Re: Конструктор виджетов
Добавлено: 2020.01.24, 01:56
samdark
К вопросу о необходимости событий:
viewtopic.php?f=39&t=54180
Re: Конструктор виджетов
Добавлено: 2020.01.24, 02:28
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?
Re: Конструктор виджетов
Добавлено: 2020.01.24, 14:47
samdark
По задумке должен подменять. Я не вижу сходу почему это не случается. Если это так, то это баг factory. Если знаете как поправить, расскажите.