Yii2 и виджеты: немного полемики

Насколько прекрасен и прост Yii2 в работе с backend (хотя, так с любым фреймворком: сколько бы ни ругался на Symfony, но 90% работы происходит с PHP, а не с ним), настолько отвратителен в виджетах и рендеринге. Не знаю, есть ли где-нибудь подобный треш, как в Yii2. Сравнивая с тем же Symfony: там разработчики решили остановиться на дефолтном шаблонизаторе twig и не внедрять в стартовые шаблоны никаких примеров чудо-виджетов. Спасибо, ребят!

Виджеты — ужасная штука. «Это самодостаточный блок», говорили они. «MVC», говорили они. Неужели попытки скрыть передачу данных под видом DataProvider во вьюху действительно не дают повода задуматься?

Как только приходится что-то поменять в виджете, начинается боль. Если вы хотите поменять расположение кнопок — должны потратить два часа на поиски и применение информации. Вы достаточно постигли стандартные виджеты типа GridView? Не волнуйтесь! Любой другой виджет, который вы установите, например, FileInput от Kartik — и вуаля, гуглите снова. Гуглите много.

Окей, я не буду голословным, вот вам код:

Серьёзно, он такой и есть. Выглядит интуитивно понятно и очень гибко. Можно поменять язык, можно настроить множественную загрузку файлов, главное что смотрится красиво! Гляньте:

46078f35a64995249bae95a2076351e7

Да, мне тоже нравится. Работа над плагином проделана большая. Но оставьте это плагином. Зачем делать из него такое, от чего мои глаза ( речь идёт про мои впечатления после использования виджета, и они нисколько не объективны, да ) кровоточили разочарованием в принятых решениях. Побуду циником: взамен предложить нечего. Возможно, потому что Yii2 не стоит лезть во frontend. Возможно потому что отделение backend от frontend есть самое логичное, что произошло с вебом. С тем же вебом, где ECMAScript5 до сих пор не определился, как регламентировать асинхронные процессы, и весь Ajax реализован как бы интуитивно, а не по стандарту ECMA (ну и здорово!).

Давайте вернёмся к коду. Вы заметили ‘pluginEvents’? Это элемент массива, значением которого является… JavaScript! Даже jQuery. Впрочем, на использование jQuery нас обрёк сам фреймворк, но ладно. Дело в том, что приходится писать текст JavaScript прямо в строках PHP. То есть, когда в html встречался коннект к БД, бывалые программисты пускают скупую слезу отчаяния, но сами пишут JavaScript в PHP. Почему? Потому что «виджет есть независимый самодостаточный блок». Тогда что можно назвать виджетом? Календарь? Зачем нам календарик, если мы с ним не можем взаимодействовать? Только в том случае, когда нужно выбрать конкретную дату (и только), он нам пригодится из коробки, как есть. Но если при перелистывании месяцев должно что-то меняться во фронте — о-о, да, запасайтесь кофе и зефирками, впереди долгие бессонные ночи.

JavaScript должен уметь общаться с другим JavaScript. Если нет — в дело пойдут глобальные переменные и window.variable = ‘1’. Как только мы захотим привинтить к календарику что-то красивое, то 1) видим что он виджет и плачем 2) не можем спихнуть эту работу на фронтенда, кроме как заставить всё переписать.

Все видели HTML-разметку? Её обычно много, и в глазах рябит. Но вызывает ли сложности изменить разметку? Хм, обычно нет. Это работа лёгкая и скучная.

Но подождите, сейчас вы увидите на редкость грустную разметку.

Часть шаблона, по которому генерится виджет (точнее, сам плагин). Да, здесь yii2 уже ни при чём, но давайте представим, что нам нужно что-то поменять из этого, а оно оформлено и зашито в виде виджета? А если верстальщик сверстает прекрасное новое оформление для FileInput, отдаст вам, чтобы вы внедрили это, что будет? Снова будет грустно. HTML, от которого просто не может быть весело.

И вы попытаетесь использовать библиотеки виджета, чтобы поменять что-то в нём на js, но не получится! Это ведь самодостаточный независимый блок.

