| name | laravel-eloquent |
| description | Guide for working with Laravel Eloquent ORM (Laravel 13.x) — models, queries, relationships, mutators/casting, collections, and API resources. |
| triggers | ["User asks about Eloquent models, queries, or ORM","Working with Laravel database models, relationships, scopes","Creating/editing files in app/Models/","Questions about soft deletes, mass assignment, upserts","Building API resources or transforming Eloquent models to JSON","Accessors, mutators, or attribute casting"] |
Laravel Eloquent ORM (13.x)
Model Generation
php artisan make:model Flight
php artisan make:model Flight -m
php artisan make:model Flight -mfsc
php artisan make:model Flight -a
php artisan make:model Member --pivot
php artisan model:show Flight
Model Conventions
#[Table('my_flights')]
class Flight extends Model {}
#[Table(key: 'flight_id')]
#[Table(key: 'uuid', keyType: 'string', incrementing: false)]
class Article extends Model { use HasUuids; }
class Article extends Model { use HasUlids; }
#[WithoutTimestamps]
public const CREATED_AT = 'creation_date';
public const UPDATED_AT = 'updated_date';
#[Connection('mysql')]
protected $attributes = ['delayed' => false, 'options' => '[]'];
Strictness (AppServiceProvider::boot)
Model::preventLazyLoading(! $this->app->isProduction());
Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
Retrieving Models
Flight::all();
$flights = Flight::where('active', 1)->orderBy('name')->limit(10)->get();
Flight::find(1);
Flight::findOrFail(1);
Flight::where('number', 'FR 900')->first();
Flight::firstOrCreate(['name' => 'London'], ['delayed' => false]);
Flight::firstOrNew(['name' => 'London']);
Flight::updateOrCreate(['departure' => 'Oakland'], ['price' => 99]);
Flight::where('active', 1)->count();
Flight::max('price');
$fresh = $flight->fresh();
$flight->refresh();
Flight::chunk(200, function (Collection $flights) { });
Flight::chunkById(200, fn ($flights) => , 'id');
Flight::lazy()->each(fn ($flight) => );
Inserting & Updating
$flight = new Flight;
$flight->name = 'London';
$flight->save();
protected $fillable = ['name', 'destination'];
protected $guarded = [];
Flight::create(['name' => 'London', 'destination' => 'Paris']);
$flight->update(['delayed' => true]);
Flight::where('active', 1)->update(['delayed' => false]);
Flight::upsert(
[['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99]],
['departure', 'destination'], // unique columns
['price'] // columns to update on match
);
Model::withoutTimestamps(fn () => $post->increment('reads'));
Deleting Models
$flight->delete();
Flight::destroy([1, 2, 3]);
Flight::where('active', 0)->delete();
use Illuminate\Database\Eloquent\SoftDeletes;
class Flight extends Model { use SoftDeletes; }
$flight->trashed();
Flight::withTrashed()->get();
Flight::onlyTrashed()->get();
$flight->restore();
$flight->forceDelete();
php artisan model:prune --pretend
Query Scopes
protected static function booted(): void
{
static::addGlobalScope('active', fn (Builder $builder) => $builder->where('active', 1));
}
Flight::withoutGlobalScope('active')->get();
public function scopeActive(Builder $query): void
{
$query->where('active', 1);
}
Flight::active()->orderBy('name')->get();
public function scopeForCurrentUser(Builder $query): Builder
{
return $query->where('user_id', Auth::id())->withPendingAttributes(['user_id' => Auth::id()]);
}
Relationships
Defining
public function phone(): HasOne
{
return $this->hasOne(Phone::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class)->chaperone();
}
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class);
}
public function latestOrder(): HasOne
{
return $this->hasOne(Order::class)->latestOfMany();
}
public function largestOrder(): HasOne
{
return $this->hasOne(Order::class)->ofMany('price', 'max');
}
public function mechanic(): HasOneThrough
{
return $this->hasOneThrough(Owner::class, Car::class);
}
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class)->withDefault(['name' => 'Guest']);
}
Querying
Post::with('comments')->get();
Post::with(['comments', 'author'])->get();
Post::with('comments.author')->get();
Post::with(['comments' => fn ($q) => $q->where('active', 1)])->get();
$posts->load('comments');
$posts->loadMissing('comments');
Post::has('comments')->get();
Post::has('comments', '>=', 3)->get();
Post::whereHas('comments', fn ($q) => $q->where('content', 'like', '%code%'))->get();
Post::doesntHave('comments')->get();
Post::withCount('comments')->get();
Post::withMin('price', 'amount')->get();
Post::whereBelongsTo($user)->get();
Post::whereBelongsTo($user, 'author')->get();
Accessors, Mutators & Casting
protected function firstName(): Attribute
{
return Attribute::make(
get: fn (string $value) => ucfirst($value),
set: fn (string $value) => strtolower($value),
);
}
protected function casts(): array
{
return [
'is_admin' => 'boolean',
'options' => 'array',
'options' => AsCollection::class,
'options' => AsArrayObject::class,
'birthday' => 'date',
'created_at' => 'datetime:Y-m-d',
'role' => UserRole::class,
'secret' => 'encrypted',
];
}
Collections
Eloquent collections extend Laravel's base Collection with extra model-specific methods:
$users->find(1);
$users->findOrFail(1);
$users->fresh();
$users->load(['comments', 'posts']);
$users->loadMissing('comments');
$users->modelKeys();
$users->only([1, 2, 3]);
$users->except([4, 5]);
$users->makeVisible(['phone']);
$users->makeHidden(['password']);
$users->toQuery()->update(['status' => 'active']);
$users->unique();
#[CollectedBy(UserCollection::class)]
class User extends Model {}
API Resources
php artisan make:resource UserResource
php artisan make:resource UserCollection
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->posts),
'created_at' => $this->created_at,
];
}
}
return new UserResource(User::findOrFail($id));
return User::findOrFail($id)->toResource();
return UserResource::collection(User::all());
return User::all()->toResourceCollection();
JsonResource::withoutWrapping();
'secret' => $this->when(Auth::user()->isAdmin(), $this->secret),
'posts' => PostResource::collection($this->whenLoaded('posts')),
Events & Observers
php artisan make:observer UserObserver --model=User
class UserObserver
{
public function created(User $user): void { }
public function updated(User $user): void { }
}
User::observe(UserObserver::class);
User::withoutEvents(fn () => User::factory()->create());
Quick Reference
| Task | Method |
|---|
| Find or 404 | Model::findOrFail($id) |
| First or create | Model::firstOrCreate(['key' => $val], $extra) |
| Upsert | Model::upsert($data, $unique, $update) |
| Soft delete restore | $model->restore() |
| Force delete | $model->forceDelete() |
| Eager load | Model::with('relation')->get() |
| Prevent N+1 | Model::preventLazyLoading(true) |
| Chunk large sets | Model::chunk(200, fn($rows) => ...) |
| Mass update | Model::where(...)->update([...]) |
| Scope | public function scopeName(Builder $q) |
| JSON cast | 'column' => 'array' in casts() |
| API resource | return new UserResource($model) |