Yii 2.0.14

habr.png

Команда Yii рада представить новую версию PHP фреймворка: Yii 2.0.14. В неё вошло более сотни улучшений и исправлений, включая исправления безопасности.


В релиз вошли несколько изменений, которые могут повлиять на уже работающие приложения. Эти изменения описаны в UPGRADE.md.


Спасибо сообществу Yii за помощь в выпуске этого обновления!


За процессом разработки можно следить, поставив звёздочку на GitHub. У нас есть много сообществ Yii, где вы можете попросить помощи или поделится своим опытом — мы и тысячи других пользователей Yii будем рады вашему участию.


Этот релиз знаменателен тем, что становится последним релизом в версии Yii 2.0, содержащим улучшения. Это значит, что мы сконцентрируем силы на разработке версии 2.1.x, в которую войдёт много новых улучшений, которые невозможно включить в ветку 2.0.х из-за ограничений по сохранению обратной совместимости. Несмотря на это, ветка 2.0.х будет получать исправления и улучшения безопасности. Сроки окончания поддержки 2.0.х будут объявлены вместе с релизом версии 2.1.


Убедитесь что версия фреймворка в composer.json прописана верно (~2.0.14) и вы не обновитесь на 2.1 случайно, когда он релизнется.


Ниже мы рассмотрим самые интересные улучшения и исправления релиза. Полный список можно, как обычно, найти в CHANGELOG.


Масштабируемость и параллелизм


Проблемы масштабируемость и параллелизма часто отходят на второй план в начале разработки, но «всплывают» при росте бизнеса. В этом релизе мы нашли и исправили ошибку, которая касалась записи значений в базу данных и обновления ID сессии. При использовании master-slave репликации, yii\web\DbSession, yii\validators\UniqueValidator и yii\validators\ExistValidator могли обращаться к slave-серверу, в то время как корректнее было бы обращаться к master-серверу.


Улучшения валидаторов


В дополнение к сказанному выше, есть ещё несколько улучшений валидаторов.


Во-первых, ExistValidator теперь может проверять существование связей, если установлено свойство targetRelation. Это значит, что теперь можно описать следующую конфигурацию правил валидации:


public function rules()
{
    return [
        [['customer_id'], 'exists', 'targetRelation' => 'customer'],
    ];
}

public function getCustomer()
{
    return $this->hasOne(Customer::class, ['id' => 'customer_id']);
}


Во-вторых FileValidator получил новое свойство minFiles указывающее минимальное количество файлов, которые должен загрузить пользователь.


Поведения


yii\behaviors\BlameableBehavior получил новое свойство defaultValue, которое используется в случае, когда ID пользователя не может быть определён. Такое обычно происходит, если модель ActiveRecord используется в консольном приложении.


В yii\behaviors\AttributeTypecastBehavior появилось новое свойство typecastAfterSave. Если его выставить в true значения атрибутов будут приводиться к указанным типам сразу после сохранения модели. Типы будут теми же, что и при загрузке модели из базы.


Было добавлено поведение yii\behaviors\CacheableWidgetBehavior. Оно автоматически кеширует контент виджета в соответствии с настройками зависимостей и времени валидности кеша. Например:


use yii\behaviors\CacheableWidgetBehavior;

public function behaviors()
{
  return [
      [
          'class' => CacheableWidgetBehavior::className(),
          'cacheDuration' => 0,
          'cacheDependency' => [
              'class' => 'yii\caching\DbDependency',
              'sql' => 'SELECT MAX(updated_at) FROM posts',
          ],
      ],
  ];
}


Базы данных и ActiveRecord


Этот релиз добавляет много новых вещей, связанных с базами данных и ActiveRecord. Эти улучшения были реализованы силами Дмитрия Науменко, Сергея Макинена, Роберта Корульчыка, Николая Олейникова и других участников сообщества.


Объектный формат описания условия и пользовательские типы данных


Была реализована поддержка пользовательских типов данных. Добавлена поддержка JSON для MySQL и PostgreSQL, а также массивов для PostgreSQL. Чтобы достигнуть этого, внутренняя реализация Query Builder-а была существенно переработана, что также позволило реализовать поддержку описания условий в объектном формате. Поддержка привычного формата описания условий осталась без изменений. Кроме того, форматы можно комбинировать:


$query->andWhere(new OrCondition([
    new InCondition('type', 'in', $types),
    ['like', 'name', '%good%'],
    'disabled=false',
]));


