Eloquent models and queries

Laravel · Essentials · 15 min

Eloquent is how almost every Laravel app reads and writes its data.

An Eloquent model is a class in app/Models representing one table: Post maps to posts by convention, with id as the primary key and created_at/updated_at maintained automatically.

Query through the model with a fluent query builder:

$posts = Post::where('published', true)->orderByDesc('created_at')->take(10)->get();
  • get() returns a Collection of models; first() one model or null; find($id) by key; findOrFail($id) throws a ModelNotFoundException, which becomes a 404.
  • count(), exists(), pluck('title'), paginate(15).
  • where('votes', '>', 100), whereIn, whereNull, orWhere, and when($cond, fn ($q) => ...) for optional filters.

All values are bound as PDO parameters, so they're safe from SQL injection.

Writing data:

  • Post::create([...]) inserts and returns the model; $post->update([...]) changes it; $post->delete() removes it.
  • Or set attributes and call $post->save().
  • firstOrCreate and updateOrCreate handle "find or insert" cases.

create and update use mass assignment, so the model must whitelist columns with protected $fillable = ['title', 'body']; (or use $guarded). This stops a malicious request from setting fields such as is_admin.

Define casts in a casts() method to turn columns into proper types: 'published_at' => 'datetime', 'options' => 'array', 'status' => Status::class for an enum.

Example

<?php
namespace App\Models;

use App\Enums\Status;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = ['title', 'slug', 'body', 'status', 'published_at'];
    protected function casts(): array
    {
        return ['published_at' => 'datetime', 'status' => Status::class];
    }
}

// Usage (e.g. in php artisan tinker):
$post = Post::create(['title' => 'Hi', 'slug' => 'hi', 'body' => '...', 'status' => 'draft']);
$post->update(['status' => Status::Published, 'published_at' => now()]);
$recent = Post::where('status', Status::Published)
    ->where('published_at', '>=', now()->subWeek())
    ->latest('published_at')
    ->get();                                  // Collection of Post models
$titles = $recent->pluck('title');            // Collection of strings
$post->published_at->diffForHumans();         // "1 second ago" (Carbon)
Post::findOrFail(999);                        // ModelNotFoundException -> 404

Remember

  • One model per table; conventions decide table and key names
  • Chain where/orderBy/take and finish with get, first, find or paginate
  • Whitelist $fillable for mass assignment; use casts() for types

Watch out for

  • Calling Post::create($request->all()) with a broad $guarded = [], letting users set any column.

Check yourself

  1. Why does Post::create($request->all()) ignore an is_admin field sent by the client?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: laravel.com/docs/12.x/eloquent