Laravel Eloquent

Laravel Eloquent is the core ActiveRecord ORM of the Laravel framework. Following a "convention over configuration" approach, it provides database operations through an intuitive and fluent interface, delivering an excellent developer experience. It automatically infers relationships between models and database tables based on conventions, enabling complex SQL queries to be expressed in concise, readable PHP code. With comprehensive built-in features like migrations, relationships, events, accessors/mutators, and deep integration with the Laravel ecosystem, it maximizes development efficiency for web applications.

ORMPHPActive RecordLaravelFrameworkDevelopment Productivity

GitHub Overview

laravel/framework

The Laravel Framework.

Stars33,844
Watchers958
Forks11,444
Created:January 10, 2013
Language:PHP
License:MIT License

Topics

frameworklaravelphp

Star History

laravel/framework Star History
Data as of: 7/19/2025, 09:31 AM

Library

Laravel Eloquent

Overview

Laravel Eloquent is the core ActiveRecord ORM of the Laravel framework. Following a "convention over configuration" approach, it provides database operations through an intuitive and fluent interface, delivering an excellent developer experience. It automatically infers relationships between models and database tables based on conventions, enabling complex SQL queries to be expressed in concise, readable PHP code. With comprehensive built-in features like migrations, relationships, events, accessors/mutators, and deep integration with the Laravel ecosystem, it maximizes development efficiency for web applications.

Details

Laravel Eloquent 2025 edition has established itself as the most approachable ORM choice for PHP web application development. Through its Active Record pattern implementation, each model class corresponds 1:1 with a database table, enabling object-oriented data manipulation. It provides rich practical features including powerful query builder, automatic timestamp management, soft deletes, mass assignment protection, Eloquent collections, relationships (one-to-one, one-to-many, many-to-many, polymorphic), and more. Integration with official packages like Laravel Livewire, Laravel Nova, and Laravel Breeze streamlines full-stack development.

Key Features

  • Intuitive Active Record Implementation: Simple data operations centered around model classes
  • Powerful Relationships: Support for one-to-one, one-to-many, many-to-many, and polymorphic relationships
  • Fluent Query Builder: Intuitive query writing without direct SQL awareness
  • Automatic Migrations: Systematic management of schema changes
  • Eloquent Collections: High-feature array-like data manipulation
  • Event Integration: Automatic hook processing during model operations

Advantages and Disadvantages

Advantages

  • Most familiar design for PHP developers with complete Laravel ecosystem integration
  • Convention-based design minimizes configuration files and learning curve
  • Powerful relationship features and Eager Loading prevent N+1 query problems
  • Development and testing efficiency through migrations, seeders, and factories
  • Synergistic effects with Laravel tools (Tinker, Artisan, Telescope)
  • Rich community resources and continuous evolution with Laravel 11

Disadvantages

  • Basically impossible to use outside the Laravel framework
  • Performance constraints of Active Record pattern become apparent with large data processing
  • Complex SQL queries require raw SQL or query builder combination
  • Strong database abstraction makes detailed SQL control difficult in some scenarios
  • Heavy use of magic methods limits IDE completion features
  • Difficult integration with existing systems that don't follow table naming conventions

Reference Pages

Code Examples

Installation and Basic Setup

# Create Laravel project (includes Eloquent)
composer create-project laravel/laravel my-app
cd my-app

# Database configuration (.env file)
cp .env.example .env
php artisan key:generate

# Database connection settings
# Edit .env file
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_database
DB_USERNAME=root
DB_PASSWORD=

# Verify database connection
php artisan tinker
>>> DB::connection()->getPdo();

Model Creation and Migration

# Create model and migration simultaneously
php artisan make:model User --migration
php artisan make:model Post -m
php artisan make:model Comment -mc  # Model, migration, controller

# Create with factory and seeder
php artisan make:model Product -mfs
<?php
// app/Models/User.php - User model
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'name',
        'email',
        'email_verified_at',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];

    // One-to-many relationship
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    // Accessor example
    public function getFullNameAttribute(): string
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}

