
Vì sao cần hiểu Eloquent Model Lifecycle?
Nhiều developer dùng Eloquent mỗi ngày nhưng không thực sự hiểu:
- Khi nào
creatingđược gọi? savingkhác gìcreating?- Có nên gửi email trong model event?
- Observer có khác gì Event?
Khi project lớn, model lifecycle ảnh hưởng trực tiếp đến:
- Performance
- Data consistency
- Side effects (email, sync, log)
- Bug khó trace
Tài liệu chính thức:
https://laravel.com/docs/eloquent#events
1️⃣ Eloquent Model Lifecycle
Khi bạn gọi:
User::create([...]);
Laravel sẽ trigger các event theo thứ tự:
- creating
- created
Tương tự khi update:
- updating
- updated
Khi save:
- saving
- saved
Khi delete:
- deleting
- deleted
Ví dụ sử dụng model event
class User extends Model
{
protected static function booted()
{
static::creating(function ($user) {
$user->uuid = Str::uuid();
});
}
}
Ở đây:
- Mỗi lần tạo user → tự động gán UUID
- Không cần xử lý trong controller
2️⃣ saving vs creating khác nhau thế nào?
creating:
- Chỉ chạy khi tạo mới
saving:
- Chạy cả khi create và update
Ví dụ:
static::saving(function ($user) {
$user->email = strtolower($user->email);
});
Logic normalize này sẽ chạy cho cả insert và update.
3️⃣ Observer Pattern trong Laravel
Nếu bạn không muốn đặt logic trong model, hãy dùng Observer.
Tạo observer:
php artisan make:observer UserObserver --model=User
Ví dụ:
class UserObserver
{
public function created(User $user)
{
SendWelcomeEmail::dispatch($user);
}
}
Đăng ký trong AppServiceProvider:
User::observe(UserObserver::class);
Observer giúp:
- Giữ model sạch
- Tách side-effect khỏi entity
- Dễ test hơn
4️⃣ Observer vs Event – Nên dùng cái nào?
Observer:
- Gắn trực tiếp vào model
- Phù hợp logic liên quan đến entity
Event:
event(new UserRegistered($user));
Phù hợp khi:
- Logic liên quan nhiều hệ thống
- Cần loose coupling
- Cần nhiều listener
Nếu hệ thống lớn → Event + Listener sẽ linh hoạt hơn Observer.
5️⃣ Những lỗi production thường gặp
1. Trigger query trong observer gây recursion
Ví dụ nguy hiểm:
public function updated(User $user)
{
$user->update(['synced' => true]);
}
Điều này sẽ trigger updated lần nữa → loop vô hạn.
2. Gửi mail trực tiếp thay vì queue
Sai:
Mail::to($user->email)->send(new WelcomeMail());
Đúng:
SendWelcomeEmail::dispatch($user);
Observer nên nhẹ.
Task nặng nên đẩy vào queue.
3. Đặt business logic quá nhiều trong event
Model event chỉ nên:
- Normalize dữ liệu
- Sync nhỏ
- Dispatch job
Không nên:
- Tính toán phức tạp
- Gọi API nhiều lần
- Thực hiện transaction lớn
6️⃣ Transaction & Model Event
Nếu bạn dùng:
DB::transaction(function () {
User::create([...]);
});
Event vẫn sẽ được trigger bên trong transaction.
Nếu transaction rollback:
- Data không được commit
- Nhưng event side-effect có thể đã chạy
Giải pháp:
- Dùng afterCommit() nếu cần
- Hoặc chỉ dispatch job sau commit
7️⃣ Model Booting và Static booted()
Laravel gọi boot theo thứ tự:
- boot()
- booted()
Khuyến nghị dùng:
protected static function booted()
Thay vì override boot thủ công, để tránh quên gọi parent::boot().
8️⃣ Khi nào nên tránh Model Event?
Không nên dùng model event khi:
- Logic phụ thuộc context HTTP
- Cần request data
- Logic phức tạp nhiều bước
Trong trường hợp đó, nên xử lý ở:
- Service layer
- Use case class
Kết luận
Eloquent model lifecycle rất mạnh, nhưng cũng rất dễ gây side-effect khó kiểm soát.
Best practice:
- Dùng event cho normalize dữ liệu
- Dùng observer để tách logic
- Không đặt business flow lớn trong model
- Dispatch job thay vì xử lý nặng trực tiếp
- Cẩn thận với transaction
Hiểu lifecycle giúp bạn:
- Tránh bug recursion
- Tránh data inconsistency
- Giữ code sạch
- Scale hệ thống an toàn
