Back to Read More
LaravelPHP

Laravel Eloquent ORM

Dec 15, 2025

Eloquent is Laravel's built-in ORM (Object-Relational Mapping). It lets you interact with your database using PHP classes and objects instead of writing raw SQL. Each database table has a corresponding "Model" that you use to query, insert, update, and delete data.

What is Eloquent?

Think of Eloquent as a translator between your PHP code and the database. Instead of writing:

Raw SQL (without Eloquent)
SELECT * FROM users WHERE active = 1 ORDER BY name ASC;

You write this instead:

Eloquent (clean PHP)
$users = User::where('active', 1)->orderBy('name')->get();

Much cleaner, safer (prevents SQL injection), and easier to maintain.

1. Creating a Model

Every Eloquent model represents one database table. By convention, a Post model maps to a posts table.

Terminal
# Create a model
php artisan make:model Post

# Create model + migration + controller + factory + seeder
php artisan make:model Post -mcfs
app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Fields that can be mass assigned
    protected $fillable = [
        'title',
        'body',
        'status',
        'user_id',
    ];

    // Fields that should be hidden (e.g. in JSON)
    protected $hidden = [
        'password',
    ];

    // Auto-cast fields to specific types
    protected $casts = [
        'published_at' => 'datetime',
        'is_featured'  => 'boolean',
        'metadata'     => 'array',
    ];
}
$fillable vs $guarded:$fillable = whitelist (only these fields can be mass assigned). $guarded = blacklist (all fields except these can be mass assigned). Use $guarded = [] to allow all fields.

2. CRUD Operations

Create (Insert Data)

Creating Records
// Method 1: Create and save in one step
$post = Post::create([
    'title' => 'My First Post',
    'body'  => 'This is the content.',
]);

// Method 2: Create instance, set values, then save
$post = new Post();
$post->title = 'My First Post';
$post->body  = 'This is the content.';
$post->save();

// Method 3: Find or create (avoid duplicates)
$post = Post::firstOrCreate(
    ['title' => 'My First Post'],     // Search by this
    ['body' => 'This is the content.'] // Create with this if not found
);

Read (Fetch Data)

Reading Records
// Get ALL posts
$posts = Post::all();

// Find by primary key (ID)
$post = Post::find(1);

// Find or throw 404 error
$post = Post::findOrFail(1);

// Get first matching record
$post = Post::where('status', 'published')->first();

// Get with conditions
$posts = Post::where('status', 'published')
    ->where('user_id', 1)
    ->orderBy('created_at', 'desc')
    ->take(10)
    ->get();

// Count records
$count = Post::where('status', 'published')->count();

// Check if any exist
$exists = Post::where('title', 'Hello')->exists();

Update (Modify Data)

Updating Records
// Method 1: Find then update
$post = Post::find(1);
$post->title = 'Updated Title';
$post->save();

// Method 2: Update in one step
$post = Post::find(1);
$post->update([
    'title'  => 'Updated Title',
    'status' => 'published',
]);

// Method 3: Mass update (multiple records)
Post::where('status', 'draft')
    ->update(['status' => 'archived']);

Delete (Remove Data)

Deleting Records
// Method 1: Find then delete
$post = Post::find(1);
$post->delete();

// Method 2: Delete by ID directly
Post::destroy(1);

// Method 3: Delete multiple by IDs
Post::destroy([1, 2, 3]);

// Method 4: Delete with condition
Post::where('status', 'archived')->delete();

3. Query Scopes

Scopes let you define reusable query conditions inside your model. This keeps your controllers clean.

app/Models/Post.php
class Post extends Model
{
    // Define a scope (always prefix with "scope")
    public function scopePublished($query)
    {
        return $query->where('status', 'published');
    }

    public function scopeRecent($query)
    {
        return $query->orderBy('created_at', 'desc');
    }

    // Scope with parameter
    public function scopeOfStatus($query, string $status)
    {
        return $query->where('status', $status);
    }
}
Usage in Controller
// Clean and readable!
$posts = Post::published()->recent()->take(5)->get();

// With parameter
$drafts = Post::ofStatus('draft')->get();

4. Accessors & Mutators

Accessors format data when you read it. Mutators format data when you save it.

app/Models/User.php
use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
    // Accessor: auto-capitalize name when reading
    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucwords($value),
        );
    }

    // Mutator: auto-hash password when saving
    protected function password(): Attribute
    {
        return Attribute::make(
            set: fn (string $value) => bcrypt($value),
        );
    }

    // Both accessor + mutator together
    protected function email(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => strtolower($value),
            set: fn (string $value) => strtolower($value),
        );
    }
}
Usage
$user = User::find(1);

// Accessor runs automatically
echo $user->name; // "John Doe" (even if stored as "john doe")

// Mutator runs automatically
$user->password = 'secret123'; // Stored as hashed value

5. Soft Deletes

Instead of permanently removing records, soft deletes mark them as "deleted" by setting a deleted_at timestamp. The data stays in the database.

Migration
// Add to your migration
$table->softDeletes(); // Adds 'deleted_at' column
app/Models/Post.php
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
}
Usage
$post->delete();            // Soft delete (sets deleted_at)

Post::withTrashed()->get(); // Include soft-deleted records

Post::onlyTrashed()->get(); // Only soft-deleted records

$post->restore();           // Undo soft delete

$post->forceDelete();       // Permanently delete from DB

6. Common Query Patterns

Useful Eloquent Queries
// Pagination (15 per page)
$posts = Post::paginate(15);

// Select specific columns only
$posts = Post::select('id', 'title')->get();

// Where with multiple conditions
$posts = Post::where('status', 'published')
    ->where('views', '>', 100)
    ->get();

// Where IN
$posts = Post::whereIn('id', [1, 2, 3])->get();

// Where between dates
$posts = Post::whereBetween('created_at', [
    '2025-01-01', '2025-12-31'
])->get();

// Search with LIKE
$posts = Post::where('title', 'like', '%laravel%')->get();

// Aggregate functions
$total   = Post::count();
$average = Post::avg('views');
$max     = Post::max('views');
$sum     = Post::sum('views');

// Chunk large datasets (process 100 at a time)
Post::chunk(100, function ($posts) {
    foreach ($posts as $post) {
        // Process each post
    }
});

Summary

  • βœ“Models β€” PHP classes that represent database tables
  • βœ“CRUD β€” create, read, update, delete with simple methods
  • βœ“Scopes β€” reusable query conditions inside models
  • βœ“Accessors & Mutators β€” auto-format data on read/write
  • βœ“Soft Deletes β€” safe deletion without losing data
  • βœ“Query Patterns β€” pagination, search, aggregates, chunking

Β© 2026 Koeuk KOS. All rights reserved.

Built with Nuxt.js, Vue.js & Tailwind CSS