Это улучшение даёт несколько преимуществ. Во-первых, теперь команде разработчиков Yii проще поддерживать код, связанный с условиями. Это уже позволило добавить новое условие BetweenColumnsCondition, которое собирает SQL вроде 15 BETWEEN min_age AND max_age. К релизу 2.1, скорее всего, добавится поддержка новых типов условий. Во-вторых, теперь вы можете удобно создавать свои классы условий и использовать их в ваших проектах.


Гибкость Query Builer


Описанные выше изменения позволили принимать yii\db\Query в условиях везде, где можно было передавать yii\db\Expression ранее. Например:


$subquery = (new Query)
    ->select([new Expression(1)])
    ->from('tree')
    ->where(['parent_id' => 1, 'id' => new Expression('tree.parent_id']));

(new Query())
    ->from('tree')
    ->where(['or', 'parent_id = 1', $subquery])


Upsert


Ещё одним существенным улучшением слоя работы с базами данных стала поддержка UPSERT — атомарной операции, которая создаёт новые записи, если они ещё не существуют (проверяется уникальный ключ), или изменяет существующие записи. К примеру, взгляните на следующий код:


Yii::$app->db->createCommand()->upsert('pages', [
    'name' => 'Front page',
    'url' => 'http://example.com/', // URL уникален
    'visits' => 0,
], [
    'visits' => new \yii\db\Expression('visits + 1'),
], $params)->execute();


Он или создаёт новую страницу, или увеличит её счётчик посещений автоматически.


Schema builder и миграции


Schema builder теперь поддерживает типы «tiny integer» и «JSON», так что можно их использовать и в написании миграций:


$this->createTable('post', [
    'id' => $this->primaryKey(),
    'text' => $this->text(),
    'title' => $this->string()->notNull(),
    'attributes' => $this->json(),
    'status' => $this->tinyInteger(),
]);


Ещё одно улучшение позволяет создавать и удалять представления (views):


$this->createView(
    'top_10_posts',
    (new \yii\db\Query())
        ->from('post')
        ->orderBy(['rating' => SORT_DESC])
        ->limit(10)
);

$this->dropView('top_10_posts');


Новый API кеширования запросов


Ранее было возможно кешировать результат выполнения запроса, оборачивая его в метод Connection::cache(). Теперь есть возможность пользоваться более удобным API:


// На уровне query
(new Query())->cache(7200)->all();

// На уровне AR
User::find()->cache(7200)->all();


Связи в Active Record


Active Record теперь сбрасывает связанные модели при изменении атрибута, на котором строится эта связь:


$item = Item::findOne(1);
echo $item->category_id; // 1
echo $item->category->name; // weapons

$item->category_id = 2;
echo $item->category->name; // toys


Обработка ошибок


Цели логирования теперь выбрасывают исключение, когда не могут корректно экспортировать лог. Ранее они молча игнорировали ошибку, что могло привести к отсутствию логов, например, из-за неправильных прав на директорию.


Также теперь если HTTP заголовки уже были отправлены, при попытке отправить дополнительные будет выброшено исключение yii\web\HeadersAlreadySentException. Ранее эта ситуация молча игнорировалась.


Теперь возможно настроить обработчик ошибок Yii, изменив свойство $traceLine. Это может быть использовано, например, для генерации ссылок, которые могут быть открыты сразу в среде разработки. Настройка схожа с настройкой ссылок для панели отладки:


'components' => [
    // ...
    'errorHandler' => [
        'errorAction' => 'site/error',
        'traceLine' => '{html}',
    ],
],


Используя свойство yii\web\ErrorAction::$layout, можно удобно изменить шаблон страницы ошибки:


class SiteController extends Controller
{
    // ...
    /**
     * @inheritdoc
     */
    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
                'layout' => 'error', // <-- HERE
        ],
    ];
}


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


Было обнаружено и исправлено две уязвимости:


  • CVE-2018–6009. Метод switchIdentity() в web/User.php не пересоздавал токен CSRF при смене пользователя.
  • CVE-2018–6010. В некоторых случаях было возможно получение отладочной информации из исключений, которые обрабатывал обработчик ошибок.


PHP 7.2


Yii 2.0.14 полностью поддерживает PHP 7.2. Мы поправили yii\filters\HttpCache, FileHelper::getExtensionsByMimeType() и yii\web\Session для нормальной работы на всех поддерживаемых версиях PHP.


Виджеты, формы, клиентский JavaScript


Тег