Вышла новая версия PHP-фреймворка Yii, включающая в себя более 80 улучшений и исправлений. Инструкции по установке и обновлению можно найти по адресу. Стоит отметить, что в релиз вошли четыре небольших изменения, которые могут повлиять на работу существующих приложений. Обязательно прочитайте UPGRADE.md.
Спасибо замечательному сообществу за отличные пулл-реквесты и обсуждения. Без вас этого релиза не было бы! За процессом разработки Yii 2 можно начать следить, поставив звёздочку на GitHub. Подписывайтесь на наш Twitter и Facebook. Обсудить релиз можно в комментариях.
Полный список изменений можно найти в CHANGELOG. Далее мы рассмотрим наиболее интересные.
URL
Новый класс yii\web\UrlNormalizer
позволяет нормализовать запросы на URI с присутствующим или отсутствующим слешем в конце, что довольно важно для поисковой оптимизации. Подробное описание можно найти в разделе «URL normalization» официального руководства.
Миграции
Помимо небольших исправлений миграции получили и довольно значительное улучшение. Теперь можно запускать миграции из нескольких мест одновременно, если использовать для них пространства имён. Чтобы это сделать, необходимо настроить свойство migrationNamespaces
консольного контроллера:
return [
'controllerMap' => [
'migrate' => [
'class' => 'yii\console\controllers\MigrateController',
'migrationNamespaces' => [
'app\migrations',
'some\extension\migrations',
],
//'migrationPath' => null, //можно отключить миграции без пространств имён
],
],
];
Обработка ошибок
Ошибки при записи и чтении сессии теперь не скрываются в отладочном режиме, что позволяет легко выявить большинство проблем на этапе разработки.
Request
Появился новый метод yii\web\Request::getHostName()
, возвращающий имя хоста для текущего запроса.
Не POST запросы, кодированные как multipart/form-data
(например, загрузка файлов) теперь можно распарсить через yii\web\MultipartFormDataParser
. Для того, чтобы этим воспользоваться, вы должны настроить Request::parsers
следующим образом:
return [
'components' => [
'request' => [
'parsers' => [
'multipart/form-data' => 'yii\web\MultipartFormDataParser'
],
],
// ...
],
// ...
];
После этого следует вызвать Request::getBodyParams()
и запрос будет разобран в соответствующие переменные. В том числе в $_FILES
.
Базы данных
Было добавлено новое поведение для ActiveRecord. yii\behaviors\AttributeTypecastBehavior
позволяет автоматически приводить типы значений атрибутов.
Типы задаются через attributeTypes
:
use yii\behaviors\AttributeTypecastBehavior;
class Item extends \yii\db\ActiveRecord
{
public function behaviors()
{
return [
'typecast' => [
'class' => AttributeTypecastBehavior::className(),
'attributeTypes' => [
'amount' => AttributeTypecastBehavior::TYPE_INTEGER,
'price' => AttributeTypecastBehavior::TYPE_FLOAT,
'is_active' => AttributeTypecastBehavior::TYPE_BOOLEAN,
],
'typecastAfterValidate' => true,
'typecastBeforeSave' => false,
'typecastAfterFind' => false,
],
];
}
// ...
}
Если attributeTypes
не задан, значение будет определяться автоматически на основе правил валидации:
use yii\behaviors\AttributeTypecastBehavior;
class Item extends \yii\db\ActiveRecord
{
public function rules()
{
return [
['amount', 'integer'],
['price', 'number'],
['is_active', 'boolean'],
];
}
public function behaviors()
{
return [
'typecast' => [
'class' => AttributeTypecastBehavior::className(),
'owner' => $this,
// 'attributeTypes' будет задан автоматически на основе `rules()`
],
];
}
// ...
}
Также был добавлен yii\mutex\OracleMutex
— реализация блокировки возможностями Oracle.
Консоль
В консоли теперь можно вызвать описание команды передав -h
или --help
.
Тестирование
Шаблоны приложений были изменены, чтобы работать с недавними изменениями в Codeception. Подробнее об этом можно прочитать в новом разделе на сайте Codeception: «Yii 2.0 quickstart guide». Если вы используете шаблон проекта advanced, ознакомьтесь с его документацией по тестированию.
Комментарии (40)
samizdam
20.10.2016 17:45Почему бы не использовать semver?
SamDark
20.10.2016 17:53Мы его используем. Полная версия — 2.0.10.0. Просто чистые патч-релизы получаются не часто. В основном, когда крупно налажали и латаем на ходу (пока такое было, кажется, один раз за всё существование Yii).
samizdam
20.10.2016 18:01Но по соглашению сем.вер. добавление фунциональности это минорное обновление. У вас же появляются новые классы, методы, а выпускается как будто патч.
Big
20.10.2016 18:18+1Они используют такое соглашение по наименованию версий — 2.MAJOR.MINOR.PATCH (сейчас сменился MINOR с 9 на 10)
Mendel
22.10.2016 13:50+1Ну да, правильно писать что-то вроде yii2 версия 0.10.0 а не yii версия 2.0.10.0 но композер так тоже понимает, так что чего уж нарушать исторически сложившийся шаблон.
ПС: да, для нуля особые правила, я помню.
naquad
20.10.2016 18:21Круто! Очень радует, что фреймворк живее всех живых :)
Хотелось бы ещё узнать как по поводу зависимостей от клиентских библиотек? Когдато на Хабре проскакивала статья, о том, что есть планы их убрать подальше. Это в планах осталось или от этого отказались?
nepster09
21.10.2016 10:00+1Я давненько по рабочей необходимости перебрался на laravel5, однако продолжаю следить, как там у Yii2 дела продвигаются, так вот возможно я что-то пропустил или не знаю, но есть следующий список фитч, которых нет в (или я об этом не знаю):
Seeds: — возможность наполнения базы данных тестовыми данными. В Yiii2 такое можно делать в миграциях, однако в laravel5 это сделанно в виде отдельной команды, что дает возможность получить как голую схему базы данных, так и заполнить ее тестовыми данными.
Composers: — весьма интересная штука, которая позволяет внедрять данные в одну и/или более вьюшек. Что-то похожее на виджеты, такой себе класс, который может содержать логику и передать некоторые данные в вид. Что бывает удобно, например когда нужно передать одни и те-же данные в несколько страниц.
Middleware: — во круг этого крутилось множество обсуждений, но я упустил конкретный ответ. Все останется по прежнему, тоесть поведения (фильтры и тп.) или все-же Middleware будут жить в Yii2?
(хеш тег: Yii2, give a chance to Middleware)
Requests: — спорная штука, но иногда удобно. Во первых вынос валидации из модели в отдельный спец. класс, а во вторых можно сделать так, что пока валидация не пройдет, мы даже до экшина не дойдем.
И так-же присоединяюсь к тому, что нужно разбить Yii2 на отдельные компоненты. Что мне нравится в этом инструменте, что почти о любом наркоманстве, о котором я могу подумать, оно уже есть. Я имею ввиду хелперы или вспомогательные методы (например сравнение 2 объектов активрекорд https://github.com/yiisoft/yii2/issues/9036, equals вместо === и много еще чего интересного в хорошем смысле).
Однако по факту есть разные области применения Yii2 и не всегда это просто сайт. что делает более 50% функционала просто не нужными в зависимости от определенных ситуаций.
В общем было бы здорово получить комментарии от разработчиков по теме.wispoz
21.10.2016 10:27+2Аналог Seeds — это Fixtures
http://www.yiiframework.com/doc-2.0/guide-test-fixtures.html
SamDark
21.10.2016 11:39+1Seeds — fixtures.
Composers — может быть удобно в отдельных случаях, но вообще штука спорная. Таскает данные довольно неявно. Легко просадить производительность, легко перекрыть локальной переменной, не сильно приятно дебажить, когда не ясно сходу, откуда прилетела переменная.
Middleware — не в 2.1, но мы не перестаём обдумывать, нужно ли оно и в каком виде. По сути у нас уже примерно то же, только не по PSR. Используется извне, например, Codeception.
Про Requests не понял, про что именно речь. Можно ссылку?
И так-же присоединяюсь к тому, что нужно разбить Yii2 на отдельные компоненты.
Да, потихоньку делаем. С каждой версией что-то будет уезжать из ядра.
Однако по факту есть разные области применения Yii2 и не всегда это просто сайт. что делает более 50% функционала просто не нужными в зависимости от определенных ситуаций.
Факт. Хотя даже у REST API исключительно под телефоны есть лендинг...
nepster09
21.10.2016 14:55Seeds — fixtures. Да, я когда-то сталкивался, но поработать не довелось. Засовывал данные в миграции.
Согласен с Composers, но можно придерживаться неких правил именования например: $composerMyVar.
Тоесть все переменные, которые начинаются с composer будут приходить именно от туда, очевидно, понятно и сложнее перетереть.
https://laravel.com/docs/5.3/requests
По сути в 2 словах, я могу гарантировать, что в контроллере будут уже валидные данные. Вот кстате не большой пример https://mattstauffer.co/blog/laravel-5.0-form-requests.
«Факт. Хотя даже у REST API исключительно под телефоны есть лендинг...», он может быть сделан на другой платформе или с помощью angular2 и тп.SamDark
21.10.2016 15:01Согласен с Composers, но можно придерживаться неких правил именования например: $composerMyVar.
Тоесть все переменные, которые начинаются с composer будут приходить именно от туда, очевидно, понятно и сложнее перетереть.Не знаю… костыльно как-то.
https://laravel.com/docs/5.3/requests
По сути это form model.
nepster09
21.10.2016 16:02Да, но тут удобно еще. что Laravel5 сам все инжектит и проделывает. Плюс я после Yii2 достаточно быстро привык к тому, что в Laravel5 все разбили очень жестко. Это весьма удобно, в Yii2 вы как-то все соединили очень жестко. Тоесть то, что по факту можно расписать в 5 классов, влазит в одну модель.
Mendel
22.10.2016 14:23+1А зачем разделять?
У любого правила цель одна — повысить эффективность.
Вот многие ругают Yii за то, что валидация в модели. мол не SOLID-но.
Но ТАК УДОБНЕЕ. Я когда начал писать свой фреймворк, то пошел по пути Юии.
Потом углубился в этом подходе еще больше. У меня правила это не только валидация а просто правило работы с полем. У него есть и свой аналог авфтерЛоад и бефорСаве (привязанные к конкретному полю), и валидация и другие обработчики. Выходит если я указал полю правило int то я этим сказал что оно при загрузке из базы приводится к целому, при валидации — приводится и валидируется. Повесил на него defaultValue и при чтении значения из поля — NULL меняется на значение, но оно не попадает в базу, а остается NULL, а указав defaultSaveValue наоборот — при сохранении оно сохранится. Так удобно. Да, более «кошерно» было бы сделать например так как сделали тут — отдельным поведением. Но зачем? В тех 5% случаев где стандартного поведения не хватит можно будет просто создать свое правило, благо они простые и копипаст никто не отменял.
В особо сложных случаях можно и методы в модели соответствующие переопределить.
Потом я пошел еще дальше. Я вынес связи в правила. Ведь и поле и связь это виртуальное свойство объекта. Зачем? Ну тут больше упрощение кода из соображений солидности чем удобство работы, но удобство не страдает, и можно всегда довесить на это виртуальное поле другие правила, или даже заменить его без изменения прочего кода, что дает большую гибкость.
следующая итерация у меня была еще более спорная. К ней и веду:
Значительная часть контроллеров представляли из себя CRUD в админке.
У меня есть базовый контроллер у которого есть виджет выводящий форму, которая активформ, но разбитая сразу на закладки. Когда у объекта полсотни полей, то всегда удобно вынести их по разным закладкам. Естественно чтобы не перечислять поля по закладкам это выносится в настройки. Держать эти настройки во вьюве неудобно. Мы плодим лишние шаблоны. Которые не отличаются.
По факту место настройкам разделяющим поля по группам — в контроллере.
Так и сделал.
Но в процессе реальной разработки часто бывает поля появляются и исчезают.
При таких изменениях нужно отразить изменение в конфиге модели, в конфиге контроллера и в языковом файле. Лезть в три файла муторно. Проще в два, ибо от языка особо не избавишься, тут ломается функционал. Поэтому настройки разделения полей модели на группы я унес в настройки модели. Это может и не так кошерно, но это практично и экономит время разработки, уменьшает колво ошибок и все такое.
Не призываю к тому чтобы идти моим путем. Я лишь защищаю рациональность того чтобы валидация была в модели. Так удобнее.nepster09
22.10.2016 14:45+1а Вы понимаете, что такое модель?
Mendel
22.10.2016 15:24+1В данном контексте речь идет про AR. Но смешивание этих понятий не так уж и важно.
Модель отображает нечто из предметного мира в програмном окружении. Данные, объект и т.п.
Я понимаю что сферическая модель может быть вообще без атрибутов и явно не влазить в паттерн активРекорд, но на практике важнее удобство в 90% случаях, которое не лишает возможности пусть и менее удобно решить оставшиеся 10% задач.
А так то Ваш вопрос уж очень общий.
В стиле Ларавел.) Не согласны — скажите в чем. Увидели ошибку, пусть даже терминологическую — скажите где. А так то звучит стремновато. Раскройте мысль, будьте добры.nepster09
22.10.2016 15:42+1Речь скорее о подходах как laravel5, так и Yii2, в этих инструментах сидит ActiveRecord, за несколько лет работы с ним, у меня почему-то начинает вырабатываться дикая аллергия на него. Так-как по большей части в сообществах принято считать, что модель == 1 файл (а точнее класс унаследованный от ActiveRecord).
Но если чуть-чуть покапать, поделать проекты с более сложной логикой и с весьма длительной поддержкой, то ActiveRecord породит достаточно много проблем.
Я прошел и до сих пор прохожу через множество адских штук, которые были рождены именно благодаря ActiveRecord. Это скорее претензия не к вам конкретно, а наверно для множество новичков или людей, которые порождают божественные классы, дублируют логику, суют ее во вьюшки и еще очень много интересных вещей делают.
Я не могу сказать, что я стал хорошо разбираться в этом всем деле, так как еще до сих пор обжигаюсь, но то, что мне достается из легаси кода на инструментах с использованием ActiveRecord оставляет желать лучшего.
Вообще изначально под моделью подразумевается бизнес логика по хорошему состоящая из множество различных классов, что улучшает читабельность кода, поддержку и в целом благоприятно влияет на проект. Хорошим примером будет domain model, при чем не обязательно в контексте DDD.
Я так-же согласен, что ActiveRecord это дико удобная штука, с ее помощью можно весьма быстро и удобно работать, очень просто делать реляции, различные связи и сократить код. Однако это удобство несет в себе весьма скрытую опасность, и если вам нужна длительная поддержка, жирная бизнес-логика, удобство и гибкость, то с ActiveRecord будет весьма сложно и сложнота будет стремиться к невозможному.
И самый больный пример из своего опыта, который я могу примести это примерно следующая ситуация:
Представьте, что вы работаете в небольшой конторе по разработке WEB-проектов различной сложности. Штат предположим из 5 бэкендеров в вашем подчинении. 3 из них джуны, 1 что-то похожий на мидла и вы тоже мидл, такой себе среднячковый (это я возможно о себе). Вы распределяете работу, пишите задачи, сроки горят, туда сюда, быстрее и вот потом когда вы смотрите на код работающего проекта, то все правки и доработки туда вносятся начиная с комментария «Отче наш, сущий на небесах ...».
Конечно это не проблема Yii2 или Laravel5, или вообще AR. Но сложилось как сложилось и глубокая связанность, а особенно размазанная логика весьма сложно исправляется.
В доменной же моделе, когда все разбито на отдельные части, при готовой архитектуре, которую можно навязать тем-же джунам, будет все более менее терпимо, а при желании можно подменить через тот-же DI.
Честно говоря у меня много наболело по этому поводу. Поэтому я наверно извинюсь, за излишки.Mendel
22.10.2016 15:52+1Вы под Опенкартом поработайте. Сразу начнете любить ваших легаси-писателей как хороших кодеров)
Вообще юии это такой «вордпресс для умных». В нем такого творят, что страшно.
Но как правило 90% проекта это много разных вариаций на тему CRUD, с десяток взаимных связей и пляски по борьбе с собственным непониманием АПИ.
Можешь сделать быстро — сделай быстро. RAD наше всё). Да, желательно соблюдать структуру и документирование и т.п., но без фанатизма. Нарушения стандартов самим Yii это малая толика зла дающая нам бонусы. Истинный ад живет в нарушениях стандартов теми кто пользуется фреймворком.
zelenin
22.10.2016 15:34Но ТАК УДОБНЕЕ.
удобнее, не значит лучше.
и опять же стандартная аргументация: yii — rad-фреймворк, поэтому для задач, которые он решает, быстрее и удобнее — аргумент. Для крупных приложений, которые на rad-фреймворках обычно не пишутся, встроенная в модель валидация (а так же общее неследование SOLID) не прокатит.Mendel
22.10.2016 15:44+1В том то и дело, что для своей ниши оно эффективно. Всё.
Это сродни критике всего явления ORM. Мол там такие планы запросов вырастают, что уж проще делать запросы руками. Ну так и делайте. Но только там где это нужно.
Пишешь на ORM, потом в уже живом окружении, уже покрытое тестами и т.п. дописываешь узкие места прямыми запросами. В процессе уточнив ТЗ, проверив все взаимодействия компонент и т.п.
У юии в принципе AR тяжелые. Разделяй не разделяй, а в сложных задачах все равно выкидывать всю подсистему и писать свое. Или переписать 0.1% кода, поднажать на кеширование и доплатить лишние 20 баксов в месяц на более мощный сервер и не морочить себе голову.
ablai
21.10.2016 11:26Ребята, не много не по теме, подскажите как можно установить все расширения с «minimum-stability»: «stable» и сделать исключение для несколько других расширений.
Ситуация такая. Нужно установить kartik-v/yii2-export «dev-master», необходим функциональность с dev версий. Но при установке «minimum-stability»: «dev» все другие пакеты переходят тоже на dev игнорируя версий указанные в composer.json. Как быть?SamDark
21.10.2016 11:40В идеале — упросить Kartik-а тэгнуть релиз. Но должно работать, если пакету приписать
@dev
к версии.zelenin
21.10.2016 17:37+1или лучше номер коммита, чтобы все-таки зафиксировать версию —
dev-master#c64571f892bda1298bad9c5e94ede0bc3f0e4627
ablai
22.10.2016 15:18можно подробнее
zelenin
22.10.2016 15:35+1указать версию пакета в таком стиле в composer.json. Тем самым мы зафиксируем пакет на конкретном коммите, если стабильный релиз нам не подходит или пакет не миеет стабильного тега.
BoShurik
22.10.2016 20:09composer.json все равно будет считываться из указанной ветки, а не из коммита, так что это не всегда выход
https://getcomposer.org/doc/04-schema.md#package-links
Note: While this is convenient at times, it should not be how you use packages in the long term because it comes with a technical limitation. The composer.json metadata will still be read from the branch name you specify before the hash. Because of that in some cases it will not be a practical workaround, and you should always try to switch to tagged releases as soon as you can.
Может помочь объявление своего пакета:
http://stackoverflow.com/questions/34784809/how-to-use-a-specific-tag-version-with-composer-and-a-private-git-repository
"repositories": [ # ... { "type": "package", "package": { "name": "vendor/package", "version": "v0.5.0", "source": { "url": "git@gitlab.server.com:vendor/project.git", "type": "git", "reference": "dd6ed3c8" } } } ]
zelenin
22.10.2016 23:11+1composer.json все равно будет считываться из указанной ветки, а не из коммита
непонятно, что там с чем что. dev-master#123abc установит коммит с хэшом 123abc из ветки dev-master. Что не так по вашему?BoShurik
23.10.2016 00:07Если в HEAD в composer.json будут зависимости, к примеру
{ "require": { "symfony/console": "3.0" } }
А в dev-master#123abc
{ "require": { "symfony/console": "~2.7" } }
То composer будет считать, что надо установить "symfony/console": "3.0" в качестве зависимости, хотя сам пакет будет установлен из указанного коммита. Это происходит потому. что пакет скачивается уже после того, как разрешены зависимости.
zelenin
23.10.2016 00:10я не понимаю о чем вы. мы тут про указание зависимости в СВОЕМ проекте? если будет указан dev-master#123abc, то он и установится.
BoShurik
23.10.2016 13:24+1Он устанвится, но его зависимости будут отрезолвены неверно.
В документации же все понятно:
The composer.json metadata will still be read from the branch name you specify before the hash.
Т.е. если указать
"kartik-v/yii2-export": "dev-master#47fd3e870a1b7c8dcfe572b8290b6c61011a6aa7"
То версия composer.json будет использована из мастера вместо https://github.com/kartik-v/yii2-export/blob/47fd3e870a1b7c8dcfe572b8290b6c61011a6aa7/composer.json, и если они отличаются, то будут проблемы
zelenin
23.10.2016 14:40+1да, теперь понял проблему. Хотя формулировка очень размытая. Указанный коммит тоже находится в ветке перед хэшом, и логично что и содержимое composer.json тоже находится в этой ветке. Только речь не о ветке, а о текущем/последнем коммите указанной ветки.
Т.е. указав версию в нотации dev-master#47fd3e870a1b7c8dcfe572b8290b6c61011a6aa7, мы разресолвим зависимости не из composer.json коммита 47fd3e870a1b7c8dcfe572b8290b6c61011a6aa7 ветки master, а из composer.json последнего коммита ветки master.
PS. Да, это проблема.
nurik_6
21.10.2016 17:59По поводу пункта «Requests» — скорее всего вы пропустили этот момент, при чтении документации, ведь тоже самое можно сделать и в Yii2. У меня в одном из проектов как раз и реализована аутентификация прежде, чем actions выполнятся.
Просто в контроллере добавляем поведение с необходимым способом аутентификации, при этом заранее описываем класс аутентификации наследованным от AuthMethod. При этом можно объединять сразу 2 вида аутентификации для использования в одном контроллере.
Вот чего действительно не хватает, так это Middleware, из-за этого иногда приходится приделывать велосипеды.
mhthnz
За поведение спасибо) а то постоянно в changedAttributes ерунду получал.