Pull to refresh

Yii 2.0 beta

Reading time 12 min
Views 42K
Нам очень приятно сообщить о выходе бета-версии PHP фреймворка Yii 2. Вы можете загрузить его с yiiframework.com.

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



Часто задаваемые вопросы



  • Что значит бета? Бета означает стабильные набор возможностей и архитектуру. Начиная с беты и до GA (General Availability, стабильного релиза), мы будем заниматься, в основном, исправлением ошибок и документацией. Мы не собираемся изменять архитектуру фреймворка или добавлять какие-либо новые возможности. Стоит отметить, что поломки обратной совместимости всё ещё могут случаться, но мы попытаемся делать их как можно меньше, а сделанные детально описывать.
  • Когда будет стабильный релиз? Пока что мы не можем назвать точную дату. Так как следующий этап заключается, главным образом, в исправлении ошибок и доработке документации, мы думаем, что сильно много времени это не займёт.
  • Могу ли я использовать бету в моих проектах? Не стоит использовать бету в проектах с сжатыми сроками или если вы ещё не знакомы с Yii 2.0. Если это не про вас и вас не пугают изменения в фреймворке, можете попробовать. Мы слышали, что довольно много проектов уже запущены и работают на ветке `master`. Также помните, что минимальная версия PHP для работы фреймворка — 5.4.
  • Есть ли документация по 2.0? Да, есть The Definitive Guide и API documentation. Гайд постоянно дополняется. Перевод на русский будет как только оригинал будет более-менее завершён.
  • Как мне обновить приложения с 1.1 на 2.0? На эту тему написан отдельный раздел
    Upgrading from Yii 1.1. Стоит отметить, что так как 2.0 переписан полностью, обновление не будет тривиальной задачей. Тем не менее, если вы работали с 1.1, вам будет намного проще потому как между 1.1 и 2.0 много общего.
  • Как обновиться с альфы 2.0? Если вы обновляете альфу через Composer, стоит удалить всё, кроме .gitignore из директории vendor и запустить composer ещё раз. Сделать это необходимо лишь один раз и вам не придётся так поступать с каждым новым релизом. Полный список изменений, в том числе и ломающих обратную совместимость, доступен в файле CHANGELOG.
  • Как следить за разработкой 2.0? Вся разработка и обсуждения происходят на GitHub:
    https://github.com/yiisoft/yii2. Вы можете подписаться на обновления или поставить звёздочку чтобы получать уведомления об обновлениях. Также можно следить за нашим twitter https://twitter.com/yiiframework.


Большие изменения с альфа-версии



Полный список изменений вы можете найти в CHANGELOG, а ниже мы опишем самое важное.

Структура


Yii 2 начал использовать PSR-4
для загрузки классов. То есть:

  • Структура директорий фреймворка стала проще.
  • Структура директорий расширений стала проще.
  • Фреймворк больше не загружает классы, именованные в стиле PEAR. Загрузка классов от этого упростилась и стала быстрее.


Классы контроллеров теперь обязательно должны находится в пространстве имён, указанном в Module::controllerNamespace, если конечно вы не используете Module::controllerMap.

Также мы вернули поддержку группировки контроллеров в субдиректории, которая была в 1.1.

Удобство использования


Удобство использования — один из наивысших приоритетов нашей команды. Именно поэтому мы уделяем много внимания именованию и тому, чтобы код нормально работал с различными IDE. Всё это позволяет сделать повседневную разработку более приятной.

Мы перешли на стили кода PSR-1 и PSR-2 и получили поддержку многих IDE, автоматизированной проверки кода и
автоматического форматирования.

Производительность


Одно из самых значительных изменений состоит в том, что сессия не стартует до тех пор, пока она действительно не понадобится. Это позволяет приложениям не тратить лишние ресурсы.

Если в своих проектах вы используете Markdown, вы заметите, что скорость преобразования в HTML существенно возросла. Это стало возможным после того, как Carsten Brandt (cebe), после рассмотрения существующих решений, написал с нуля свою библиотеку для этих целей. Кроме производительности, она лучше расширяется и поддерживает вариант markdown, используемый GitHub.

