菜鸟常忽略的基础 - 覆盖过滤器 ¶
作者:KK
发表日期:2016.10.11
带key的写法不影响运行 ¶
过滤器可以有多个,所以控制器的behaviors
方法可以返回多个过滤器:
public function behaviors()
{
return [
[
'class' => '过滤器1的class',
],
[
'class' => '过滤器2的class',
],
];
}
返回一个大数组,大数组里的元素都是数组,这些数组每个都是一个过滤器。
这经常会给菜鸟带来一种错觉:过滤器就是这样写的了!?数组里面包含几个小数组就是多少个过滤器**
对!然而其实可以这样写的:
public function behaviors()
{
return [
[
'class' => '过滤器1的class',
],
'name2' => [ // 这行是重点,加了个 name2 的key
'class' => '过滤器2的class',
],
];
}
其中第2个过滤器是带有key的,叫“name2”,那这样会不会报错呢?不会哦!告诉你底层怎么大概怎么执行过滤器的:
foreach($controller->behaviors() as $filterConfig){
$filter = Yii::createObject($filterConfig);
if($filter->run() == false){
return false;
}
}
return true;
大概是这样的意思啦,所以,有没有key人家都在foreach遍历,不会造成影响
然而带key是有好处的 ¶
虽然给过滤器定义key对底层的foreach处理毫无影响,但我认为这也是Yii留给我们的一个扩展余地,试想有这样的情况:
项目有
app\lib\BaseController
这个自定义的控制器基类项目90%的控制器都继承了BaseController
BaseController定义了一个通用的登陆验证过滤器,代码如下:
public function behaviors(){ return [ [ 'class' => AccessControl::className(), 'only' => ['index', 'login', 'register'], 'rules' => [ //登陆用户 [ 'allow' => true, 'roles' => ['@'], ], ], ], ]; }
UserController想只开放index,login,register三个方法,但其它方法还是要登陆后才能访问
此时如果User控制器这样写就会显得与Base控制器有点重叠冗余,而且并不优雅:
public function behaviors(){ return [ [ 'class' => AccessControl::className(), 'only' => ['index', 'login', 'register'], 'rules' => [ //登陆用户 [ 'allow' => true, 'roles' => ['@'], ], //游客 [ 'allow' => true, 'actions' => ['index', 'login', 'register'], 'roles' => ['?'], ], ], ], ]; }
其实有这样一个折衷的办法:
public function behaviors(){ $behaviors = parent::behaviors(); $behaviors[0]['rules'][] = [ 'allow' => true, 'actions' => ['index', 'login', 'register'], 'roles' => ['?'], ]; return $behaviors; }
看似优雅不少,不用重复定义已经定义过的东西,只需要追加新的规则需求。那如果Base控制器有多个过滤器呢?你要保证第0个元素就是登陆认证的过滤器吗?
其实如果Base控制器是这样的就好了,给过滤器定义一个key:
public function behaviors(){
return [
'access' => [过滤器配置]
];
}
这个key叫access或叫name1、nameX什么都可以,就是自己起的名字,反正底层是foreach不管你,但User控制器可以这样来合成配置:
public function behaviors(){
return \yii\helpers\ArrayHelper(parent::behaviors(), [
'access' => [
'rules' => [
[
'allow' => true,
'actions' => ['index', 'login', 'register'],
'roles' => ['?'],
],
]
],
]);
}
由于parent::behaviors返回的数组中带access,所以被ArrayHelper合并掉了,合并时由于里面是索引数组,所以就追加了元素到原有的rules里
所以这里有一个不显眼的细节不知你有没有注意到,官方演示过滤器的章节里,就给登陆认证过滤器增加了access这个key