Models
Eloquent: observers
Models dispatch events as they are created, updated, deleted and restored. Listen for them with a closure, or group the listeners for one model in an observer class.
Introduction#
A model dispatches these events, each with the model:
| Event | When |
|---|---|
retrieved | A model was read from the database |
creating, created | A new model is about to be saved for the first time, and was |
updating, updated | A model that exists is about to be saved with changes, and was |
saving, saved | A model is about to be saved, new or not, changed or not, and was |
deleting, deleted | A model is about to be deleted, or soft-deleted, and was |
restoring, restored | A soft-deleted model is about to be restored, and was |
forceDeleting, forceDeleted | A soft-deleted model is about to be deleted for good, and was |
Creating a model dispatches saving, creating, created, then saved; updating one dispatches saving,
updating, updated, then saved. Saving a model with no changes dispatches only saving and saved.
A listener of a -ing event that returns false stops the operation: the model isn't saved, deleted or restored.
Using closures#
Register a closure for an event in the model's static booted(), with the method named after the event:
import { Model } from '@orieljs/framework'export class User extends Model { /** The "booted" method of the model. */ static override booted(): void { this.created((user) => { // ... }) }}booted() runs once, the first time the model is used in your app.
Observers#
Defining observers#
An observer is a class whose methods are named after the events they handle. make:observer writes one in
app/, with created(), updated() and deleted() methods; give their parameter your model's type:
node oriel make:observer UserObserverimport type { User } from '../Models/User'export class UserObserver { /** Handle the User "created" event. */ created(user: User): void { // ... } /** Handle the User "updated" event. */ updated(user: User): void { // ... } /** Handle the User "deleted" event. */ deleted(user: User): void { // ... }}Register it with the model's observe(), in a service provider's boot():
import { ServiceProvider } from '@orieljs/framework'import { User } from '../Models/User'import { UserObserver } from '../Observers/UserObserver'export class AppServiceProvider extends ServiceProvider { override boot(): void { User.observe(UserObserver) }}Every method named after an event is registered. Oriel makes the observer through your app's container, so it can take
a service with inject(); an instance works too: User.observe(new UserObserver()).
A -ing method that returns false cancels the operation, as a closure does:
import { Str } from '@orieljs/framework'import type { Post } from '../Models/Post'export class PostObserver { /** Give a new post its slug. */ creating(post: Post): void { post.slug = Str.slug(post.title) } /** A published post can't be deleted. */ deleting(post: Post): boolean { return post.published_at === null }}Event names#
A model event is dispatched as eloquent.<event>: <Model>, such as eloquent.created: User, so you can also listen
for it with Event.listen(). Laravel uses the model's full class name; Oriel uses the class's name.
Muting events#
Model.withoutEvents() runs a function with model events off, for the code it runs:
const user = await Model.withoutEvents(() => User.findOrFail(1))saveQuietly() and deleteQuietly() save or delete one model without events:
const user = await User.findOrFail(1)user.name = 'Victoria Faith'await user.saveQuietly()