Как вывод, я хочу сказать, что современный веб всегда подразумевает интерактивность компонентов интерфейса. Сейчас такие увесистые компоненты, что перезагружать каждый раз страницу ради серверного рендеринга есть непозволительная роскошь. И если вы загрузили файл, а в списке файлов он отобразится только после ф5, это уже плохо!

Интерактивность требует доступности всех компонентов. В виджетах эта доступность страдает. Может, я не умею их готовить (скорее всего, так и есть) — но зачем учиться готовить то, в чём другим людям придётся ещё долго после меня разбираться? Это одинаково непонятная магия для любого новичка, и одинаково муторная проблема для мидла — виджеты, которые нужно менять, с которыми нужно взаимодействовать, и уж тем более с которыми нужно уживаться, когда пишешь SPA.

Валидаторы

унаследовать от yii/validators/Validator;

 

 

Сценарии в Yii2

При определенных в rules правилах валидации можно указывать сценарии чере scenario:

Использовать так:

Остальные поля исключаются из проверки словно их вообще нет.

События в Yii2

 

Сервис-локаторы в Yii2

Чтобы добавить сервис-локатор в проект, нужно написать во входном скрипте index.php

 

далее идет объявление приложения:

$application тоже является сервис-локатором, поэтому можно так:

Как использовать?

Где-нибудь в контроллере:

Либо:

Еще один способ добавить компонент — через config (main) в массиве components;

‘имя_класса’ => [‘class’ =>’путь к классу’]

вызывать так: \Yii::$app->Имя_класса

Что такое компонент в Yii2

Компонент или сервис — такой класс, который может пригодиться в любой части программы.
Компоненты === сервисы.

Хелперы < Компоненты; Хелперы є Компоненты ( Хелперы это компоненты, но не все компоненты — хелперы ).

Модули < Компоненты; Модули є Компоненты. В чём прикол использования компонентов через объявление их в конфигурации приложения? Прикол в том, что такие компоненты регистрируются, и сервис-локатор беспокоится о том, чтобы эти классы были синглтонами. Это экономнее, безопаснее и лучше.

Регистрация компонентов осуществляется через config:

Доступ к зарегистрированным компонентам осуществляется через переменную приложения:

\Yii::$app->ИмяТвоегоКрутогоКомпонента

Если ты поменял расположение компонента, то регистрация компонента послужит дополнительной обёрткой и тебе не нужно будет бегать, заменяя все пути, которые указывали на компонент: достаточно поменять только в конфиге.

Не используй компоненты через use, используй через components => [] в конфиге.

Никогда не верь подобным выводам: просто используй use с умом.

PS инфа из документации:

Информация: Хотя вы можете зарегистрировать столько компонентов в приложении сколько вам нужно, все таки стоит это делать разумно. Компоненты приложения похожи на глобальные переменные. Использование слишком большого количества компонентов приложения может потенциально сделать ваш код сложным для разработки и тестирования. В большинстве случаев вы можете просто создать локальный компонент и использовать его при необходимости.

Применение некоторых миграций к другой базе данных

В классе миграции переопределить метод init():

Создание WebSocket в yii2

Собирал по кускам из разных статей. Для создания сокетов будет использована технология Ratchet (WebSocket для PHP) и расширенный каркас приложения Yii2 (yii2-advanced).

Понадобится Composer. Yii2 должен был быть развернут именно с его помощью.
1) Нужно добавить в сomposer.json библиотеку Ratchet:

где тильдой обозначен корень проекта.

2) Создать компонент с обработчиком событий сокета в console/components:

3) Создать в console/controllers (или в другом месте, где хранятся контроллеры для консольного приложения) класс:

4) запустить терминал (команды для терминала обозначены как $, сам символ вводить не надо), перейти в корень проекта, ввести:

Терминал перейдёт в режим выполнения задачи и не даст вводить команды, зато сервер готов принимать запросы. Чтобы остановить работу сервера, нужно нажать Ctrl+C, чтобы приостановить, нужно нажать Ctrl+X.

Сервер блокирует выбранный порт (по умолчанию 8080), можно отследить его PID через терминал:

где Номер_порта — число. Для стандартного порта выглядит так:

