Pull to refresh

Yii2. Знакомство

Reading time4 min
Views109K

Введение

На днях, свершилось событие, которое Я и думаю еще немало людей ждали. Авторы Yii Framework выкатили превью-версию.

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

Начало

Вторая версия отличается от первой кардинально. Список в краткой форме:

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

— Базовый CComponent разделили на Object и Component. Первый осуществляет работу геттеров и сеттеров, второй расширяя первый, добавляя события и поведения.

— Видоизменилось подключение событий и поведений. Подписываемся на событие
$post->on('update', function($event) {
    // send email notification
});

Настраиваем компонент
$component = \Yii::createObject(array(
  'class' => '\app\components\GoogleMap',
  'apiKey' => 'xyz',
  // Добавим событие
  'on eventName' => array('Event', 'run'),
  // Добавим поведение
  'as behaviorName' => array(/* Behavior config */),
));

— Добавили новый класс View, теперь у нас настоящий MVC фреймворк. Представление
<?php
use yii\helpers\base\Html;
/**
 * Обратите внимание $this в представлении это уже не контроллер.
 * Добраться к контроллеру можно $this->context
 * @var yii\base\View $this
 */
$this->title = 'Hello world';
?>
<h1><?php echo Html::encode($this->title); ?></h1>
<p class="lead">Привет мир!</p>
* View можно для каждого контроллера устанавливать, или использовать базовый для приложения.

— render() контроллера больше ничего не выводит. Оно возвращает данные
public function actionIndex()
{
	echo $this->render('index');
}

— В контроллере появились два события, на котрые можно подписываться: beforeAction, afterAction
public function init()
{
  $this->on('beforeAction', function($event) {
    // отменяем действие
    $event->isValid = false;
  });
}

— Убраны фильтры контроллера CFilter, теперь все делается через поведения
public function behaviors()
{
  return array(
    'AccessControl' => array(
      'class' => '\yii\web\AccessControl',
      'rules' =>array(/* тут ничего не поменялось */),
    ),
  );
}

— В контроллере появился отличный помощник — метод populate
public function actionLogin()
{
  $model = new LoginForm();
  if ($this->populate($_POST, $model) && $model->login()) {
    Yii::$app->response->redirect(array('site/index'));
  }

  echo $this->render('login', array(
    'model' => $model,
  ));
}

— Добавлены еще несколько статических классов-хелперов: ArrayHelper, StringHelper, SecurityHelper. Все хелперы теперь можно перекрыть через LSB. Ура, воскликнул я, т.к лично мне не раз нужно было перекрыть Html.

— Виджет ActiveForm тоже переписан, и скорее всего заменит форм-билдер CForm. Каждое поле формы теперь может быть представлено как объект ActiveField, который создает ActiveForm
$form = $this->beginWidget('yii\widgets\ActiveForm', array(
  'options' => array('class' => 'form-horizontal')
));

  echo $form->field($model, 'username')->textInput(); 
  echo $form->field($model, 'password')->passwordInput(); 
  echo $form->field($model, 'rememberMe')->checkbox();

  echo Html::tag('div', Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')), array(
    'class' => 'form-actions'
   ));

$this->endWidget();
* Внимание: в Html::tag($tag, $content, $options) — изменили порядок параметров!

ActiveRecord

«По большей части, ActiveRecord осталась нетронутой»
— написано в предыдущей статье. Верно подмечено — не трогали.
Просто взяли и написали совсем другой ActiveRecord.

— Забываем про model()

— Убран CDbCriteria. Но не пугайтесь, работа с базой стала от этого легче. Появился ActiveQuery, который представляет себя гибрид CActiveFinder и CDbCriteria.
// получаем экземпляр ActiveQuery
$query = Post::find();

// все посты
$posts = $query->all();

// ищем все посты с условием
$posts = $query
    ->where(array('status' => Post::DRAFT))
    ->orderBy('time')
    ->all();

// ищем один пост 
$post = $query
   ->where(array('id' => 10, 'status' => Post::READ))
   ->one();

// или проще, условие where можно передавать прямо в фабричный метод
$post = Post::find(array('id' => 10, 'status' => Post::READ));

// передав в фабричный метод не массив а число эквивалентно поиску по первичному ключу 
$post = Post::find(10)
   ->where(array('status' => Post::READ))
   ->one();

// индексируем результат по нужному атрибуту
$posts = $query->indexBy('title')->all();

// результат в виде массива
$posts = $query->asArray()->all();

— Все общие методы теперь статические: getDb, tableName, find*, saveAll*, primaryKey. Выигрыш очевиден.

— Связи, куда же без них. Теперь связи определяются добавлением геттеров
class Post extends ActiveRecord
{
    public function getCreator()
    {
        return $this->hasOne('User', array('id' => 'user_id'));
    }
    public function getComments()
    {
        return $this->hasMany('Comment', array('post_id' => 'id'));
    }
    public function getTrustComments($isTrust = true)
    {
        return $this->hasMany('Comment', array('post_id' => 'id'))
            ->where('status = :status', array(
                     ':status' => $isTrust ? self::TRUST : self::UNTRUST,
              ))
            ->orderBy('id');
    }
}

— Для удобства работы со связями добавили link() и unlink(), который автоматически расставят ключи
$post = Post::find(1);

$comment = new Comment();
$comment->text = 'Yii Framework is cool!';
$post->link('comments', $comment);

— Именованные группы условий есть, но в другом виде. У нас же нет больше CDbCriteria, а значит и массивов условий тоже больше нет. Теперь это методы, причем статические, добавляющие условия в Query
class Post extends \yii\db\ActiveRecord
{
    /**
     * @param ActiveQuery $query
     */
    public static function byCreator($query, $userId)
    {
        $query->andWhere('user_id = :userId', array('userId' => $userId));
    }
    /**
     * @param ActiveQuery $query
     */
    public static function removed($query)
    {
        $query->andWhere('removed = 1');
    }
}

$posts = Post::find()->removed()->all();
$myPosts = Post::find()->byCreator(Yii::$app->user->id)->all();


Все

На этом поставлю точку. Статья получилась большая, много кода, но надеюсь вы выдержали и дочитали.

До связи.
Tags:
Hubs:
Total votes 127: ↑116 and ↓11+105
Comments54

Articles