Безопасность


Теперь Yii использует *маскированые* CSRF-токены для предотвращения атак типа BREACH.

RBAC был переписан, вследствие чего стал проще. Бизнес-правила теперь оформляются в виде классов без всякого eval.

RESTful API framework


Долгожданная возможность, появившаяся в бете — встроенный фреймворк для создания REST API. В данном обзоре мы не будем описывать его в деталях, а лишь перечислим основные особенности. Полное описание доступно в The Definitive Guide.

  • Быстрое прототипирование частых операций через ActiveRecord;
  • Response format negotiation (по умолчанию поддерживается JSON и XML);
  • Настраиваемая сериализация объектов. Можно выбрать сериализуемые поля.
  • Правильное форматирование коллекций данных и ошибок валидации;
  • Эффективный роутинг с полной поддержкой HTTP;
  • Поддержка OPTIONS и HEAD;
  • Аутентификация;
  • Авторизация;
  • Поддержка HATEOAS;
  • HTTP-кеширование;
  • Ограничение количества запросов.


Dependency Injection и Service Locator


Многие спрашивали, почему в Yii нет контейнера Dependency Injection (DI). На самом деле Yii всегда предоставлял похожую функциональность в виде Service Locator — экземпляра приложения Yii. Теперь мы выделили service locator в отдельный компонент yii\di\ServiceLocator. Как и раньше, и приложение и модули являются service locator-ами. Вы можете получить сервис (в 1.1 он назвался компонент приложения) используя Yii::$app->get('something').

Кроме Service Locator, мы также реализовали DI контейнер yii\di\Container. Он помогает создавать менее связанный код. По предварительным данным, наш контейнер является одним из самых быстрых контейнеров DI на PHP. Вы можете использовать Yii::$container->set() для задания начальных значений классов. Старый метод Yii::$objectConfig удалён.

Тестирование


Yii был интегрирован с Codeception. Это позволяет тестировать приложение в целом путём эмуляции действий пользователя и проверки правильности генерируемых ответов. В отличие от поддержки selenium в PHPUnit, Codeception не требует браузера, его проще поставить на CI-сервер и отрабатывает он гораздо быстрее.

В Yii также добавлена поддержка фикстур, решающая проблему инициализации тестовых данных — одной из самых долгих и рутинных задач при написании тестов. Поддержка фикстур покрывает как их создание, так и применение. Также было реализовано расширение faker, которое помогает создавать близкие к реальным наборы данных.

Оба шаблона приложений, как «basic», так и «advanced», поставляются вместе с тестами: модульными, функциональными и приёмочными. Надеемся, это будет хорошим стимулом применять разработку через тестирование.

Валидация моделей


В валидации моделей произошло довольно много интересных улучшений.

Валидаторы UniqueValidator и ExistValidator теперь поддерживают проверку нескольких столбцов. Ниже приведены несколько примеров для unique:

// a1 должен быть уникальным
['a1', 'unique']

// a1 должен быть уникален, но сравнивать будем с a2
['a1', 'unique', 'targetAttribute' => 'a2']

// a1 и a2 вместе должны быть уникальны и оба поля получат сообщения об ошибке
[['a1', 'a2'], 'unique', 'targetAttribute' => ['a1', 'a2']]

// a1 и a2 вместе должны быть уникальны, но только a1 получит сообщение об ошибке
['a1', 'unique', 'targetAttribute' => ['a1', 'a2']]

// a1 должен быть уникален при сравнении его значения как с a2, так и с a3
['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']]


Валидацию можно производить по условиям, которые задаются через свойства when и whenClient. Далее показан пример обязательности поля «state» только в том случае, если выбранная страна «USA»:

['state', 'required',
    'when' => function ($model) {
        return $model->country == Country::USA;
    },
    'whenClient' =>  "function (attribute, value) {
        return $('#country').value == 'USA';
    }",
]


Иногда требуется проверить данные, не привязанные к модели. Это можно сделать используя новый класс yii\base\DynamicModel:

