Laravel Tutorial · Database and Eloquent · Lesson 15 of 27

Eloquent Models

Map tables to model classes, create, read, update and delete records, protect against mass assignment, cast attributes, and add accessors and query scopes.

Create a free account to save this page, take notes and track your progress. Sign in

One class per table

An Eloquent model represents a table: class Post extends Model maps to the posts table, each instance is a row, and columns are properties. Generate one with php artisan make:model Post -m (with a migration).

Task Code
Create Post::create([...]) (needs $fillable) or new Post + save()
Find Post::find(1), findOrFail(1), firstWhere('slug', $slug)
Query Post::where('published', true)->latest()->get() (all query builder methods work)
Update $post->update([...]), or change properties then save()
Delete $post->delete(), Post::destroy([1, 2])

Mass assignment protection: create($request->all()) could set columns like is_admin. List allowed columns in $fillable (or blocked ones in $guarded); Laravel ignores the rest.

Casts convert columns to PHP types ('published' => 'boolean', 'options' => 'array', 'published_at' => 'datetime'), accessors compute attributes, and scopes name reusable query conditions.

Create, query, update, delete, casts, accessors and scopes
<?php
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

Schema::create('articles', function (Blueprint $t) {
    $t->id();
    $t->string('title');
    $t->boolean('published')->default(false);
    $t->json('tags')->nullable();
    $t->boolean('is_featured')->default(false);
    $t->timestamps();
});

class Article extends Model
{
    protected $fillable = ['title', 'published', 'tags'];    // is_featured can't be mass-assigned

    protected function casts(): array
    {
        return ['published' => 'boolean', 'tags' => 'array'];
    }

    protected function headline(): Attribute                  // an accessor: $article->headline
    {
        return Attribute::get(fn () => strtoupper($this->title));
    }

    #[Scope]
    protected function published(Builder $query): void       // a query scope: Article::published()
    {
        $query->where('published', true);
    }
}

$a = Article::create(['title' => 'Hello Eloquent', 'published' => 1, 'tags' => ['php', 'laravel'], 'is_featured' => true]);
Article::create(['title' => 'Draft post']);

echo "created #{$a->id}: {$a->headline}, featured: ", var_export($a->fresh()->is_featured, true), "\n";
echo 'tags is an array: ', implode(' + ', $a->tags), "\n";
echo 'published titles: ', Article::published()->pluck('title')->implode(', '), "\n";

$draft = Article::firstWhere('title', 'Draft post');
$draft->update(['published' => true]);
echo 'published count: ', Article::published()->count(), "\n";

$draft->delete();
echo 'remaining: ', Article::count(), ', find(2): ', var_export(Article::find(2), true), "\n";
echo json_encode(Article::first()->only('id', 'title', 'published', 'tags')), "\n";

Output

created #1: HELLO ELOQUENT, featured: false
tags is an array: php + laravel
published titles: Hello Eloquent
published count: 2
remaining: 1, find(2): NULL
{"id":1,"title":"Hello Eloquent","published":true,"tags":["php","laravel"]}

Run this on your computer — see “Get Started” for setup.

Test yourself

What does $fillable protect against?

  1. SQL injection
  2. Mass assignment of columns you didn't intend users to set
  3. Slow queries
  4. Duplicate rows
Show answer

Answer: Mass assignment of columns you didn't intend users to set

Was this page helpful?