Начало
Вторая версия отличается от первой кардинально. Список в краткой форме:
— Отделили ядро от дополнений. Выбросили много классов. Часть из них перекочуют в отдельные, официально поддерживаемые, расширения. Часть просто убрана за ненадобностью.
— Базовый CComponent разделили на Object и Component. Первый осуществляет работу геттеров и сеттеров, второй расширяя первый, добавляя события и поведения.
— Видоизменилось подключение событий и поведений. Подписываемся на событие
1 2 3 4 |
$post->on(<span class="hljs-string">'update'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($event)</span> </span>{ <span class="hljs-comment">// send email notification</span> }); |
Настраиваем компонент
1 2 3 4 5 6 7 8 9 |
$component = \Yii::createObject(<span class="hljs-keyword">array</span>( <span class="hljs-string">'class'</span> => <span class="hljs-string">'\app\components\GoogleMap'</span>, <span class="hljs-string">'apiKey'</span> => <span class="hljs-string">'xyz'</span>, <span class="hljs-comment">// Добавим событие</span> <span class="hljs-string">'on eventName'</span> => <span class="hljs-keyword">array</span>(<span class="hljs-string">'Event'</span>, <span class="hljs-string">'run'</span>), <span class="hljs-comment">// Добавим поведение</span> <span class="hljs-string">'as behaviorName'</span> => <span class="hljs-keyword">array</span>(<span class="hljs-comment">/* Behavior config */</span>), )); |
— Добавили новый класс View, теперь у нас настоящий MVC фреймворк. Представление
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="hljs-meta"><?php</span> <span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\<span class="hljs-title">helpers</span>\<span class="hljs-title">base</span>\<span class="hljs-title">Html</span>; <span class="hljs-comment">/** * Обратите внимание $this в представлении это уже не контроллер. * Добраться к контроллеру можно $this->context * <span class="hljs-doctag">@var</span> yii\base\View $this */</span> $this->title = <span class="hljs-string">'Hello world'</span>; <span class="hljs-meta">?></span> <h1><span class="hljs-meta"><?php</span> <span class="hljs-keyword">echo</span> Html::encode($this->title); <span class="hljs-meta">?></span></h1> <p <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">lead</span>">Привет мир!</<span class="hljs-title">p</span>> </span> |
* View можно для каждого контроллера устанавливать, или использовать базовый для приложения.
— render() контроллера больше ничего не выводит. Оно возвращает данные
1 2 3 4 5 |
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionIndex</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">echo</span> $this->render(<span class="hljs-string">'index'</span>); } |
— В контроллере появились два события, на котрые можно подписываться: beforeAction, afterAction
1 2 3 4 5 6 7 8 |
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span><span class="hljs-params">()</span> </span>{ $this->on(<span class="hljs-string">'beforeAction'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">($event)</span> </span>{ <span class="hljs-comment">// отменяем действие</span> $event->isValid = <span class="hljs-keyword">false</span>; }); } |
— Убраны фильтры контроллера CFilter, теперь все делается через поведения
1 2 3 4 5 6 7 8 9 10 |
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">behaviors</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-keyword">array</span>( <span class="hljs-string">'AccessControl'</span> => <span class="hljs-keyword">array</span>( <span class="hljs-string">'class'</span> => <span class="hljs-string">'\yii\web\AccessControl'</span>, <span class="hljs-string">'rules'</span> =><span class="hljs-keyword">array</span>(<span class="hljs-comment">/* тут ничего не поменялось */</span>), ), ); } |
— В контроллере появился отличный помощник — метод populate
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionLogin</span><span class="hljs-params">()</span> </span>{ $model = <span class="hljs-keyword">new</span> LoginForm(); <span class="hljs-keyword">if</span> ($this->populate($_POST, $model) && $model->login()) { Yii::$app->response->redirect(<span class="hljs-keyword">array</span>(<span class="hljs-string">'site/index'</span>)); } <span class="hljs-keyword">echo</span> $this->render(<span class="hljs-string">'login'</span>, <span class="hljs-keyword">array</span>( <span class="hljs-string">'model'</span> => $model, )); } |
— Добавлены еще несколько статических классов-хелперов: ArrayHelper, StringHelper, SecurityHelper. Все хелперы теперь можно перекрыть через LSB. Ура, воскликнул я, т.к лично мне не раз нужно было перекрытьHtml.
— Виджет ActiveForm тоже переписан, и скорее всего заменит форм-билдер CForm. Каждое поле формы теперь может быть представлено как объект ActiveField, который создает ActiveForm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$form = $this->beginWidget(<span class="hljs-string">'yii\widgets\ActiveForm'</span>, <span class="hljs-keyword">array</span>( <span class="hljs-string">'options'</span> => <span class="hljs-keyword">array</span>(<span class="hljs-string">'class'</span> => <span class="hljs-string">'form-horizontal'</span>) )); <span class="hljs-keyword">echo</span> $form->field($model, <span class="hljs-string">'username'</span>)->textInput(); <span class="hljs-keyword">echo</span> $form->field($model, <span class="hljs-string">'password'</span>)->passwordInput(); <span class="hljs-keyword">echo</span> $form->field($model, <span class="hljs-string">'rememberMe'</span>)->checkbox(); <span class="hljs-keyword">echo</span> Html::tag(<span class="hljs-string">'div'</span>, Html::submitButton(<span class="hljs-string">'Login'</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">array</span>(<span class="hljs-string">'class'</span> => <span class="hljs-string">'btn btn-primary'</span>)), <span class="hljs-keyword">array</span>( <span class="hljs-string">'class'</span> => <span class="hljs-string">'form-actions'</span> )); $this->endWidget(); |
* Внимание: в Html::tag($tag, $content, $options) — изменили порядок параметров!
ActiveRecord
«По большей части, ActiveRecord осталась нетронутой»
— написано в предыдущей статье. Верно подмечено — не трогали.
Просто взяли и написали совсем другой ActiveRecord.
— Забываем про model()
— Убран CDbCriteria. Но не пугайтесь, работа с базой стала от этого легче. Появился ActiveQuery, который представляет себя гибрид CActiveFinder и CDbCriteria.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<span class="hljs-comment">// получаем экземпляр ActiveQuery</span> $query = Post::find(); <span class="hljs-comment">// все посты</span> $posts = $query->all(); <span class="hljs-comment">// ищем все посты с условием</span> $posts = $query ->where(<span class="hljs-keyword">array</span>(<span class="hljs-string">'status'</span> => Post::DRAFT)) ->orderBy(<span class="hljs-string">'time'</span>) ->all(); <span class="hljs-comment">// ищем один пост </span> $post = $query ->where(<span class="hljs-keyword">array</span>(<span class="hljs-string">'id'</span> => <span class="hljs-number">10</span>, <span class="hljs-string">'status'</span> => Post::READ)) ->one(); <span class="hljs-comment">// или проще, условие where можно передавать прямо в фабричный метод</span> $post = Post::find(<span class="hljs-keyword">array</span>(<span class="hljs-string">'id'</span> => <span class="hljs-number">10</span>, <span class="hljs-string">'status'</span> => Post::READ)); <span class="hljs-comment">// передав в фабричный метод не массив а число эквивалентно поиску по первичному ключу </span> $post = Post::find(<span class="hljs-number">10</span>) ->where(<span class="hljs-keyword">array</span>(<span class="hljs-string">'status'</span> => Post::READ)) ->one(); <span class="hljs-comment">// индексируем результат по нужному атрибуту</span> $posts = $query->indexBy(<span class="hljs-string">'title'</span>)->all(); <span class="hljs-comment">// результат в виде массива</span> $posts = $query->asArray()->all(); |
— Все общие методы теперь статические: getDb, tableName, find*, saveAll*, primaryKey. Выигрыш очевиден.
— Связи, куда же без них. Теперь связи определяются добавлением геттеров
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span> </span>{ <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCreator</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> $this->hasOne(<span class="hljs-string">'User'</span>, <span class="hljs-keyword">array</span>(<span class="hljs-string">'id'</span> => <span class="hljs-string">'user_id'</span>)); } <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getComments</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> $this->hasMany(<span class="hljs-string">'Comment'</span>, <span class="hljs-keyword">array</span>(<span class="hljs-string">'post_id'</span> => <span class="hljs-string">'id'</span>)); } <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTrustComments</span><span class="hljs-params">($isTrust = true)</span> </span>{ <span class="hljs-keyword">return</span> $this->hasMany(<span class="hljs-string">'Comment'</span>, <span class="hljs-keyword">array</span>(<span class="hljs-string">'post_id'</span> => <span class="hljs-string">'id'</span>)) ->where(<span class="hljs-string">'status = :status'</span>, <span class="hljs-keyword">array</span>( <span class="hljs-string">':status'</span> => $isTrust ? <span class="hljs-keyword">self</span>::TRUST : <span class="hljs-keyword">self</span>::UNTRUST, )) ->orderBy(<span class="hljs-string">'id'</span>); } } |
1 2 3 4 5 6 |
$post = Post::find(<span class="hljs-number">1</span>); $comment = <span class="hljs-keyword">new</span> Comment(); $comment->text = <span class="hljs-string">'Yii Framework is cool!'</span>; $post->link(<span class="hljs-string">'comments'</span>, $comment); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">yii</span>\<span class="hljs-title">db</span>\<span class="hljs-title">ActiveRecord</span> </span>{ <span class="hljs-comment">/** * <span class="hljs-doctag">@param</span> ActiveQuery $query */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">byCreator</span><span class="hljs-params">($query, $userId)</span> </span>{ $query->andWhere(<span class="hljs-string">'user_id = :userId'</span>, <span class="hljs-keyword">array</span>(<span class="hljs-string">'userId'</span> => $userId)); } <span class="hljs-comment">/** * <span class="hljs-doctag">@param</span> ActiveQuery $query */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removed</span><span class="hljs-params">($query)</span> </span>{ $query->andWhere(<span class="hljs-string">'removed = 1'</span>); } } $posts = Post::find()->removed()->all(); $myPosts = Post::find()->byCreator(Yii::$app->user->id)->all(); Если говорить предельно кратко, то в новой версии фреймворка: |
- Отсутствие обратной совместимости с Yii 1.1;
- Пересмотрена архитектура классов, некоторые их реализации;
- Отсутствие, как следствие новой архитектуры, некоторых сущностей, например: CDbCriteria, CClientScript, CUserIdentity и другие;
- Поддержка шаблонизаторов Smarty и Twig.
1 |
Namespace
1 2 3 4 |
Отныне и повсеместно Yii 2.0 использует пространства имен, и это не может не радовать, особенно в случаях, когда проект начинает разрастаться. Префикс «C» перестал использоваться в именах классов. Именование классов соответствует структуре папок фреймворка, например класс <i>yii\web\Request</i> говорит, о том что будет подключен файл <i>web/Request.php</i> в папке фреймворка. Кстати вложенность в большинстве случаев не больше двух, поэтому объявление класса вряд ли покажется огромным, более того его даже легко запомнить. Да, как ты догадался, теперь фреймворк требует PHP 5.3 (или если быть <a href="http://www.slideshare.net/samdark/yiiconf-2012-alexander-makarov-yii2" rel="nofollow">точным</a> PHP 5.3.8+) со многими вытекающими (но приятными) последствиями, например использование анонимных функций. |
Псевдонимы путей
1 2 3 4 |
Yii 2.0 позволяет использовать псевдонимы как для путей к файлу/директории так и для URL. Псевдонимы обязаны начинаться с символа @, чтобы его можно было легко отличить от пути к файлу/директории или URL. Например псевдоним @yii ссылается на директорию, где установлен фреймворк Yii. Псевдонимы путей используются во многих местах ядра Yii 2.0, например в <i>FileCache::cachePath</i>. Также псевдонимы тесно связаны с пространством имен. Рекомендуется определять псевдоним для каждого корня пространства имен. Если ты используешь сторонние библиотеки, как например Zend Framework, то ты должен определить псевдоним @Zend, который будет ссылаться на директорию куда установлен Zend, чтобы автозагрузчик классов Yii смог обработать любой класс оттуда, например: |
1 |
\<span class="hljs-tag">Yii</span><span class="hljs-pseudo">::setAlias('</span><span class="hljs-at_rule">@<span class="hljs-keyword">Zend',</span> <span class="hljs-string">'@app/vendors/Zend'</span>)</span>; |
1 2 3 |
Кстати упомянутый выше автозагрузчик классов Yii соответвует <a href="https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md" rel="nofollow">PSR-0</a>. |
Компонент и объект
1 2 |
Класс CComponent, положенный в основу любого компонента в Yii1.x, теперь представлен в виде двух сущностей: |
- \yii\base\Object – легковесный класс, реализующий определение атрибутов класса через методы получение (set) и установки (get);
- \yii\base\Component – является расширением вышеуказанного, который поддерживает дополнительно события (event) и поведения (behavior).
1 2 3 |
По рекомендации авторов Yii, если проектируемый тобой класс не нуждается в использовании событий и поведений, наследуй его от Object. Среди прочих изменений можно добавить, что методы<strong> </strong>primaryKey() и tableName() стали статическими методами. |
Консольные приложения
1 2 3 4 5 6 |
Консольные приложения теперь также как и веб-приложения состоят из контроллеров и по сути оба наследуются от одного базового класса контроллера. Каждый консольный контроллер похож на класс <i>CConsoleCommand</i> из Yii 1.1 и состоит из одного или нескольких действий. Чтобы выполнить консольную команду используй <i>yiic <route></i>, где <i><route></i> это путь до контроллера (например, sitemap/index). Дополнительные анонимные аргументы передаются в качестве параметров для соответствующего метода контроллера, а именованные аргументы рассматриваются в качестве глобальных параметров, отъявленных в <i>GlobalOptions()</i>. Yii 2.0 поддерживает автоматическое создание справки из блока комментариев. |
Yii 2.0 активно развивается
1 2 |
Новая версия фреймворка очень заметно развивается, не только в плане исправления ошибок но и документации, достаточно проследить за активностью в течение нескольких дней: |
- 3 мая, вышел Public preview Yii 2.0;
- 6 мая, Yii 2.0 на первом месте в github, по рейтингу и количеству созданных веток в этот день, неделю и месяц. Также в этот день появляется первое расширение nested-set-behavior-2 от creocoder. На Хабрахабр появляется статья “Создание простого CRUD-приложения с помощью Yii2“;
- 7 мая, обновление гайдов на хитгаб, в том числе Upgrading from Yii 1.1;
- 8 мая, статья на Хабрахарб
1 |
[su_custom_gallery source="media: 209,210,211,212,213,215,216,217,218,219,220,221" link="lightbox" width="130"] |