public function actionSearch($name, $email)
{
    $model = DynamicModel::validateData(compact('name', 'email'), [
        [['name', 'email'], 'string', 'max' => 128],
        ['email', 'email'],
    ]);
    if ($model->hasErrors()) {
        // неудачная валидация
    } else {
        // всё хорошо
    }
}



База данных и Active Record


Всё связанное с базами данных — сильная сторона Yii. Набор возможностей был уже довольно интересен в альфа-версии, а бета принесла улучшения и новые возможности. В числе реализаций Active Record есть elasticsearch, redis и Sphinx search. А в бете появилась поддержка mongodb.

Поддержка вложенных транзакций


Yii теперь поддерживает вложенные транзакции. Вы можете начать транзакцию не беспокоясь о том, начата ли внешняя по отношению к данной транзакции.

Join


Мы добавили ActiveQuery::joinWith() для поддержки создания SQL-запросов с JOIN использую уже объявленные связи AR. Это особенно полезно, если вы хотите отфильтровать или отсортировать данные по полям из связанных таблиц. К примеру:

// найдёт все заказы и отсортирует их по id клиента и id заказа. При этом для "customer" будет использована жадная загрузка
$orders = Order::find()->joinWith('customer')->orderBy('customer.id, order.id')->all();

// найдёт все заказы, в которых есть книги. При этом для "books" будет использована жадная загрузка
$orders = Order::find()->innerJoinWith('books')->all();



Это особенно полезно при работе с связанными столбцами в GridView. Теперь, используя joinWith(), очень легко сделать по ним сортировку или отфильтровать.

Преобразование типов данных


ActiveRecord теперь конвертирует данные, полученные из базы в соответствующие типы. К примеру, если у вас в базе столбец type типа integer, после получения соответствующего экземпляра ActiveRecord, type будет типа integer в PHP.

Поиск


Для того, чтобы упростить задачу поиска мы добавили метод Query::filterWhere(), который автоматически убирает пустые значения. К примеру, если у вас есть форма поиска с фильтром по полям name и email, то вы можете использовать приведённый код для построения поискового запроса. Без данного метода вам бы пришлось проверять, ввёл ли пользователь что-либо в поле и добавлять условие поиска только в этом случае. filterWhere() делает такую проверку за вас.

$query = User::find()->filterWhere([
    'name' => Yii::$app->request->get('name'),
    'email' => Yii::$app->request->get('email'),
]);



Пакетные запросы


Мы добавили поддержку пакетных запросов для работы с крупными объёмами данных. При использовании данной возможности мы получаем данные порциями, а не сразу. Это позволяет значительно экономить память. К примеру:

use yii\db\Query;

$query = (new Query())
    ->from('user')
    ->orderBy('id');

foreach ($query->batch() as $users) {
    // $users — массив из 100 или менее строк из таблицы user
}

// или, если хотите получать по одной строке за раз
foreach ($query->each() as $user) {
    // $user — одна строка данных из таблицы user
}


Вы можете использовать пакетные запросы и с ActiveRecord:

// выбираем по 10 клиентов за раз
foreach (Customer::find()->batch(10) as $customers) {
    // $customers — массив 10 или менее объектов Customer
}
// выбираем по 10 клиентов за раз, перебираем по одному
foreach (Customer::find()->each(10) as $customer) {
    // $customer — объект Customer
}
// пакетный запрос с жадной загрузкой
foreach (Customer::find()->with('orders')->each() as $customer) {
}



Поддержка подзапросов


В построитель запросов была добавлена поддержка вложенных запросов. Вы можете составить подзапрос как обычный объект Query и далее использовать его в другом Query:

$subQuery = (new Query())->select('id')->from('user')->where('status=1');
$query->select('*')->from(['u' => $subQuery]);



Обратные связи


Связи часто могут объявляться парами. К примеру, Customer может содержать связь orders, в Order может содержать связь customer. В примере ниже можно заметить, что customer заказа не тот же самый объект, что и изначальный, для
которого ищутся заказы. Вызов customer->orders приведёт к новому SQL-запросу также, как и как вызов customer заказа:

