最近到新公司了,然后,这边虽然使用Yii框架,不过,居然没有使用filter或者其他的功能,而所有的验证代码都堆在了beforeAction,相信有点经验的开发者都知道,这是致命性的,不可持续的。现在beforeAction已经有250行左右了。再这么发展半年,后面的开发就会很难进行下去。所以,这是一个拆分解耦的过程。
因为系统是商业系统,涉及到钱的都很敏感,另外慢也不要快。所以,不可能一下子上RBAC的功能。只能先用filter。目前代码的情况是,所有的Controller都基于一个父类也就是自己写得Controller。然后,现在有一个小困难,就是,如何我修改的代码上线了,不对其他久的代码有影响?
这个实际上很简单,我再写一个父类DController,然后,新的代码可以继承这个父类,而久的代码就没有影响了。
然后,这里详细说下filter的使用方法和代码详解。
入门级的使用,请看官方文档。
然后,我们看下背后是如何实现的:
一、一个GET请求进来之后,会经过下面的代码
这也是一个调试的好技巧,在代码的某个地方,抛个异常,就能够看到执行栈了。
详细的过程,我就不多说了。说一下重点,就是上面截图中的第4步、第3步、第2步。
在第4步,程序回去获取filters,如果有的话,就会在CController.php的282行,创建执行链。如下图:
然后,就会在CFilterChain里面,使用职责链模式。这些都是比较简单的。我们真正关心的是下面的问题:
我有A、B、C、D、E五个filter,也就是 filterA($filterchain)之类的。然后,可以有以下组合的filters:我们需要搞明白,Yii框架会如何执行这些filters:
第一种,filters为空的场景:
public function filters(){
return array();
}
有可能,有的人会认为,空的话,就会执行全部。 实际上,看代码的话,是没有的。那一句emtpy就判断了。
第二种,正常的filters的场景:
public function filters(){
return array(
'A - index, login, logout',
'B + download, check',
);
}
这是最常见的场景,让我们看看代码是如何解决的:在CFilterChain.php的Create函数和run函数。
代码详解:
看注释,我们能知道,这是一个filterChain的工厂类,会根据我们传进去的参数,返回一个实体类。
代码中的逻辑是这样的:根据传进去的filters,然后,foreach其中的每个数据,判断其类型是string、数组。
如果是string,那么会先判断filter是否有+或者-,而判断的标准就是,当前的action是否在filter中。如果,当前访问的actionid正好在某个有+的filter,那么就会创建一个CInlineFilter::create的filter。
最后,符合规则的filter都会被加到chain中。
至此,一个完整的chain就OK了。然后,就会开始执行这个链,执行完之后,就会去执行action了。
这里面,有对几个设计模式的应用:1.职责链设计模式;2.迭代器设计模式。有兴趣,可以研究研究。
到这里,我们对filter的代码就研究透彻了~ 现在写几点注意点:
1.一个空的filters,就会什么filters都不执行;
2.对于+的,只要在后面的方法列表上,那么就会被执行;
3.对于-的,只要出现在上面,就不会被执行。
4.请不要挑战代码的健壮性,因为作者没有判断多个+之类或者你能想到的奇葩情况。。所以,规规矩矩的用吧。。
好了,到这里就,filter我们就研究明白了。可以达到以下的目标:
单个模块的权限控制,而且能够达到灵活的,组装和复用。通过创建不同的Controller,就可以定义不同的组或者角色。
不过,现在离企业级的权限管理,有一定的距离。
差距就在于:
1.随着业务的发展,我们的action和filter就会越来越多。而且,会频繁的修改代码。这将会对代码的维护性,产生很大的影响。另外,修改成本也会越来越大。
2.多模块化之后,跨模块的管理,会越发的复杂。
所以,到这一步,我们就要考虑正宗的RBAC了。很憧憬这种环境下的开发~~ 不过,我这边还没达到,先做好第一步吧,把filter给弄好。
我接下去的目标是,把SRbac给弄好。。搞定之后,就要弄一个中心控制的SRbac。这个时候,真的就是企业级别了~~~ 嘿嘿~
如有欠缺,欢迎讨论~~~