记录laravel orm trait加载小技巧

因为某些时候需要在很多model里面加入一些保存前保存后的事件
比如

  • created_by updated_by 字段自动维护

这种情况头一次想的是用 observer
或者直接监听 model 保存新增事件

机缘巧合下看到一篇文章 关于laravel orm加载trait的技巧 原文

实现方案

// app/Model/Traits/UserStamps
trait Usertamps{
        public static function bootUserStamps()
        {
            static::creating(function (Model $model) {
                // 设置 created_by 字段的值为当前登录的用户ID
                $model->created_by = auth()->id();
            });

            static::updating(function (Model $model) {
                // 设置 updated_by 字段的值为当前登录的用户ID
                $model->updated_by = auth()->id();
            });
        }
}

这样只需要在用到的model直接use这个类即可。

大概语法是

  • initializeUserStamps 每次实例化新模型的时候都会调用
  • bootUserStamps 这个应该是类似与 model::booted()里面执行
本作品采用《CC 协议》,转载必须注明作者和本文链接
终不似少年游
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 19
sanders

实际业务场景里面不建议这样用,原因在于 auth() 是根据请求鉴权结果获取的数据,以下3种情况无法通过 auth() 获取授准确的权信息:

  1. 未授权请求;
  2. 队列任务中;
  3. 定时任务调度或命令行执行;

所以这样做并不能稳定获取授权信息,我们这样处理以上问题:

  1. 业务逻辑层单独封装;
  2. 控制器将授权用户ID传入业务逻辑层方法;
  3. 队列任务负载数据中保存发起用户的ID;
  4. 命令行或任务调度有关联的用户数据,或默认执行的系统用户;

至于 trait 在模型方面的用法,确实有很多可发挥的余地,比如公共的模型关系:

// 存在创建用户的都可以通过这个特性获取该模型关系
trait HasCreatedBy {
    // 只封装这一个方法,因为有些模型可能没有更新用户,这样可以增加适配性
    public function createdBy (): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }
    // 增加一个本地作用域 byCreatorId($userId) 方法用来根据创建用户ID查询本模型数据
    public function scopeByCreatorId (Builder $query, int $userId)
    {
        $query->whereHas('createdBy', fn ($query) => $query->where('id',$userId));
    }
}

类似的场景还比如有,是否关联品类 或 三级行政区 等等。

1个月前 评论
DeathSatan (楼主) 1个月前
DeathSatan (楼主) 1个月前
sanders

实际业务场景里面不建议这样用,原因在于 auth() 是根据请求鉴权结果获取的数据,以下3种情况无法通过 auth() 获取授准确的权信息:

  1. 未授权请求;
  2. 队列任务中;
  3. 定时任务调度或命令行执行;

所以这样做并不能稳定获取授权信息,我们这样处理以上问题:

  1. 业务逻辑层单独封装;
  2. 控制器将授权用户ID传入业务逻辑层方法;
  3. 队列任务负载数据中保存发起用户的ID;
  4. 命令行或任务调度有关联的用户数据,或默认执行的系统用户;

至于 trait 在模型方面的用法,确实有很多可发挥的余地,比如公共的模型关系:

// 存在创建用户的都可以通过这个特性获取该模型关系
trait HasCreatedBy {
    // 只封装这一个方法,因为有些模型可能没有更新用户,这样可以增加适配性
    public function createdBy (): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }
    // 增加一个本地作用域 byCreatorId($userId) 方法用来根据创建用户ID查询本模型数据
    public function scopeByCreatorId (Builder $query, int $userId)
    {
        $query->whereHas('createdBy', fn ($query) => $query->where('id',$userId));
    }
}

类似的场景还比如有,是否关联品类 或 三级行政区 等等。

1个月前 评论
DeathSatan (楼主) 1个月前
DeathSatan (楼主) 1个月前
Tomo11111

其实创建时间和更新时间框架会自动维护的, 如果是字段和框架默认的 created_at 不同,那只需要在模型中修改 CREATED_AT 和 UPDATED_AT 的值即可。

1个月前 评论
Cooper 1个月前

并不实用,也不推荐这种做法trait 的作用是实现代码复用,而不是逻辑复用,created_by 字段还是推荐在控制器注入,observer也不适合这个例子,observer适合一些事件,比如创建用户同步创建用户扩展,修改用户同步修改用户扩展

1个月前 评论
DeathSatan (楼主) 1个月前
DeathSatan (楼主) 1个月前
DeathSatan (楼主) 1个月前
sanders 1个月前
DeathSatan (楼主) 1个月前
DeathSatan (楼主) 1个月前
sanders 1个月前
DeathSatan (楼主) 1个月前
Imuyu (作者) 1个月前
Imuyu (作者) 1个月前
DeathSatan (楼主) 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!