Устройство поведений Behaviors в Yii2
Спасибо участникам! Было круто! Провели очередной вебинар по мотивам статьи о поведениях. В перерыве поговорили о жизни, о программировании, о блогах:
А какая тема дальше? Поразмышлял и об этом в эфире. В любом случае сразу вам сообщу в рассылке по вебинарам. Запишитесь, если ещё не с нами:
P.S. Если вдруг назрели интересные темы для следующих вебинаров, то можете предложить их в комментариях здесь или в первой статье. Спасибо за внимание!
Здравствуйте. Жаль, что перестали публиковать статьи в текстовом виде. Не всегда удобно просматривать видео. А так пробежал по тексту, и что-нибудь для себя взял.
Уже думал о выкладывании расшифровки. Попробую сделать.
Присоединяюсь к комменту выше. Я часто летаю и нет возможности везде смотреть видео, а текст очень бы хотелось читать.
Здравствуйте, сделайте пожалуйста на сайте текстовые версии примеров скриптов используемых в вебинарах.
Да, сделаю.
Дмитрий, спасибо за вебинар!
Было бы очень хорошо, если бы к записи вебинара (этого и других) приложить файл презентации (ссылку на презентацию). Мне кажется это оптимальное решение.
Здравствуйте, Дмитрий. По тестированию что-нибудь планируется? Интересует неразбериха вокруг юнит тестов. Кто-то разделяет их собственно на юнит и интеграционные тесты, а кто-то не разделяет. К примеру здесь тестируется метод LoginForm::login(), а также неявно вызывается и соответственно тестируется LoginForm::getUser() и User::findByUsername($login). Я пытался спросить на тостере и некоторые стали писать, что это не юнит-тест из-за того, что он неявно тестирует другие методы, что в тесте нужно было мокать LoginForm::getUser(). Но лично я не увидел в этом целесообразности, так как в таком случае нельзя проверить, действительно ли получается залогиниться с верными данными. Смысла в таком тесте будет мало (или даже вовсе не будет) и всё равно нужно будет писать так называемый "интеграционный тест" на этот метод.
Я же хотел выяснить грань, когда при тестировании одного метода допускается неявное тестирование другиих методов, а когда это категорически не следует делать. И есть ли вообще эта грань. Но к сожалению, так и не смог найти ответ.
Дмитрий, а есть архив с вебинарами, чтобы скачать и смотреть оффлайн в дороге?
Можете попробовать загрузить с YouTube.
Спасибо за хороший урок по Поведениям, очень хорошо и подробно все рассказали!
Дмитрий, пожалуйста, посоветуй готовое поведение для загрузки множества изображений.
Обычно для множества я завожу отдельную таблицу с моделью PostImage и навешиваю обычное одинарное поведение уже на неё.
Понял, спасибо!
Здравствуйте, Дмитрий. Как поступить с вынесением метода beforeValidate() в поведение? Проблема возникает в том, что метод возвращает false, а валидация всё-равно проходит успешно. Но если выносить код в саму модель в beforeValidate() то все поля проходят/не проходят валидацию. Вот код самого поведения.
В методах beforeValidate, beforeSave и прочих before* используется экземпляр ModelEvent с дополнительным полем isValid, значение которого в итоге возвращается из соответствующих методов.
Следовательно, для прерываения действия в обработчике события нужно установить isValid в false при ошибке:
А касательно реализации поведения - непосредственная работа в самой модели или в её поведении с $request->post() сильно связывает код.
Спасибо! По поводу последнего замечания, так буде правильнее или есть еще какие либо варианты:
Нет, Вы просто перенесли это из поведения обратно в модель. В итоге без POST-запроса значение request->post() будет пустым, что сломает валидацию и сохранение.
Логичнее помимо геттера getMetaTags добавить сеттер setMetaTags, принимающий массив из формы, и действия по загрузке производить уже в нём.
Дмитрий, добрый день!
Вопрос не совсем про поведения, но связан с вебинаром про них :)
Для закрепления материала решил написать поведение, которое рассматривалось в качестве примера на уроке - загрузка файлов. Почему-то у меня в приложении Yii::getAlias('@web') выдает пустую строку. Что-то пропущено в конфигурации?
Ничего не пропущено. Это путь от корня сайта. Если у Вас сайт открывается не из поддиректории, то этот путь пустой.
Дмитрий, большое спасибо за быстрые ответы и здесь и на yiiframework форуме
Дмитрий,
теперь вопрос чисто по поведениям. Допустим, я в поведении объявляю некий статический метод
public static method1...
Это поведение присоединяю к модели AR model1.
Вопрос. Должен ли этот статичский метод быть доступен извне по model1::method1? Что-то у меня ругается, что метод недоступен... Хотя, по идее, методы поведения должны быть доступны его owner'у. Или есть особенности для статических методов?
Для статических методов вместо __call используется магический метод __callStatic. Он в Yii2 не реализован. Но если бы это было, то по логике класс модели не смог бы ничего узнать о подключенных к нему поведениях. И наоборот, статический метод поведения ничего бы не знал о классе модели. Так что смысла использования статических методов в поведениях нет никакого.
Дмитрий, а можно поподробнее об этом:
" Но если бы это было, то по логике класс модели не смог бы ничего узнать о подключенных к нему поведениях. И наоборот, статический метод поведения ничего бы не знал о классе модели."
Что-то не уловил смылса... Почему класс модели ничего бы не узнал о поведениях?
Взаимообратные задачи:
Со статическими методами нужно делать то же самое:
Ну если пойти на хитрость и из __callStatic вызывать self::behaviors() статически, брать оттуда имена классов поведений и искать у них статический метод, то первое реализовать можно.
Но обратно из статического метода поведения явно узнать класс вызывающей его модели будет невозможно (если не передавать имя класса ещё одним параметром в сам метод или не парсить стек вызовов).
А вообще с практической точки зрения вызывать статические методы из поведения смысла не вижу. Они же ненастраиваемые и к модели никак не привязаны. Не проще ли их вызывать напрямую или, в крайнем случае, подключать через трейты?
Кажется, начинаю понимать, спасибо.
Вопрос на самом деле встал вот из-за чего. в вашем примере поведения для загрузки файлов есть метод getDir. Я подумал, что его было бы логично сделать статическим, поскольку он не привязан к экземпляру, будет одинаковым для всех экземпляров этого класса.
Привет, когда следующий вебинар? Куда пропал? :-)
Работу работаю :) Надо бы провести на днях...
Понятно. Если много времени приходится готовиться к вебинарам, может быть можно было бы сделать что-нибудь в формате подкаст-вебкаст? Например, обсуждать какую-нибудь проблему или например, расширение или паттерн какой или что что-то интересное узнал или best practices на примерах. Я думаю многим было бы интересно!
То есть выбрать какую-то менее глобальную тему, чем тестирование или разбить тестирование на части или вообще по-говорить например, как разбивать приложение на модули или еще чего.
Здравствуйте Дмитрий
Помогите настроить на сайте оплату товаров через WebMoney в автоматизированном режиме
начиная с выбора товара.
Я не программист но готовые коды куда нужно вставлю, просто нет нигде конкретной пошаговой информации для чайников, с подробными инструкциями.
Спасибо
Ваш подписчик
Здравствуйте. Скажите, а нельзя ли из поведения добавить правила валидации в основную модель?
Пробовал сделать через $this->owner->validators[] = [...] в методе init() поведения, но ничего не вышло.
Добрый день!
Прошу пояснить - в чем преимущество использования TimestampBehavior перед реализацией данного функционала на стороне базы данных при помощи триггеров и значений полей по умолчанию?
CURRENT_TIMESTAMP можно установить только у одного поля в таблице, так что одновременно для created_at и updated_at это сделать не получится.
Это можно реализовать средствами БД при помощи триггера.
Получается, что преимущество в удобстве - просто, вся логика в приложении, повторное использование кода. Да и когда много подобных таблиц придется соответственно много триггеров создавать.
Ответ на вопрос также прояснили исходники. В шаблоне yii2-app-advanced в миграции для создания таблицы user поля created_at и updated_at имеют тип integer и в них сохраняется значение, возвращаемое PHP функцией time(). Видим, что при помощи TimestampBehavior реализован нестандартный (в отличие от типов полей - DATETIME, TIMESTAMP) способ хранения даты/времени в базе.
Да, так как результаты DATETIME и TIMESTAMP неудобно конвертировать в текущую временную зону.
Использую OmgDef/yii2-multilingual-behavior
Все отлично работало до появления в моделе метода afterFind
Скажите, это криво написанное behavior или нельзя использовать метод afterFind если он используется в behavior?
Не забывайте дёргать parent::afterFind
При добавление поста мне надо записать и айди юзера и его имя. как мне лучше использовать?
Я сделал так, но не уверен что это правильно или оптимально
А есть ли смысл в дополнительном поле username, если уже есть поле user_id, с которого можно выводить имя по связи $post->user->username?
Не мешало бы к каждому видео писать полноценную статью, тогда как конспект к лекционному материалу получится.