Eloquent сам розсилає події життєвого циклу: creating, created, updating, updated, saving, saved, deleting, deleted, restored, replicating.
Зручно для дрібниць, які мають виконуватися завжди:
class Post extends Model
{
protected static function booted(): void
{
static::creating(function (Post $post) {
$post->slug ??= Str::slug($post->title);
});
}
}
Для повного набору краще окремий observer - інакше booted() розростається:
#[ObservedBy(PostObserver::class)]
class Post extends Model
{
}
Чим небезпечні:
- Масові операції їх не викликають.
Post::where(...)->update([...]),->delete()таinsert()йдуть повз Eloquent, тож жоден слухач не спрацює. Дані тихо розходяться з тим, що гарантував observer. - Логіка стає невидимою.
$post->save()у контролері виглядає простим рядком, а насправді тягне за собою запис в інші таблиці й виклик API. - Тести сповільнюються. Кожна фабрика в кожному тесті тягне весь ланцюжок подій, включно з тими, що ходять у мережу.
- Помилка в слухачі ламає збереження. Виняток у
creatingскасовує операцію - зокрема там, де про це ніхто не думав. - Рекурсія. Слухач
saved, який оновлює ту саму модель, викликає сам себе; рятуєsaveQuietly().
Правило: модельні події - для інваріантів самої моделі (слаг, нормалізація поля, службові звʼязки). Бізнес-процес - оформлення замовлення, розсилка, інтеграції - належить явному сервісу чи доменній події, які видно в місці виклику.