本文目录导读:

在 PHP 中,模型事件主要与 ORM(对象关系映射)框架相关,最常见的框架是 Laravel Eloquent,我将以 Laravel 为例,详细介绍模型事件的使用方法。
什么是模型事件
模型事件是数据库模型生命周期中触发的钩子,允许你在特定时刻执行自定义逻辑,Eloquent 模型会自动触发这些事件。
常用事件列表
Eloquent 提供以下模型事件:
生命周期事件(按顺序)
// 创建过程 creating → created // 更新过程 updating → updated // 保存过程(创建+更新都会触发) saving → saved // 删除过程 deleting → deleted // 恢复软删除 restoring → restored // 查询过程 retrieving → retrieved
事件监听方式
模型内定义 $dispatchesEvents 属性
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $dispatchesEvents = [
'created' => UserCreated::class,
'deleted' => UserDeleted::class,
];
}
模型内使用静态方法
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected static function booted()
{
static::creating(function ($user) {
// 创建前触发
$user->status = 'active';
$user->remember_token = Str::random(20);
});
static::created(function ($user) {
// 创建后触发
Log::info('用户创建成功: ' . $user->email);
event(new UserCreated($user));
});
static::updating(function ($user) {
// 更新前触发
$user->updated_by = auth()->id();
});
static::deleted(function ($user) {
// 删除后触发
Mail::to($user->email)->send(new AccountDeletedMail());
});
static::retrieved(function ($user) {
// 查询后触发
$user->last_retrieved_at = now();
});
}
}
在服务提供者中注册
<?php
namespace App\Providers;
use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
User::observe(UserObserver::class);
}
}
使用观察者(推荐)
观察者是组织事件监听代码的最佳方式:
<?php
namespace App\Observers;
use App\Models\User;
use Illuminate\Support\Facades\Log;
class UserObserver
{
public function creating(User $user)
{
// 生成唯一标识
$user->user_code = 'USR' . time() . rand(1000, 9999);
}
public function created(User $user)
{
// 发送欢迎通知
$user->notify(new WelcomeNotification());
// 记录日志
Log::info('用户创建: ' . $user->email);
// 创建关联数据
$user->profile()->create([
'bio' => '新用户'
]);
}
public function updating(User $user)
{
// 更新前检查
if ($user->isDirty('email')) {
$user->email_verified_at = null;
}
}
public function updated(User $user)
{
// 更新后的操作
activity()->log('用户信息已更新');
}
public function deleting(User $user)
{
// 防止删除管理员
if ($user->is_admin) {
return false; // 返回 false 可以阻止删除
}
}
public function deleted(User $user)
{
// 清理关联数据
$user->logs()->delete();
Storage::delete($user->avatar_path);
}
public function restored(User $user)
{
// 恢复软删除
$user->restore_notes = '用户申诉恢复';
}
}
事件的应用场景
自动填充字段
class Product extends Model
{
protected static function booted()
{
static::creating(function ($product) {
// 自动生成商品编号
$product->sku = strtoupper(uniqid('SKU-'));
// 设置默认库存
if (is_null($product->stock)) {
$product->stock = 0;
}
// 设置创建者
$product->created_by = auth()->user()->id ?? null;
});
static::updating(function ($product) {
// 自动更新修改者
$product->updated_by = auth()->user()->id ?? null;
});
}
}
数据关联处理
class Order extends Model
{
protected static function booted()
{
static::created(function ($order) {
// 创建订单后自动生成订单日志
$order->orderLogs()->create([
'action' => 'order_created',
'description' => '订单已创建',
'operator_id' => auth()->id()
]);
// 更新库存
foreach ($order->items as $item) {
$item->product->decrement('stock', $item->quantity);
}
});
static::updated(function ($order) {
// 订单状态变更时发送通知
if ($order->wasChanged('status')) {
$order->customer->notify(new OrderStatusUpdated($order));
$order->orderLogs()->create([
'action' => 'status_changed',
'description' => "状态变更为: {$order->status}",
'operator_id' => auth()->id()
]);
}
});
}
}
缓存管理
class Setting extends Model
{
protected static function booted()
{
static::saved(function ($setting) {
// 清除相关缓存
Cache::forget('setting.' . $setting->key);
Cache::forget('all_settings');
});
static::deleted(function ($setting) {
// 清除相关缓存
Cache::forget('setting.' . $setting->key);
Cache::forget('all_settings');
});
}
}
事件与队列结合
class User extends Model
{
protected static function booted()
{
static::created(function ($user) {
// 异步发送邮件
dispatch(function () use ($user) {
Mail::to($user->email)->send(new WelcomeMail($user));
})->delay(now()->addMinutes(10));
});
static::deleted(function ($user) {
// 异步清理资料
dispatch(new CleanUserDataJob($user->id))->onQueue('cleanup');
});
}
}
注意事项
事件中使用事务
class TransactionObserver
{
public function created(Transaction $transaction)
{
// 在事务中执行
DB::transaction(function () use ($transaction) {
// 更新余额
$transaction->account->balance += $transaction->amount;
$transaction->account->save();
// 记录变动
$transaction->account->transactions()->create([
'type' => 'balance_change',
'amount' => $transaction->amount
]);
});
}
}
阻止事件执行
class UserObserver
{
public function deleting(User $user)
{
// 返回 false 会阻止删除
if ($user->hasActiveOrders()) {
return false;
}
}
}
// 使用事件阻止
static::updating(function ($user) {
// 检查邮箱是否被占用
if (User::where('email', $user->email)->where('id', '!=', $user->id)->exists()) {
return false; // 阻止更新
}
});
调试事件
// 临时监听所有事件
Event::listen('eloquent.*: App\Models\User', function ($event, $data) {
Log::info('User model event fired: ' . $event);
});
事件类示例
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UserCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function broadcastOn()
{
return new Channel('users.' . $this->user->id);
}
}
最佳实践建议
- 事件命名要清晰:使用明确的事件名称,如
UserCreated、OrderPaid - 保持事件轻量:不要做过重的操作,大任务放到队列中
- 使用观察者组织:当有多个事件监听时,使用观察者类组织更清晰
- 避免递归触发:在事件中保存模型时,注意防止无限递归
通过合理使用模型事件,可以让代码更加解耦、易于维护,并且可以很方便地在模型生命周期中添加各种业务逻辑。