
本文介绍如何在 Laravel 中优雅、全局地监听模型特定字段(如 status)的值变更,无需手动调用 isDirty(),通过模型事件或观察者实现自动化响应。
本文介绍如何在 laravel 中优雅、全局地监听模型特定字段(如 `status`)的值变更,无需手动调用 `isdirty()`,通过模型事件或观察者实现自动化响应。
在 Laravel 应用中,常需对模型某字段的变更做出即时响应——例如当用户订阅状态(status)变为 'unsubscribed' 时,自动触发邮件通知、清理缓存或同步至第三方系统。若依赖每次赋值后手动检查 isDirty('status'),不仅易遗漏、重复冗余,还违背单一职责原则。
Laravel 提供了更健壮的解决方案:模型生命周期事件与观察者模式。推荐优先使用 static::updated() 闭包事件(Laravel 8+ 支持 booted()),它在模型成功更新数据库后触发,且能精准判断字段是否真实变更:
// app/Models/Subscriber.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Subscriber extends Model
{
protected static function booted()
{
static::updated(function (Subscriber $subscriber) {
// 检查 status 字段是否在本次更新中发生变更
if ($subscriber->wasChanged('status')) {
// 获取变更前后的值(可选)
$oldStatus = $subscriber->getOriginal('status');
$newStatus = $subscriber->status;
// 仅当新状态为 'unsubscribed' 时执行业务逻辑
if ($newStatus === 'unsubscribed') {
\Log::info("Subscriber {$subscriber->id} unsubscribed", [
'from' => $oldStatus,
'to' => $newStatus
]);
// ✅ 此处添加你的业务操作:
// dispatch(new UnsubscribeNotificationJob($subscriber));
// Cache::forget("subscriber:{$subscriber->id}");
// sendWebhookToCRM($subscriber);
}
}
});
}
}⚠️ 关键注意事项:
- wasChanged() 仅在 updated 事件中可靠工作(因 saved 或 updating 阶段数据尚未持久化,getOriginal() 可能不准确);
- 确保字段变更确实触发了数据库更新(即 $subscriber->save() 被调用),批量更新(update() 静态方法)不会触发模型事件,此时需改用观察者或数据库触发器;
- 若逻辑复杂或需复用,建议将事件处理提取为独立观察者类:
// app/Observers/SubscriberObserver.php
<?php
namespace App\Observers;
use App\Models\Subscriber;
class SubscriberObserver
{
public function updated(Subscriber $subscriber)
{
if ($subscriber->wasChanged('status') && $subscriber->status === 'unsubscribed') {
// 处理退订逻辑
}
}
}
// 在服务提供者中注册(如 AppServiceProvider@register)
use App\Models\Subscriber;
use App\Observers\SubscriberObserver;
Subscriber::observe(SubscriberObserver::class);✅ 总结:通过 booted() + updated 事件配合 wasChanged(),你可实现零侵入、高可维护的字段变更监听。该方案自动生效于所有修改 status 的场景(无论来自控制器、命令行还是 API 请求),是 Laravel 生态中响应式数据流的最佳实践之一。

















