本文目录导读:

在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的事件系统至关重要,有助于你写出更健壮的业务逻辑。