lavarel 模型事件 Observer 观察者模式

简介

Laravel中的事件与监听使用的了观察者模式,观察者模式可以做到优雅的处理一连串的动作,动态的增加和减少动作,而不用去改变主线业务代码。事件类通常存放在app/Events目录中,而这些事件类的监听器则存放在 app/Listeners 中。是应用中实现解耦的非常的好的一种方法。例如:当用户在应用中使用会员权益购买一样商品,在购买时,需要消耗用户相应的剩余权益。这时候你就使用监听可以把订单生成和权益消耗区分开。

一、监听者模式和观察者模式的区别

参考: 前人栽树、后人乘凉1:观察者模式和监听者模式

二、数据库模型事件了解

Laravel 事先已经定义好了 10多 个模型事件以供我们使用,它们分别是:

  public function getObservableEvents()
    {
        return array_merge(
            [
                'retrieved', 'creating', 'created', 'updating', 'updated',
                'saving', 'saved', 'restoring', 'restored', 'replicating',
                'deleting', 'deleted', 'forceDeleted',
            ],
            $this->observables
        );
    }

这些事件名称都很浅显易懂。具体使用可以打开**Illuminate\Database\Eloquent\Model ,**找到save()方法:

    public function save(array $options = [])
    {
        $query = $this->newModelQuery();

        // If the "saving" event returns false we'll bail out of the save and return
        // false, indicating that the save failed. This provides a chance for any
        // listeners to cancel save operations if validations fail or whatever.
        if ($this->fireModelEvent('saving') === false) {
            return false;
        }

        // If the model already exists in the database we can just update our record
        // that is already in this database using the current IDs in this "where"
        // clause to only update this model. Otherwise, we'll just insert them.
        if ($this->exists) {
            $saved = $this->isDirty() ?
                        $this->performUpdate($query) : true;
        }

        // If the model is brand new, we'll insert it into our database and set the
        // ID attribute on the model to the value of the newly inserted row's ID
        // which is typically an auto-increment value managed by the database.
        else {
            $saved = $this->performInsert($query);

            if (! $this->getConnectionName() &&
                $connection = $query->getConnection()) {
                $this->setConnection($connection->getName());
            }
        }

        // If the model is successfully saved, we need to do a few more things once
        // that is done. We will call the "saved" method here to run any actions
        // we need to happen after a model gets successfully saved right here.
        if ($saved) {
            $this->finishSave($options);
        }

        return $saved;
    }

可以看到首先触发的是 saving:

$this->fireModelEvent('saving')

接着会判断此 model 是不是新创建的。

如果是新创建的,执行 $saved = $this->performInsert($query);进行 insert 操

作,否则执行$saved = $this->isDirty() ? $this->performUpdate($query) : true;先判

调用 isDirty 方法判断此 model 是否进行了修改。

如果进行了修改,那么会调用 performUpdate 方法进行更新操作,如果没有进行修改,则直接返回 true。

performUpdate /performInsert 方法执行以后,可以看到 Laravel 最后做了一个判断:if ($saved) {$this->finishSave($options)};

在 update/insert 成功的情况下,会触发 finishSave() 方法,此方法会接收一个参数 $options, 即是修改的属性。

之后就是finishSave()方法,里面时:

    protected function finishSave(array $options)
    {
        $this->fireModelEvent('saved', false);

        if ($this->isDirty() && ($options['touch'] ?? true)) {
            $this->touchOwners();
        }

        $this->syncOriginal();
    }

可以看到在此方法内会触发 saved 事件;

也就是说:

  • 当模型已存在,不是新建的时候,依次触发的顺序是:
    saving -> updating -> updated -> saved
  • 当模型不存在,需要新增的时候,依次触发的顺序是:
    saving -> creating -> created -> saved
三、观察者模式使用
1、生成文件
  • 执行命令 生成文件
    php artisan make:observer SrtVideoTranslateTaskObserve --model=SrtVideoTranslate
2、注册观察者

修改EventEventServiceProvider

    public function boot()
    {
        parent::boot();

        SrtVideoTranslate::observe(SrtVideoTranslateTaskObserve::class);//新增的
    }

或者在AppServiceProvider里注册

2、完善SrtVideoTranslateTaskObserve的逻辑
<?php

namespace App\Observers;

use App\Models\SrtVideoTranslate;
use App\Services\TranslateEvents\SrtVideoTranslateStatusChange;

class SrtVideoTranslateTaskObserve
{
    public function saved(SrtVideoTranslate $task)
    {
        info(123456789);
        info(json_encode($task));
        if ($task->project_id !== "web") {
            return;
        }
//        if (!$task->isDirty("status")) {
//            return;
//        }

        if ($task->status === SrtVideoTranslate::TASK_STARTED) {
            SrtVideoTranslateStatusChange::started($task);//这里是扣除用户会员权益的逻辑
        } else if ($task->status === SrtVideoTranslate::TASK_ERROR) {
            SrtVideoTranslateStatusChange::failed($task);//这是恢复用户已扣除会员权益的逻辑
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值