PHP项目Laravel模型事件触发时机

wen PHP项目 3

本文目录导读:

PHP项目Laravel模型事件触发时机

  1. 事件类型与触发时机
  2. 事件监听方式
  3. 注意事项和陷阱
  4. 实际应用示例

在Laravel中,模型事件(Model Events)是Eloquent提供的强大特性,允许你在模型生命周期的特定时刻执行代码,以下是各种模型事件的触发时机详细介绍:

事件类型与触发时机

创建(creating/created)

// creating:创建前
// created:创建后(已保存到数据库)
$user = new User;
$user->name = 'John';
$user->created_at = now(); // creating触发
$user->save(); // created触发

更新(updating/updated)

// updating:更新前
// updated:更新后
$user = User::find(1);
$user->name = 'Jane';
$user->save(); // updating和updated都会触发
// 注意:批量更新不会触发
User::where('status', 1)->update(['status' => 0]);

保存(saving/saved)

// saving:创建或更新前(先于creating/updating)
// saved:创建或更新后(后于created/updated)
$user = new User;
$user->name = 'Test';
$user->save(); // 顺序:saving → creating → created → saved
$user->email = 'new@email.com';
$user->save(); // 顺序:saving → updating → updated → saved

删除(deleting/deleted)

// deleting:删除前
// deleted:删除后
$user = User::find(1);
$user->delete(); // deleting和deleted都会触发
// 软删除也会触发
$user->delete(); // 如果是SoftDeletes,也会触发

恢复(restoring/restored)

// restoring:恢复前
// restored:恢复后
// 仅适用于软删除模型
$user = User::withTrashed()->find(1);
$user->restore(); // restoring和restored都会触发

强制删除(forceDeleting/forceDeleted)

// forceDeleting:强制删除前
// forceDeleted:强制删除后
$user = User::withTrashed()->find(1);
$user->forceDelete(); // forceDeleting和forceDeleted都会触发

事件监听方式

在模型类中直接定义

class User extends Model
{
    protected static function booted()
    {
        static::creating(function ($user) {
            if (empty($user->uuid)) {
                $user->uuid = Str::uuid();
            }
        });
        static::updating(function ($user) {
            $user->updated_by = auth()->id();
        });
        static::deleted(function ($user) {
            // 删除关联数据
            Log::info("User {$user->id} deleted");
        });
    }
}

独立事件类

// app/Events/UserCreated.php
class UserCreated
{
    public $user;
    public function __construct(User $user)
    {
        $this->user = $user;
    }
}
// 在模型中使用
protected static function booted()
{
    static::created(function ($user) {
        event(new UserCreated($user));
    });
}
// EventServiceProvider.php
protected $listen = [
    UserCreated::class => [
        SendWelcomeEmail::class,
        CreateUserProfile::class,
    ],
];

观察者模式

// app/Observers/UserObserver.php
class UserObserver
{
    public function creating(User $user)
    {
        $user->uuid = Str::uuid();
    }
    public function created(User $user)
    {
        // 创建后逻辑
    }
    public function updating(User $user)
    {
        // 更新前逻辑
    }
    public function updated(User $user)
    {
        // 更新后逻辑
    }
    public function saving(User $user) {}
    public function saved(User $user) {}
    public function deleting(User $user) {}
    public function deleted(User $user) {}
    public function restoring(User $user) {}
    public function restored(User $user) {}
    public function forceDeleting(User $user) {}
    public function forceDeleted(User $user) {}
}
// AppServiceProvider.php
public function boot()
{
    User::observe(UserObserver::class);
}

注意事项和陷阱

不会触发事件的操作

// ① 批量更新
User::where('age', '>', 18)->update(['status' => 2]);
// ② 直接使用DB
DB::table('users')->where('id', 1)->update(['name' => 'John']);
// ③ 复制的模型
$newUser = $existingUser->replicate();
$newUser->save(); // 只触发创建事件
// ④ forceFill + save 需要配合检查
$user->forceFill(['name' => 'John'])->save(); // 会触发保存事件

事件顺序

$user = User::create([...]);
// 实际执行顺序:
// 1. saving
// 2. creating  
// 3. created
// 4. saved
$user->update([...]);
// 实际执行顺序:
// 1. saving
// 2. updating
// 3. updated
// 4. saved

防止无限递归

// 在update中重复save会导致无限递归
static::updating(function ($user) {
    // ❌ 错误:这样会无限递归
    $user->name = strtoupper($user->name);
    $user->save();
    // ✅ 正确:直接修改属性,不需要再次save
    $user->name = strtoupper($user->name);
});

条件判断

static::updating(function ($user) {
    // 只在字段变更时执行
    if ($user->isDirty('password')) {
        // 密码变更了
    }
    // 检查原始值
    if ($user->getOriginal('status') == 1 && $user->status == 2) {
        // 状态从1变为2
    }
});

实际应用示例

class Order extends Model
{
    protected static function booted()
    {
        // 生成订单号
        static::creating(function ($order) {
            $order->order_no = 'ORD-' . date('YmdHis') . rand(1000, 9999);
        });
        // 更新库存
        static::created(function ($order) {
            foreach ($order->items as $item) {
                Product::where('id', $item->product_id)
                       ->decrement('stock', $item->quantity);
            }
        });
        // 记录操作日志
        static::updated(function ($order) {
            Log::info('Order updated', [
                'order_id' => $order->id,
                'changes' => $order->getChanges()
            ]);
        });
        // 取消订单时恢复库存
        static::deleting(function ($order) {
            if ($order->status == OrderStatus::CANCELLED) {
                Log::warning('Deleting order with status cancelled');
            }
        });
    }
}

理解这些触发时机对于正确使用Laravel的事件系统至关重要,有助于你写出更健壮的业务逻辑。

抱歉,评论功能暂时关闭!