Pull to refresh

Yii 2.0.14

Reading time 9 min
Views 19K

Команда 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 Builder


Описанные выше изменения позволили принимать 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' => '<a href="ide://open?url={file}&line={line}">{html}</a>',
    ],
],

Используя свойство 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


Тег <script> больше не содержит свойства type. Выглядит короче, и делает валидаторы HTML5 счастливыми :)


В полях, генерируемых Active Form и Html helper для аттрибутов модели, можно использовать автоматически сгенерированный placeholder:


<?=  Html::activeTextInput($post, 'title', ['placeholder' => true]) ?>

На пути к поддержке Bootstrap 4, добавлена возможность указывать, какой элемент будет получать класс-отметку о наличии ошибки валидации:


<?php $form = ActiveForm::begin([
    'validationStateOn' => ActiveForm::VALIDATION_STATE_ON_INPUT, // или VALIDATION_STATE_ON_CONTAINER 
]) ?>

Появилась возможность безопасно регистрировать JavaScript переменные из PHP кода:


class SiteController extends Controller
{
    public function actionIndex()
    {
        $this->view->registerJsVar('username', 'SilverFire');
        return $this->render('index');
    }
}

Не смотря на то, что этот способ широко используется для передачи данных из PHP в JS, мы всё-таки советуем сначала попробовать воспользоваться возможностью HTML5 – data-атрибутами.


События


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


API, сериализация и фильтры


При настройке JsonResponseFormatter теперь можно указать тип контента:


'components' => [
    'response' => [
        // ...
        'formatters' => [
            \yii\web\Response::FORMAT_JSON => [
                'class' => \yii\web\JsonResponseFormatter::className(),
                'contentType' => \yii\web\JsonResponseFormatter::CONTENT_TYPE_HAL_JSON,
            ],
        ],
    ],
]

Data filter теперь поддерживает условия lt,gt,lte и gte для yii\validators\DateValidator.


yii\base\ArrayableTrait::toArray() теперь поддерживает рекурсию в свойствах $fields и $expand. Запросы к REST APIs с expand могут быть описаны как extra1.extra2 и это будет значить, что нужно развернуть extra1 в первоначальном наборе данных, а затем extra2 в extra1. То есть теперь возможны запросы вроде http://localhost/comments?expand=post.author.


Теперь проще реализовывать поддержку своих заголовков для аутентификации, используя yii\filters\auth\HttpHeaderAuth.


В случае, когда вам нужно сериализировать ошибки валидации в JSON, вы можете использовать новый метод \yii\helpers\Json::errorSummary().


Консоль


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


if (!$model->validate()) {
    echo "Model is not valid:\n";
    echo \yii\helpers\Console::errorSummary($model);
    return ExitCode::DATAERR;
}

Улучшен скрипт автодополнения для bash и zsh. Теперь он поддерживает автодополнение для ./yii help.


Вызывая консольные команды, параметры можно указывать как в camelCase, так и kebab-case: --selfUpdate и --self-update будут считаться одним и тем же параметром.
Более того, в дополнение к --<option>=<value> появилась поддержка синтаксиса --<option> <value>.


Маршрутизация


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


'components' => [
    'urlManager' => [
        // ...
        'rules' => [
            new GroupUrlRule([
                'prefix' => 'file',
                'rules' => [
                    'POST document' => 'document/create',
                ],
            ]),
    ],
],

i18n


Был добавлен компонент yii\i18n\Locale с методом getCurrencySymbol(), который возвращает символ валюты в выбранной локали.


Helper'ы


В этом релизе сделаны некоторые интересные улучшения хэлперов.


Два новых метода yii\helpers\FileHelper:


  • findDirectories() – возвращает найденные директории и поддиректории по указанному пути. Этот метод работает схоже с findFiles(), но ищет директории.
  • unlink() – удаляет файл или симлинк кроссплатформенно. Как выяснилось, даже там есть особенности.

В yii\helpers\StringHelper добавился метод matchWildcard(), который делает то же самое, что и нативный метод fnmatch(), но с учётом особенностей операционной системы. Подтверждено, что нативная реализация даёт разные результаты на разных ОС.


Добавлен yii\helpers\IpHelper. Он предоставляет методы для определения версии IP адреса, проверки IP адреса или подсети на вхождение в другую подсеть, разворачивания IPv6 адреса до полного формата. Например:


if (!IpHelper::inRange($ip, '192.168.1.0/24')) {
    // deny access
}

Контейнер DI


В контейнере появилась возможность переиспользовать описания в свойствах:


'container' => [
    'definitions' => [
        \console\models\TestService::class => [
            'class' => \console\models\TestService::class,
            'model' => Instance::of(\console\models\TestModel::class)
        ],
        \console\models\TestModel::class => [
            'class' => \console\models\TestModel::class,
            'property' => 20,
        ],
    ],
]

В этом примере значением свойства model в классе TestService будет объект класса TestModel, сконфигурированный в соответствии с описанием.


Шаблоны приложений


В дополнение к некоторым незначительным улучшениям, шаблон basic получил поддержку Docker и Vagrant.


Подготовка к релизу 2.1


Чтобы упростить переход с 2.0 на 2.1, Brandon Kelly предложил отметить методы и классы, которые уже удалены в ветке 2.1 аннотацией @deprecated в ветке 2.0.х. Такую отметку получили:


  • yii\base\BaseObject::className() в пользу нативного синтаксиса ::class, который не вызывает автозагрузку (поддерживается в PHP >=5.5);
  • Модули поддержки XCache и Zend data cache;
  • Метод yii\BaseYii::powered();
  • yii\base\InvalidParamException в пользу yii\base\InvalidArgumentException;
  • yii\BaseYii::trace() в пользу yii\BaseYii::debug().

Код, который использует эти методы, будет продолжать работать, но IDE будет подсвечивать его как устаревший.

Tags:
Hubs:
+39
Comments 59
Comments Comments 59

Articles