// database/migrations/xxxx_create_users_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
            $table->softDeletes();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};

Basic CRUD Operations

<?php
use App\Models\User;
use App\Models\Post;

// Create - Data creation
$user = User::create([
    'name' => 'John Doe',
    'email' => '[email protected]',
    'password' => bcrypt('password123')
]);

// Or new + save
$user = new User();
$user->name = 'John Doe';
$user->email = '[email protected]';
$user->password = bcrypt('password123');
$user->save();

// Read - Data retrieval
$users = User::all(); // Get all users
$user = User::find(1); // Get by ID
$user = User::where('email', '[email protected]')->first();

// Multi-condition search
$users = User::where('created_at', '>=', now()->subDays(30))
    ->where('email_verified_at', '!=', null)
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->get();

// Update - Data update
$user = User::find(1);
$user->name = 'Jane Doe';
$user->save();

// Or bulk update
User::where('id', 1)->update(['name' => 'Jane Doe']);

// Delete - Data deletion
$user = User::find(1);
$user->delete(); // Soft delete (sets deleted_at)

// Force delete
$user->forceDelete();

// Bulk delete
User::where('email_verified_at', null)->delete();

Relationships and Eager Loading

<?php
// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Post extends Model
{
    protected $fillable = ['title', 'content', 'user_id'];

    // Many-to-one relationship
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    // One-to-many relationship
    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}

// app/Models/Comment.php
class Comment extends Model
{
    protected $fillable = ['content', 'post_id', 'user_id'];

    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

// Relationship operations example
$user = User::find(1);

// Retrieve related data
$posts = $user->posts; // User's posts
$postCount = $user->posts()->count(); // Post count

// Create related data
$post = $user->posts()->create([
    'title' => 'New Post',
    'content' => 'Post content'
]);

// Eager Loading (N+1 problem prevention)
$posts = Post::with(['user', 'comments.user'])->get();

foreach ($posts as $post) {
    echo $post->user->name; // No additional queries
    foreach ($post->comments as $comment) {
        echo $comment->user->name; // No additional queries
    }
}

// Conditional Eager Loading
$posts = Post::with(['comments' => function ($query) {
    $query->where('approved', true)->orderBy('created_at', 'desc');
}])->get();

Advanced Queries and Scopes

<?php
// Define local scopes in app/Models/Post.php
class Post extends Model
{
    // Local scopes
    public function scopePublished($query)
    {
        return $query->where('status', 'published');
    }

    public function scopeByUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

    public function scopeRecent($query, $days = 7)
    {
        return $query->where('created_at', '>=', now()->subDays($days));
    }
}

// Using scopes
$posts = Post::published()->recent(30)->get();
$userPosts = Post::byUser(1)->published()->orderBy('created_at', 'desc')->get();

// Complex query builder
$posts = Post::select('posts.*', 'users.name as author_name')
    ->join('users', 'posts.user_id', '=', 'users.id')
    ->where('posts.created_at', '>=', now()->subMonth())
    ->whereHas('comments', function ($query) {
        $query->where('approved', true);
    })
    ->withCount(['comments', 'likes'])
    ->orderBy('comments_count', 'desc')
    ->paginate(15);

// Subqueries
$latestPosts = Post::select('user_id', DB::raw('MAX(created_at) as latest_post'))
    ->groupBy('user_id');

$users = User::joinSub($latestPosts, 'latest_posts', function ($join) {
    $join->on('users.id', '=', 'latest_posts.user_id');
})->get();

// Conditional queries
$query = Post::query();

if ($request->has('category')) {
    $query->where('category_id', $request->category);
}

if ($request->has('search')) {
    $query->where(function ($q) use ($request) {
        $q->where('title', 'like', '%' . $request->search . '%')
          ->orWhere('content', 'like', '%' . $request->search . '%');
    });
}

$posts = $query->paginate(20);

Events and Observers

<?php
// app/Models/Post.php - Model events
class Post extends Model
{
    protected static function boot()
    {
        parent::boot();

        // Creating event
        static::creating(function ($post) {
            if (auth()->check()) {
                $post->user_id = auth()->id();
            }
        });

        // Updating event
        static::updating(function ($post) {
            $post->updated_by = auth()->id();
        });

        // Deleting event
        static::deleting(function ($post) {
            // Delete related comments
            $post->comments()->delete();
        });
    }
}

// app/Observers/PostObserver.php - Observer pattern
class PostObserver
{
    public function created(Post $post): void
    {
        // Post creation notification
        Notification::send($post->user, new PostCreatedNotification($post));
    }

