Laravel如何通过Trait实现带操作人标识的自定义时间戳通用逻辑
Laravel 自定义用户操作时间戳封装方案
完全可以通过 Trait 结合 PHP 魔术方法实现你需要的逻辑,无需重复编写相似代码,具体实现如下:
步骤1:创建通用 Trait
在 app/Traits 目录下新建 HasUserTimestamps.php 文件,代码如下:
<?php namespace App\Traits; use Illuminate\Support\Str; use App\Models\User; use Illuminate\Database\Eloquent\Relations\BelongsTo; trait HasUserTimestamps { public function __call($method, $parameters) { // 先判断模型是否配置了自定义操作列表 if (!isset($this->timestamps_with_users) || !is_array($this->timestamps_with_users)) { return parent::__call($method, $parameters); } foreach ($this->timestamps_with_users as $action) { $actionPast = Str::studly(Str::past($action)); $actionStudly = Str::studly($action); // 匹配设置操作:$model->finish() if ($method === $action) { $userId = $parameters[0] ?? auth()->id(); return $this->update([ "{$action}_by" => $userId, "{$action}_at" => now(), ]); } // 匹配撤销操作:$model->undoFinish() if ($method === "undo{$actionStudly}") { return $this->update([ "{$action}_by" => null, "{$action}_at" => null, ]); } // 匹配状态判断:$model->isFinished() if ($method === "is{$actionPast}") { return !empty($this->{$action.'_by'}) && !empty($this->{$action.'_at'}); } // 匹配用户关联:$model->finishedBy() if ($method === "{$actionPast}By") { return $this->belongsTo(User::class, "{$action}_by"); } } // 未匹配到对应方法,走原生逻辑 return parent::__call($method, $parameters); } }
步骤2:模型中使用 Trait
只需要在需要复用逻辑的模型中引入 Trait,配置自定义操作数组即可:
<?php namespace App\Models; use App\Traits\HasUserTimestamps; use Illuminate\Database\Eloquent\Model; class Post extends Model { use HasUserTimestamps; // 配置需要自动生成方法的操作名 protected $timestamps_with_users = [ 'finish', 'check', 'publish' ]; // 其他原有逻辑... }
Action 模型同理:
class Action extends Model { use HasUserTimestamps; protected $timestamps_with_users = [ 'finish' ]; }
使用示例
和你之前手写的方法调用逻辑完全一致,不需要修改原有业务代码:
// 设置操作 $post->finish(); // 支持手动传入用户ID,适配无登录态的控制台场景 $post->publish(1); // 撤销操作 $post->undoCheck(); // 状态判断 if ($post->isPublished()) { // 业务逻辑 } // 获取操作用户 $user = $post->finishedBy;
补充说明
- 需要提前在数据库表中创建对应字段,例如配置了
publish操作,就需要有publish_by和publish_at两个字段 - 如果遇到特殊词形变化(例如动词过去式不是加ed的情况),可以直接在模型中手动定义对应方法,手动定义的方法优先级高于魔术方法,不会被覆盖
内容的提问来源于stack exchange,提问作者Dirk Jan
相关产品推荐
相关产品推荐