// SELECT * FROM customer WHERE id=1
$customer = Customer::findOne(1);
// echoes "not equal"
// SELECT * FROM order WHERE customer_id=1
// SELECT * FROM customer WHERE id=1
if ($customer->orders[0]->customer === $customer) {
    echo 'equal';
} else {
    echo 'not equal';
}


Чтобы избежать лишнего SQL запроса можно объявить обратную связь для связей customer и orders. Делается это при помощи метода inverseOf():

class Customer extends ActiveRecord
{
    // ...
    public function getOrders()
    {
        return $this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer');
    }
}



Теперь, если мы выполним приведённый код ещё раз, мы получим следующее:

// SELECT * FROM customer WHERE id=1
$customer = Customer::findOne(1);
// echoes "equal"
// SELECT * FROM order WHERE customer_id=1
if ($customer->orders[0]->customer === $customer) {
    echo 'equal';
} else {
    echo 'not equal';
}



Единообразные API для Relational Query


В альфе 2.0 в ActiveRecord мы реализовали поддержку как реляционных (например, MySQL), так
и noSQL (например, redis, elasticsearch, MongoDB) хранилищ данных. В бете мы отрефакторили этот код и достигли большего единообразия интерфейсов. А именно, был удалён ActiveRelation, а ActiveQuery стал единой точкой входа для выполнения запросов по связям и описания связей. Также мы добавили методы ActiveRecord::findOne() и findAll().
Эти методы позволяют делать запросы по ключам или значениям столбцов, используя короткий синтаксис. Ранее это можно было делать параметрами метода ActiveRecord::find(), что вызывало путаницу из за возврата методом разных типов данных.

Поддержка AJAX


Мы решили использовать отличную библиотеку Pjax и создали виджет yii\widgets\Pjax. Это общий виджет, позволяющий добавить AJAX ко всему, что в него обёрнуто. К примеру, в него можно обернуть GridView для
того, чтобы получить постраничную навигацию и сортировку без перезагрузки страницы:

use yii\widgets\Pjax;
use yii\grid\GridView;

Pjax::begin();
echo GridView::widget([ /*...*/ ]);
Pjax::end();



Request и response


Кроме множества внутренних исправлений и улучшений, компоненты request и response подверглись и множеству изменений. Самое заметное заключается в том, что работа с request теперь выглядит так:

// получаем GET параметр из request, если его там нет, умолчание равно 1
$page = Yii::$app->request->get('page', 1);
// получаем POST параметр из request, если его там нет, умолчание равно null
$name = Yii::$app->request->post('name');


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

Класс request теперь умеет разбирать тело запроса в различных форматах, например JSON.

Фильтры


Весь механизм фильтрации был переосмыслен. Теперь вы можете включить фильтрацию action-ов на как уровне контроллера, так и на уровнях приложения или модуля. Это позволяет вам организовать иерархичные фильтры. К примеру, вы можете установить фильтр для модуля и он будет применяться ко всем его action-ам. В дополнение можно установить ещё один фильтр на некоторые контроллеры модуля. Этот фильтр будет применяться только к action-ом в этих контроллерах.

Код был реорганизован и фильтры теперь находятся в пространстве имён yii\filters. К примеру, вы можете использовать фильтр yii\filters\HttpBasicAtuh для того, чтобы включить аутентификацию HTTP Basic Auth. Для этого он описывается в контроллере или модуле:

public function behaviors()
{
    return [
        'basicAuth' => [
            'class' => \yii\filters\auth\HttpBasicAuth::className(),
            'exclude'=> ['error'],   // не применяем к action "error"
        ],
    ];
}



Инициализация компонент


Мы ввели в жизненный цикл приложения важный шаг инициализации («bootstrap»). Расширения могут зарегистрировать bootstrap-классы путём объявления их в composer.json. Обычный компонент также может быть зарегистрирован для bootstrap если его объявить в Application::$bootstrap.

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

Работа с URL


Так как разработчики очень много работают с URL, мы вынесли большинство относящихся к URL методов в хелпер Url и получили более приятный API:

use yii\helpers\Url;

// текущий активный маршрут
// например: /index.php?r=management/default/users
echo Url::to('');