    public function updated(Post $post): void
    {
        // Clear cache
        Cache::forget("post.{$post->id}");
    }

    public function deleted(Post $post): void
    {
        // Delete image files
        Storage::delete($post->image_path);
    }
}

// Register observer in app/Providers/AppServiceProvider.php
public function boot(): void
{
    Post::observe(PostObserver::class);
}

Many-to-Many Relationships and Pivot Tables

<?php
// app/Models/User.php
class User extends Model
{
    // Many-to-many relationship (User ⟷ Role)
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class)
            ->withTimestamps()
            ->withPivot(['assigned_at', 'assigned_by']);
    }

    // Tagging system (polymorphic many-to-many)
    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

// app/Models/Role.php
class Role extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }

    public function permissions(): BelongsToMany
    {
        return $this->belongsToMany(Permission::class);
    }
}

// Many-to-many operations
$user = User::find(1);

// Add roles
$user->roles()->attach(1); // Add role_id = 1
$user->roles()->attach([1, 2, 3]); // Add multiple
$user->roles()->attach(1, ['assigned_at' => now()]); // With pivot data

// Remove roles
$user->roles()->detach(1); // Remove role_id = 1
$user->roles()->detach([1, 2]); // Remove multiple
$user->roles()->detach(); // Remove all

// Sync (keep only specified IDs)
$user->roles()->sync([1, 2, 3]);

// Condition check
if ($user->roles()->where('name', 'admin')->exists()) {
    // Has admin role
}

// Get pivot data
$userRoles = $user->roles()->withPivot(['assigned_at', 'assigned_by'])->get();
foreach ($userRoles as $role) {
    echo $role->pivot->assigned_at;
    echo $role->pivot->assigned_by;
}

Factories and Seeders (Test & Development Data)

<?php
// database/factories/UserFactory.php
namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class UserFactory extends Factory
{
    protected $model = User::class;

    public function definition(): array
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => bcrypt('password'), // Fixed password for testing
            'remember_token' => Str::random(10),
        ];
    }

    // State variations
    public function unverified(): static
    {
        return $this->state(fn (array $attributes) => [
            'email_verified_at' => null,
        ]);
    }

    public function admin(): static
    {
        return $this->state(fn (array $attributes) => [
            'name' => 'Administrator',
            'email' => '[email protected]',
        ]);
    }
}

// database/factories/PostFactory.php
class PostFactory extends Factory
{
    public function definition(): array
    {
        return [
            'title' => $this->faker->sentence(),
            'content' => $this->faker->paragraphs(3, true),
            'status' => $this->faker->randomElement(['draft', 'published']),
            'user_id' => User::factory(),
        ];
    }
}

// database/seeders/DatabaseSeeder.php
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Create admin user
        $admin = User::factory()->admin()->create();

        // Create 50 regular users, each with 1-5 posts
        User::factory(50)
            ->has(Post::factory()->count(rand(1, 5)))
            ->create();

        // Specific relationship structure
        User::factory()
            ->has(
                Post::factory()
                    ->has(Comment::factory()->count(3))
                    ->count(5)
            )
            ->create();
    }
}

// Usage in tests
$users = User::factory(10)->create();
$post = Post::factory()->for($admin)->create();