常用底层知识 - 过滤器

  • 作者:KK

  • 发表日期:2017.1.27


过滤器通常用于自动检测“用户的这次请求能不能运行控制器的方法”,这种情况经常出现在登录检测、权限检测和活动期的检测需求中。


创建过滤器

比如有一个用于处理打折活动逻辑的控制器,你希望10月1号到7号期间可以访问,7号以后就不允许访问了,那么就可以先定义一个过滤器返回 true/false 告诉底层能否运行这个控制器的方法。

先创建一个过滤器,比如我这样:

namespace app\lib;

class MyFilter extends \yii\base\ActionFilter {

	//重写父类的beforeAction方法,返回true/false以通知是否能执行控制器方法
	public function beforeAction($action) {
		$_10月1号的时间戳的时间戳'Y-10-1'));
		$_10月7号的时间戳的时间戳'Y-10-7'));
		
		$不是国庆节$_10月1号的时间戳的时间戳$_10月7号的时间戳的时间戳

其中过滤器都要继承 yii\base\ActionFilter 重写 beforeAction 方法并返回一个 boolean 值。


使用过滤器

定义好了过滤器就要使用它了,办法是在控制器重写父类的“behaviors”方法,返回值是一个数组,结构大概如下:

public function behaviors(){
	return [
		'my_filter123' => [	//这个key是自己起的名字,因为可以产生多个过滤器,键名是识别它们的唯一标识,其实也可以不要这个key

			'class' => 'app\lib\MyFilter'
		],
	];
}

意思就是说定义一个叫“my_filter123”的过滤器,这个过滤器是通过“app\lib\MyFilter”这个类来实现的。

然后运行一个 HTTP 请求,底层就会自动调用这个类里面的 beforeAction 方法获取一个 true/false 了,如果返回 false ,画面将会一片空白,因为无法执行控制器方法,请求被停止了。

可是显示白屏确实不是什么好事,应该给点东西反馈给用户,所以可以设置 response 组件的 data 属性来实现输出:

if ($不是国庆节$app->response->data = '抱歉,本场活动只在国庆期间开放哦';
	return false;
}

配置化

上面我们定义了一个国庆时间才开放的过滤器,其实基于时间来确认是否要执行控制器方法,这种需求偶尔也会有其它的控制器也用得上的。

所以其实我们可以优化这个过滤器实现重复利用而不是某个控制器才适用,比如A控制器要国庆期间用,B控制器要中秋期间用,但定义两个 filter 类不靠谱,逻辑都一样的嘛,咱可以改造成下面这样子:

class MyFilter extends \yii\base\ActionFilter {
	public $startTime = '';
	public $endTime = '';
	public $closeMessage = '抱歉,这段时间内暂时关闭访问';

	public function beforeAction($oAction) {
		$startTime = strtotime($this->startTime);
		$endTime = strtotime($this->endTime);
		$now = time();
		
		if ($now < $startTime || $now > $endTime) {
			Yii::$app->response->data = $this->closeMessage;
			return false;
		} else {
			return true;
		}
	}
}

然后控制器的behaviors方法就返回

[
	'my_filter123'	=> [
		'class' => 'app\lib\MyFilter',
		'startTime' => '2017-10-1',
		'endTime' => '2017-10-7',
	],
]

这样子不同的控制器使用这个过滤器时就可以自己定义开始和结束时间,即可让这个过滤器变得可重复利用。


题外话

通常在大多数普通程序员接触的项目中,过滤器的用途基本就是做用户登录检测,后面有关于用户登录的专题文章,我在里面会提到使用过滤器做登录检测。