После этой команды появится PID процесса, который слушает порт. Его можно использовать для снятия задачи:

где PID — число (обычно четырёх-пятизначное)

Чтобы было удобнее, можно запускать в фоновом режиме:

После этой команды PID процесса появляется в терминале сразу.

Клиентская часть (JavaScript):

Поведения (behaviors)

Поведения

Оригинал: русскоязычная документация по yii2. Сжато.

Поведения (behaviors) в yii2 — экземпляры класса yii\base\Behavior. Поведения (примеси) дополняют компоненты приложения без перенаследования. Методы и свойства поведения «внедряются» в компонент, и становятся доступными так же, как если бы они были объявлены в классе компонента. Поведение может реагировать на события, создаваемые компонентом.

Создание поведений

Поведения создаются наследованием класса yii\base\Behavior:

Класс поведения MyBehavior содержит свойства prop1 и prop2, а также метод foo(). Свойство prop2 объявлено с использованием геттера getProp2() и сеттера setProp2(). Компоненту, к которому будет прикреплено это поведение, будут доступны свойства prop1 и prop2, и метод foo(). Внутри поведения можно обращаться к компоненту, к которому оно прикрплено, при помощи self::owner.

Обработка событий компонента

Если поведению требуется реагировать на события, нужно переопределить метод yii\base\Behavior::events(). Например,

Метод events() должен возвращать список событий и их обработчиков. В приведенном выше примере, объявлено событие yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE и его обработчикbeforeValidate(). Указать обработчик в виде:

  • строки с именем метода текущего поведения;
  • массива, содержащего объект или имя класса, и имя метода, например, [$object, 'methodName'];
  • анонимной функции.

Функция обработчика события должна выглядеть так:

Прикрепление поведений

Чтобы прикрепить поведение статически, нужно переопределить метод yii\base\Component::behaviors() в компоненте, к которому оно будет прикреплено. Метод behaviors() должен возвращать список конфигураций поведений. Конфигурация поведения это имя класса поведения, либо массив его настроек:

Для поведения можно указать имя, задав его как ключ элемента массива в конфигурации(myBehavior2 и myBehavior4). Поведение с именем называется именованным, а без имени, соответственно, анонимным.

Чтобы прикрепить поведение динамически, необходимо вызвать метод yii\base\Component::attachBehavior() компонента, к которому оно будет прикреплено

Так же, прикрепить поведение к компоненту можно через конфигурацию:

Использование поведений

Можно обращаться к публичным переменным, методам или свойствам, объявленным с использованием геттеров и сеттеров в поведении, через компонент, к которому оно прикреплено:

Если два поведения, имеющие свойства или методы с одинаковыми именами, прикреплены к одному компоненту, преимущество будет у поведения, прикрепленного раньше.

Примеры работы с поведениями:

Пример: поведение TimestampBehavior

yii\behaviors\TimestampBehavior позволяет автоматически обновлять атрибуты с метками времени при сохранении AR моделей. Прикрепление поведения:

Конфигурация выше описывает следующее:

  • при вставке новой записи поведение должно присвоить текущую метку времени атрибутам created_at иupdated_at;
  • при обновлении существующей записи поведение должно присвоить текущую метку времени атрибутуupdated_at.

Теперь, если сохранить объект User, то в его атрибуты created_at и updated_at будут автоматически установлены значения метки времени на момент сохранения записи:

Поведение yii\behaviors\TimestampBehavior так же содержит метод yii\behaviors\TimestampBehavior::touch(), который устанавливает текущую метку времени указанному атрибуту и сохраняет его в базу данных:

Сравнение с трейтами

Плюсы поведений

  • поддерживают наследование, в отличии от трейтов;
  • могут быть прикреплены и отвязаны от компонента динамически, без изменения класса компонента;
  • можно настраивать;
  • работа с событиями;
  • не вызывают конфликта имен при одинаковых методах в разных поведениях; конфликт разрешается при помощи приоритетов.

Плюсы трейтов

  • не являются объектами, потому имеют высокую производительность;
  • поддерживаются многими IDE, поскольку являются стандартными конструкциями языка.