// тот же контроллер, другой action
// например: /index.php?r=management/default/page&id=contact
echo Url::toRoute(['page', 'id' => 'contact']);


// тот же модуль, другие контроллер и action
// например: /index.php?r=management/post/index
echo Url::toRoute('post/index');

// абсолютный маршрут не зависит от того, какой контроллер делает запрос
// например: /index.php?r=site/index
echo Url::toRoute('/site/index');

// url для регистрозависимого имени `actionHiTech` текущего контроллера
// например: /index.php?r=management/default/hi-tech
echo Url::toRoute('hi-tech');

// url для action в контроллере с регистрозависимым именем, `DateTimeController::actionFastForward`
// например: /index.php?r=date-time/fast-forward&id=105
echo Url::toRoute(['/date-time/fast-forward', 'id' => 105]);

// получаем URL из alias
Yii::setAlias('@google', 'http://google.com/');
echo Url::to('@google/?q=yii');

// получаем канонический URL для текущей страницы
// например: /index.php?r=management/default/users
echo Url::canonical();

// получаем домашний URL
// например: /index.php?r=site/index
echo Url::home();

Url::remember(); // сохраняем URL
Url::previous(); // получаем сохранённый URL


В правилах URL тоже имеются улучшения. Вы можете использовать новый класс yii\web\GroupUrlRule для того, чтобы группировать правила. Для каждой группы можно задать общий префикс, который будет применяться ко всем URL в группе.

new GroupUrlRule([
    'prefix' => 'admin',
    'rules' => [
        'login' => 'user/login',
        'logout' => 'user/logout',
        'dashboard' => 'default/dashboard',
    ],
]);

// правило выше эквивалентно следующему:
[
    'admin/login' => 'admin/user/login',
    'admin/logout' => 'admin/user/logout',
    'admin/dashboard' => 'admin/default/dashboard',
]


Контроль доступа на основе ролей (RBAC)


Мы переделали реализацию RBAC. Теперь она основана на исходной модели RBAC NIST, а именно мы выкинули концепцию операций и задач. Вместо них теперь разрешения, что соответствует термину NIST.

Как было упомянуто выше, редизайн постиг и biz rule. Теперь правила описываются в отдельных классах.

Переводы


Сперва мы хотим сказать спасибо всем членам сообщества, которые участвовали в переводе сообщений фреймворка. На данный момент они переведены на 26 языков. Хорошее число, правда?

Компонент перевода сообщений теперь пытается взять сообщения из альтернативного источника, если используемый не содержит нужного сообщения. К примеру, если ваше приложение использует fr-CA в качестве языка, а переводы есть только для fr, то Yii сначала будет искать перевод в fr-CA и, если он там не найден, поиск продолжится в fr.

В генератор кода Gii была добавлена новая опция, которая позволяет вам генерировать код с сообщениями, обёрнутыми в Yii::t().

Команда для поиска сообщений для перевода научилась писать строки в .po и базы данных.

Расширения и инструменты


Мы реализовали расширение генератор документации yii2-apidoc, которое можно использовать для создания документации по API и основной документации из markdown. Генератор легко настраивается и расширяется под ваши нужды. Мы используем его для генерации официальной документации и API. Вы можете посмотреть на результат тут: http://www.yiiframework.com/doc-2.0/.

Дебаггер получил множество мелких улучшений и панель отладки почты. Также он научился показывать количество запросов к базе данных и количество отправленных писем в тулбаре.

Кроме улучшений по части переводов, упомянутых выше, в Gii был добавлен новый генератор расширений. Кроме того, вы можете заметить улучшений в предварительном просмотре генерируемого кода. Вы можете быстро переключаться между файлами и обновлять diff, в том числе и с клавиатуры. Также теперь при копи-пасте из diff в буфер не попадает ничего лишнего.
Попробуйте!

Спасибо!



Бета-версия Yii 2.0 — большая веха, которая была достигнута большими совместными усилиями. У нас бы ничего не получилось без огромного количества ценного кода, полученного от нашего замечательного сообщества.
Спасибо вам за то, что этот релиз состоялся.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+84
Comments 43
Comments Comments 43

Articles