You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 22:36:02