подскажите, народ — как фильтр может предотвратить выполнение следующих за ним фильтров?
текст мануала =
Действие может иметь множество фильтров.
Фильтры запускаются в том порядке, в котором они указаны в списке фильтров,
при этом фильтр может предотвратить выполнение действия и
следующих за ним фильтров.
class RightsFilter extends CFilter
.......
protected function preFilter($filterChain){
.....
if( $allow===false )
{
$controller->accessDenied();
return false;
}
}
....
//controller
public function accessDenied($message=null){
.....
throw new CHttpException(403, $message);
}
итого получаем фильтр контроля доступа, если доступ не разрешен показываем еррор 403.
Также реализованы и стандартные фильтры. Их если не ошибаюсь 3 (postOnly,ajaxOnly,accessControl).
Вот например ajaxOnly:
public function filterAjaxOnly($filterChain)
{
if(Yii::app()->getRequest()->getIsAjaxRequest())
$filterChain->run();
else
throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
}
Надеюсь это прояснит ситуацию, так как в вики фильтры как-то скудно описаны, но на самом деле очень мощная штука.
Допишите в виде методов в контроллере. Приатачьте к фильтрам. Собственно
$filterChain->run();
запускает цепочку (но он нужен для запуска и текущего фильтра в частности). Организуйте эти фильтры в виде
public function filterMyfilter($filterChain)
if($some_filter_pass)
$filterChain->run();
else {
throw new CHttpException($code,$message); // ну а зачем фильтр без ошибки))
return false;
}
return true;
//добавим в фильтр к контроллерам
public function filters()
{
return array(//указывайте фильтры в нужной вам последовательности
'myfilter',...
);
}
Не переживайте, если 1 фильтр завалится дальше по цепочке мы не можем пойти никак (при данном исполнении).
Не совсем так. Если вы пошли этим путем в контроллере в компонентах сделайте:
public function filterRequired($filterChain)
{
$filter = new RequiredFilter;
//можете передать то что вам нужно $filter->_required=$this->required
$filter->filter($filterChain);
}
Далее тут же в компонентах сделайте файл RequiredFilter:
class RequiredFilter extends CFilter
{
protected $_required = array();//то что вы передали например
protected function preFilter($filterChain)
{
//делайте тут то что вам нужно
// можете делать в postFilter
}
}
В контроллерах в папке protected/controllers
class ZController extends MyControllerWithFilterController
{
public function filters()
{
return array(
array(
'required',//ваш фильтр
),
);
}
}
ну то есть это публичный метод filterRequired из родительского контроллера расположенного в директории components?
а с чем связана такая цепочка: создать фильтр, в родительском классе создать его экземпляр и вызвать (ведь $filter->filter($filterChain) это аналог $filterChain->run()?) и уже после этого в дочернем классе получить доступ к методу в родительском классе?
Да это тот самый метод (также как например actionIndex начинается с action).
Ну собственно у вас ведь может быть не 1 фильтр, и не 2. В разных контроллерах возможно придется использовать разные фильтры(ну или разные последовательности). Про $filter->filter($filterChain), это практически тоже, но не совсем . Вот что нам говорят исходники:
public function filter($filterChain)
{
if($this->preFilter($filterChain))
{
$filterChain->run();
$this->postFilter($filterChain);
}
}
То есть так мы делаем триггер фильтров которые мы уже переписали (независимо это пост или пре фильтры). В данном контексте это правильнее.
Ну это мое понимание работы с фильтрами, возможно у вас оно немного отличается. Делайте так как удобно.