YiiConf 2017 всё ближе! Не забудьте купить билет.
Yii 1.1.7

На днях вышел релиз 1.1.7 PHP-фреймворка Yii, в который было включено более 90 исправленных ошибок, улучшений и новых возможностей.

Полный список изменений доступен на сайте фреймворка, самые вкусные из которых мы рассмотрим ниже.

Поддержка URL в стиле REST

Теперь при использовании CUrlManager можно указать метод (GET, POST, PUT и т.д.) в свойстве verb правила URL. К примеру, приведённые ниже правила GET-запрос на post/123 будет обрабатываться действием post/view, а PUT или POST на post/123 — действием post/update.

[php]
return array(
	'components'=>array(
		'urlManager'=>array(
			'urlFormat'=>'path',
			'rules'=>array(
				array('<controller>/view', 'pattern'=>'<controller:\w>/<id:\d+>', 'verb'=>'GET'),                
				array('<controller>/update', 'pattern'=>'<controller:\w>/<id:\d+>', 'verb'=>'PUT, POST'),
			),
		),
	),
);

Получить данные PUT и DELETE можно при помощи методов CHttpRequest::getPut() и CHttpRequest::getDelete().

Кэширование запросов

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

Кэширование запросов реализовано как для DAO, так и для AR. Несколько примеров:

[php]
// кэшируем результат выполнения $sql на 1000 секунд или пока не обновится tbl_post
$sql = 'SELECT * FROM tbl_post LIMIT 20';
$dependency = new CDbCacheDependency('SELECT MAX(update_time) FROM tbl_post');
$rows = Yii::app()->db->cache(1000, $dependency)->createCommand($sql)->queryAll();

// то же, но для AR
$posts = Post::model()->cache(1000, $dependency)->findAll();
// query caching with relational AR
$posts = Post::model()->cache(1000, $dependency)->with('author')->findAll();

Привязка параметров для классов действий

В версии 1.1.4 была добавлена поддержка автоматического наполнения параметров для действий контроллера. В этой версии возможность была расширена на действия, описываемые в классах. Пример:

[php]
class UpdateAction extends CAction
{
	public function run($id)
	{
		// $id будет заполняться данными из $_GET['id']
	}
}

Прозрачная валидация на клиенте

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

Для реализации валидации на клиенте нет необходимости в дополнительном коде. Валидация работает на основе правил модели точно так же, как и валидация на стороне сервера.

Включить валидацию на клиенте можно выставив CActiveForm::enableClientValidation в true:

[php]
<?php $form=$this->beginWidget('CActiveForm', array(
	'enableClientValidation'=>true,
)); ?>

	<div class="row">
		<?php echo $form->labelEx($model,'username'); ?>
		<?php echo $form->textField($model,'username'); ?>
		<?php echo $form->error($model,'username'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'password'); ?>
		<?php echo $form->passwordField($model,'password'); ?>
		<?php echo $form->error($model,'password'); ?>
	</div>

	<div class="row buttons">
		<?php echo CHtml::submitButton('Login'); ?>
	</div>

<?php $this->endWidget(); ?>

Передача параметров реляционным именованным группам параметров

Теперь можно передавать параметры реляционным именованным группам параметров. К примеру, если имеется группа rated в модели Post, которая принимает параметром минимальный рейтинг записи, можно использовать это из модели User следующим образом:

[php]
$users=User::model()->findAll(array(
    'with'=>array(
        'posts'=>array(
            'scopes'=>array(
                'rated'=>5,
            ),
        ),
    ),
));

Использование 'through' с HAS_MANY и HAS_ONE

В Active Record добавлена поддержка опции through, которая позволяет строить отношения, подобные MANY_MANY, но более гибкие, позволяющие получение и использование данных из средней таблицы-моста.

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

Больше информации и примеров можно найти в соответствующем разделе руководства.

Использование транзакций в миграциях

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

Вместо реализации CDbMigration::up() и CDbMigration::down(), можно использовать CDbMigration::safeUp() и CDbMigration::safeDown(). После этого код будет обёрнут в транзакцию:

[php]
class m101129_185401_create_news_table extends CDbMigration
{
	public function safeUp()
	{
		$this->createTable('tbl_news', array(
			'id' => 'pk',
			'title' => 'string NOT NULL',
			'content' => 'text',
		));
	}

	public function safeDown()
	{
		$this->dropTable('tbl_news');
	}
}

Стоит отметить, что не все СУБД поддерживают транзакции.

Регистрация и использование своих пакетов скриптов

CClientScript теперь позволяет зарегистрировать и использовать свои пакеты скриптов. Ранее данная возможность использовалась исключительно для внутренних целей.

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

Работа с пакетами строится следующим образом: сначала в CClientScript::packages описываются нужные пакеты, а затем они регистрируются при помощи CClientScript::registerPackage().