Yii2的行为和事件

首先,事件和行为是yii2框架下,组件类才拥有的功能。而组件类,即是yii\base\Component 类或其子类的实例。所以,yii2框架下,大部分的类都可以使用事件和行为。

什么是事件

事件是给指定实例或类绑定一个回调函数,在需要的时候,使用trigger调用即可。

yii\base\Controller有内置的beforeAction、afterAction方法;
BaseActiveRecord内置的有afterFind,beforeInsert,afterInsert等方法
yii\base\Model有beforeValidate、afterValidate等方法;
这些方法中,使用trigger调用了和方法名相同的事件。如果没有找到绑定的事件,则不执行。

使用事件的3种方式

如何让一个对象执行事件呢?有三种方法

1、覆盖类中内置的调用事件的方法

上面列举了几种基类内置的调用绑定事件的方法。我们可以在子类中重写这些方法,在方法中书写我们想要执行的代码即可。这样跳就跳过了先绑定事件,在用tigger调用的步骤,简单粗暴

class user extends ActiveRecord{
	public function beforeSave(){
		$this->updated_at = time();
	}
}

beforeSave是user祖先类中内置的,在保存数据前调用的方法。在祖先类中,该方法内使用tigger调用绑定的
beforeSave事件。
而我们在上面的代码中,重载了祖先类的beforeSave()方法,使用自定义代码实现了beforeSave

2、使用on绑定事件

class user extends ActiveRecord{}
$user = new user();
$user->on('beforeSave',function()use($user){$user->updated_at = time()});
$user->save();

3、使用行为

我们看到,前两个方法虽然简单直接,但是有一个弊端,就是不能代码复用。如果有很多model都需要自动插入更新时间的话,就需要在所有model下都重复编写beforeSave方法。

这个时候行为就派上用场了

行为类,类似一个Trait。当一个类引入一个行为类后,就可以使用行为类中的属性和方法。
同时,行为类提供了一个events()方法,用以绑定事件

//建立一个行为类
class AutoTimeBehavior extends Behavior{

    public function events(){
        return [
            'beforeSave' => 'setUpdateTime',
            'mine' =>'formatResult',
        ];
    }
    //实现绑定到事件的方法
    //$event是一个Event对象,表示当前调用事件对象,包含事件名称等信息
    public function setUpdateTime($event){
		//验证前执行的事件
		//$this->owner 是调用当前行为的model或controller对象,可以直接调用对象中的属性和方法
		$this->owner->updated_at = time();
	}
    public function formatResult(){
   		//我的自定义事件
	}
 }

使用行为类

class user extends ActiveRecord{
	public function behaviors(){
		return array_merge(parent::behaviors(),[
            ['class' => 'AutoTimeBehavior'],
        ]);
	}
}
$user = new user();
$user->tigger('mine');
$user->save();

行为中绑定的beforeSave事件,会被user中的内置方法调用。而mine事件因为没内置方法调用,所以需要我们在外部自行调用。也可以在user类或祖先类中,在合适的位置使用tigger调用自定义事件

Yii2预定义的一些行为

我们只要在控制器中设施好这些行为,不需要在代码中自己去执行,框架在运行时,会自动在预定义这些行为的位置执行相关的方法。

控制器行为

public function behaviors(){
        $behaviors = parent::behaviors();
        //设置跨域请求相关,一般用在接口类控制器接口的基类中
        $behaviors['cors'] = [
            'class' => \tesoon\filters\Cors::className(),
            'cors' => [
            	//设置允许跨域请求的域名,*表示不限
                'Origin' => ['*'],
                //设置允许的请求方式,*表示不限
                'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
                /*
                浏览器的同源策略,就是出于安全考虑,浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),
                所以浏览器会向所请求的服务器发起两次请求,第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,
                第一次的预检请求获知服务器是否允许该跨域请求:如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。
                Access-Control-Max-Age用来指定本次预检请求的有效期,单位为秒,在此期间不用发出另一条预检请求。
                等于0时,表示每次异步请求都发起预检请求
                */
                'Access-Control-Max-Age' => 86400,
                'Access-Control-Request-Headers' => ['*'],
                'Access-Control-Allow-Credentials' => true,
                'Access-Control-Expose-Headers' => ['*'],
                'Access-Control-Allow-Headers' => ['*']
            ],
        ];
        //身份验证
        $behaviors['authenticator'] = [
            'class'=>QueryParamAuth::class,
        ];
        //接口速率限制
        $behaviors['rateLimiter'] = [
            'class' => RateLimiter::className(),
        ];
        //设置控制器返回数据格式,也可以在config中设置
        $behaviors['contentNegotiator'] = [
                'class' => ContentNegotiator::className(),
                'formats' => [
                    'application/json' => Response::FORMAT_JSON,
                ],
            ];
		//设置控制器下,方法的执行权限
		//目前很少用到,对于需登录进行的操作,一般在身份认证时,即可阻断,不需要在这里设置
		 $behaviors['access'] = [
			'class' => AccessControl::className(),
            'only' => ['index', 'create', 'update'],
            'rules' => [
                // 允许认证用户
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // 禁止游客用户执行
                [
                        'allow' => true,
                        'actions' => ['logout'],
                        'roles' => ['@'],
                ],
            ], 
		];
         //过滤当前控制器下,方法允许的请求方式   
         $behaviors['verbFilter'] = [
             'class' => VerbFilter::className(),
             'actions' => [
                 'index' => [ 'get'],            //只允许get方式访问
                 'create' => [ 'post'],          //只允许用post方式访问
                 'update' => [ 'post']
             ],
         ];
        return $behaviors;
    }

模型行为

public function behaviors() {
        return [
        	//匿名行为,自动添加更新时间戳字段
            [
                'class' => \yii\behaviors\TimestampBehavior::className(),
                'attributes' => [
                    self::EVENT_BEFORE_INSERT => ['create_time','update_time'],
                    self::EVENT_BEFORE_UPDATE => ['update_time'],
                ],
            ],
        ];
    }

yii\behaviors\AttributeBehavior: 当某些事件发生时, 将指定的值自动分配给 AR 对象的一个或多个属性.
yii\behaviors\TimestampBehavior: 使用当前时间戳自动填充指定的属性.
yii\behaviors\BlameableBehavior: 使用当前用户ID自动填写指定的属性.
yii\behaviors\SluggableBehavior: 自动使用一个可以在 URL 中使用的值来填充指定的属性.
yii\behaviors\AttributeTypecastBehavior: 提供模型属性类型的自动转换功能

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值