[Yii2.0 TimestampBehavior]

应用场景:   在我们的Model开发中, 当你添加或者修改一条数据时, 你会发现很多都会涉及到创建时间和修改时间. 例如: 我们插入数据要添加"创建时间, 修改时间", 更新数据时要更新"修改时间". 那么多数据表的操作都重复涉及, 你会不会发现太麻烦了? 下面我就介绍一种时间戳行为, 他可以自动对某些字段进行修改的行为

下面是我的一个model类中, 使用到了行为behaviors, 代码如下:
一种: 当你的表中的创建时间和修改时间命名是created_at,updated_at时, 我们重写下面的behaviors()来实现上述行为

use yii\behaviors\TimestampBehavior;
 
/**
 * 创建时间/修改时间
 */
public function behaviors()
{
    return [
        TimestampBehavior::className(),       // 匿名的行为,仅直接给出行为的类名称
    ];
}

第二种: 当你的表中的创建时间和修改时间命名不是created_at,updated_at时,你可以使用下面这种方式进行重写behaviors()来实现上述行为
use yii\db\Expression;
 
 public function behaviors()
 {
     return [
         [
             'class' => TimestampBehavior::className(),
             'createdAtAttribute' => 'create_time',  //此时以create_time/update_at为例,实际情况可根自己表中字段名为主
             'updatedAtAttribute' => 'update_time',
         ],
     ];
 } 

就上面的一个方法,我们就是实现了: 关于添加一条数据中的"创建时间, 更新时间" 和 更新一条数据中的"修改时间", 只需在对应的model里面使用此方法, 那么你在添加或者修改数据时, 都不用再管创建时间和修改时间的事儿了, 他会自动进行添加创建时间和修改时间了.


下面我们来说说原因:

使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充。 通过将行为绑定到一个类,可以使类具有行为本身所定义的属性和方法,就好像类本来就有这些属性和方法一样。 而且不需要写一个新的类去继承或包含现有类。

Yii自带的 yii\behaviors\AttributeBehavior 类,定义了在一个 ActiveRecord 对象的某些事件发生时, 自动对某些字段进行修改的行为。 他有一个很常用的子类yii\behaviors\TimeStampBehavior 用于将指定的字段设置为一个当前的时间戳。 常用于表示最后修改日期、上次登陆时间等场景。我们以这个行为为例,来分析行为响应事件的原理。

yii\behaviors\AttributeBehavior::events() 中,代码如下:

public function events()
{
    return array_fill_keys(array_keys($this->attributes),
        'evaluateAttributes');
}

这段代码将返回一个数组,其键值为 $this->attributes 数组的键值, 数组元素的值为成员函数evaluateAttributes

 

而在 yii\behaviors\TimeStampBehavior::init() 中,有以下的代码:

public function init()
{
    parent::init();
 
    if (empty($this->attributes)) {
        // 重点看这里
        $this->attributes = [
                    BaseActiveRecord::EVENT_BEFORE_INSERT => [$this->createdAtAttribute, $this->updatedAtAttribute],
                    BaseActiveRecord::EVENT_BEFORE_UPDATE => $this->updatedAtAttribute,
        ];
        上面等价于:
        $this->attributes = [
                    BaseActiveRecord::EVENT_BEFORE_INSERT => [created_at, updated_at],
                    BaseActiveRecord::EVENT_BEFORE_UPDATE => updated_at,
        ];
    }
}

上面的代码重点看的是对于 $this->attributes 的初始化部分。 结合上面2个方法的代码,对于 yii\behaviors\AttributeBehavior::event()的返回数组,其格式应该是这样的:
return [
    BaseActiveRecord::EVENT_BEFORE_INSERT => 'evaluateAttributes',
    BaseActiveRecord::EVENT_BEFORE_UPDATE => 'evaluateAttributes',
];
数组的键值用于指定要响应的事件, 这里是 BaseActiveRecord::EVENT_BEFORE_INSERTBaseActiveRecord::EVENT_BEFORE_UPDATE 。 数组的值是一个事件handler,如上面的 evaluateAttributes


那么一旦TimeStampBehavior与某个ActiveRecord绑定,就会调用 yii\behaviors\TimeStampBehavior::attach() , 那么就会有:  

// 这里 $owner 是某个 ActiveRecord
public function attach($owner)
{
    $this->owner = $owner;
 
    // 遍历上面提到的 events() 所定义的数组
    foreach ($this->events() as $event => $handler) {
 
        // 调用 ActiveRecord::on 来绑定事件
        // 这里 $handler 为字符串 `evaluateAttributes`
        // 因此,相当于调用 on(BaseActiveRecord::EVENT_BEFORE_INSERT,
        // [$this, 'evaluateAttributes'])
        $owner->on($event, is_string($handler) ? [$this, $handler] :
            $handler);
    }
}

上面的代码干了两件事:

  • 设置好行为的 $owner ,使得行为可以访问、操作所依附的对象
  • 遍历行为中的 events() 返回的数组,将准备响应的事件,通过所依附类的 on() 绑定到类上

因此,事件 BaseActiveRecord::EVENT_BEFORE_INSERTBaseActiveRecord::EVENT_BEFORE_UPDATE 就绑定到了ActiveRecord上了。当新建记录或更新记录时,TimeStampBehavior::evaluateAttributes 就会被触发。 从而实现时间戳的功能,

 例如:  当记录插入时,行为将当前时间戳赋值给 created_at 和 updated_at 属性;

           当记录更新时,行为将当前时间戳赋值给 updated_at 属性。

保存对象,将会发现它的 created_at 和 updated_at 属性自动填充了当前时间戳

具体可以看看 yii\behaviors\AttributeBehavior::evaluateAttributes()yii\behaviors\TimeStampBehavior::getValues() 的代码

/**
 * Evaluates the attribute value and assigns it to the current attributes.
 * @param Event $event
 */
public function evaluateAttributes($event)
{
    if (!empty($this->attributes[$event->name])) {   //例如我当前是插入操作,那么$event->name 就等于 'beforeInsert';
        $attributes = (array) $this->attributes[$event->name];
        $value = $this->getValue($event);
        foreach ($attributes as $attribute) {
            // ignore attribute names which are not string (e.g. when set by TimestampBehavior::updatedAtAttribute)
            if (is_string($attribute)) {
                $this->owner->$attribute = $value;
            }
        }
    }
}

/**
 * @inheritdoc
 */
protected function getValue($event)
{
    if ($this->value instanceof Expression) {
        return $this->value;
    } else {
        return $this->value !== null ? call_user_func($this->value, $event) : time();
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值