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.
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.
<?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?
SQL injectionMass assignment of columns you didn't intend users to setSlow queriesDuplicate rows
Show answer
Answer: Mass assignment of columns you didn't intend users to set