Laravel – Eloquent Events & Model Lifecycle

2 min read

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?
  • saving khá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
Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *