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.

Профилирование кода в Symfony

Есть такая замечательная фишка Stopwatch. По сравнению со многими компонентами Симфони, которые нужно доставать через контейнер, инициализировать в каких-то конфигах и прочем, этот компонент самодостаточный и используется простым удобным способом: new Stopwatch. Волшебно! Хоть что-то приятное.

Как сообщается в первоисточнике, есть два способа установки этой штуки. Первый возможен и без самого Симфони:

Второй — использовать официальный репозиторий. Stopwatch есть в ядре фреймворка, можно оттуда её стащить.

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

 

Статистика выполнения кода, находящегося между началом и концом секции, попадёт в event, возвращаемый методом stop. Между прочим, start тоже возвращает этот эвент.

Можно вызывать start с двумя параметрами:

В таком случае, у эвента будет собственная категория. Можно объединять эвенты в категории по какому-нибудь признаку. Зачем? Разработчики приводят для примера собственное решение: Symfony Profiler (один из инструментов отладки фреймворка). В нём разные категории эвентов нужны чтобы по-разному их подсвечивать, когда отображается статитстика (например, все эвенты, профилирующие обращения к БД).

Перед тем, как рассмотреть уже наконец понятие «эвент», посмотрим ещё на одну фишку: периоды. Всё те же разработчики объясняют их на примере секундомера: кроме «вкл» и «выкл», секундомер может замерять время конкретного периода, не переставая считать секунды. Это нужно, чтобы подсчитать, какой круг за сколько времени пробежали бегуны, к примеру. Здесь то же самое:

Что из себя представляет эвент? Это объект класса StopwatchEvent с такими функциями:

После работы профайлера используйте эвент, полученный из stop, чтобы собрать всю статистику выполненного кода.

Напоследок: секции.

 

Зачем? Чтобы дозаписывать в секцию какие-либо эвенты и суммировать раздобытую информацию из разных эвентов для упрощения сбора статистики.

Спасибо, Symfony!

Роуты (routes) в Symfony

После Yii2 они кажутся чем-то странным в Symfony, но аннотации, если так присмотреться, очень удобные. Каждый контроллер может быть гибко настроен под любой роут без танцев с бубном в UrlManager (пожалуй, самый яркий недостаток в Yii2, но я всё равно люблю его больше).

как это выглядит?

 

3cd1fe6ffc635d3aec44fce25cc80913Вот так. Аннотация @Route(«/debug/grab») позволяет привести через запрос ‘http://site.com/debug/grab’ именно к этому экшену.

Если нужен динамический url, запросто делаем вот так:

Таким образом удобно передавать в экшен какой-нибудь id и сразу отдавать его в модель. Роуты могут быть самыми разными, могут вообще не соответствовать названию контроллера, экшена и тд.

Чтобы работало описание роутов через аннотацию, очень важно:

Если работаете с PhpStorm, скачайте плагин Symfony, он помогает автоматически выявлять аннотации и делает много полезных вещей при работе с этим фреймворком.

Как выглядит обычный роутинг с помощью настроек routing.yml?

Как-то так. На самом деле, неудобно, но нельзя забивать на этот способ: иногда нам нужны роуты только в dev окружении, а иногда настройка конкретного роута слишком сложна, чтобы пихать её в аннотацию (да-да, в Yii2 для этого использовались всякие verbFilter и прочее). Вот тогда может пригодиться роутинг в конфиге.

Но всё-таки многие потребности роутинга удовлетворяет и аннотация:

То есть, можно указывать и метод передачи, и динамические роуты, и присваивать имена. Кстати, очень полезная штука. Я поначалу не понимал, зачем в конфиге определять роут через имя, как _errors в примере выше. А вот зачем: потом можно заставить Symfony генерировать ссылки на конкретный роут вне зависимости от того, насколько он усложнился или изменился — достаточно только указать имя этого роута.

Пример прямо из шаблона Twig:

Отсылка к предыдущему роуту.

Спасибо этому парню за материал.

Больше инфы.