DEV Community

Adebayo Olukunle
Adebayo Olukunle

Posted on

Eloquent ORM (Models, Relationships) in Laravel

Eloquent is Laravel's built-in ORM (Object-Relational Mapper) that provides a simple and expressive way to interact with a database. It follows the Active Record pattern, where each model corresponds to a database table, and each instance of a model represents a single row in that table.

This article covers the following:

  • Creating and using Eloquent models

  • Defining and using relationships (One-to-One, One-to-Many, Many-to-Many, Has-One-Through, Has-Many-Through, and Polymorphic Relationships)

  • Querying related data

  • Best practices

1. Creating and Using Eloquent Models

To create a new model in Laravel, use the Artisan command:

php artisan make:model Product
Enter fullscreen mode Exit fullscreen mode

This command creates a Product.php file inside the app/Models directory (Laravel 8+). If using Laravel 7 or earlier, it will be in app/.

A typical Eloquent model looks like this:

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'price', 'description'];
}
Enter fullscreen mode Exit fullscreen mode

Basic CRUD Operations
When a model is created as described above, it can be used to handle basic operations in your application which we often term as CRUD meaning Create a record, Retrieving records, Updating a record, and Deleting a record.

  • Creating a Record
$product = Product::create([
    'name' => 'Laptop',
    'price' => 1500,
    'description' => 'High-performance laptop'
]);
Enter fullscreen mode Exit fullscreen mode
  • Retrieving Records
$products = Product::all(); // Get all products
$product = Product::find(1); // Find by ID, it is usually one record
$product = Product::where('name', 'Laptop')->first();
Enter fullscreen mode Exit fullscreen mode
  • Updating a Record
$product = Product::find(1);
$product->price = 1700;
$product->save();
Enter fullscreen mode Exit fullscreen mode
  • Deleting a Record
$product->delete();
Product::destroy(1); // Delete by ID
Enter fullscreen mode Exit fullscreen mode

2. Defining and Using Relationships

  • One-to-One Relationship

In this relationship, one entity is directly related to another entity. Entity in this case, an entity is a model record, say a User record would have a one-to-one-relationship with a Profile model record.

Example: User and Profile

app/Models/User.php

class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

app/Models/Profile.php

class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Fetching user profile:
To retrieve a user record, include the following code in one of the methods in the controller class created to handle user modules which typical should be created in app/Http/Controller/UserController.php, although it can be used in any class method.

php artisan make:controller UserController
Enter fullscreen mode Exit fullscreen mode

open the file created in app/Http/Controller/UserController.php, add the following code. you can change the method name to what you prefer, but use a name that clearly describes what the method does.

public function findUserProfile() 
{
   $user = User::find(1); // 1 is the user ID
   $profile = $user->profile;
}
Enter fullscreen mode Exit fullscreen mode
  • One-to-Many Relationship

In this relationship, one entity is related to multiple entities. Meaning, for instance, a specific post in the Post model would have or own multiple comments in the Comment Model (remember that a model is attached to a single Database table).

Example: Post and Comments

class Post extends Model
{
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}
Enter fullscreen mode Exit fullscreen mode
class Comment extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Fetching comments for a post: To retrieve comment records for a specific post, include the following code in one of the methods in the controller class which should be created to handle Post modules typical as app/Http/Controller/PostController.php, although it can be used in any class.

php artisan make:controller PostController
Enter fullscreen mode Exit fullscreen mode

open the file created in app/Http/Controller/UserController.php, add the following code. you can change the method name to what you prefer, but use a name that clearly describes what the method does.

public function findPostComment() 
{
   $post = Post::find(1); // 1 is the post ID
   $comments = $post->comments;
}
Enter fullscreen mode Exit fullscreen mode
  • Many-to-Many Relationship

Many entities are related to many other entities. A user can have many roles and a role can be assigned to many users. For instance, a user can have both Admin role and and HR role.

Example: Users and Roles

class User extends Model
{
    // other methods can be at the top or below

    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
}
Enter fullscreen mode Exit fullscreen mode
class Role extends Model
{
    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Assigning a role to a user: in your controller method, you can assign a role to a user like this

// assign a role using role Id to a user
$user->roles()->attach($roleId);
Enter fullscreen mode Exit fullscreen mode
  • Has-One-Through Relationship

A relationship between two models through an intermediate model. This is useful when you need to access a related model that is connected through another model.

Example: Mechanic → Car → Owner

In this scenario, a mechanic services a car, and each car has one owner. Instead of defining two separate relationships, we can use a has-one-through relationship to access the owner directly from the mechanic.

class Mechanic extends Model
{
    public function owner()
    {
        return $this->hasOneThrough(Owner::class, Car::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

This allows you to fetch an owner directly from a mechanic:

$mechanic = Mechanic::find(1);
$owner = $mechanic->owner;
Enter fullscreen mode Exit fullscreen mode
  • Has-Many-Through Relationship

A single model has many related models through an intermediate model. This is useful when a model is indirectly related to another model.

Example: Country → Users → Posts

A country has many users, and each user has many posts. Instead of fetching users first and then fetching their posts, we can define a has-many-through relationship.

class Country extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(Post::class, User::class);
    }
}
Enter fullscreen mode Exit fullscreen mode

Fetching posts from a country directly:

$country = Country::find(1);
$posts = $country->posts;
Enter fullscreen mode Exit fullscreen mode
  • Polymorphic Relationships

Allows multiple models to share the same relationship, meaning different models can be associated with a single model type.

Example: Comments on Posts and Videos

Both posts and videos can have comments, so we use a polymorphic relationship.

class Comment extends Model
{
    public function commentable()
    {
        return $this->morphTo();
    }
}
Enter fullscreen mode Exit fullscreen mode
class Post extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}
Enter fullscreen mode Exit fullscreen mode
class Video extends Model
{
    public function comments()
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}
Enter fullscreen mode Exit fullscreen mode

This allows us to fetch comments on a post or video:

$post = Post::find(1);
$comments = $post->comments;
Enter fullscreen mode Exit fullscreen mode
$video = Video::find(1);
$comments = $video->comments;
Enter fullscreen mode Exit fullscreen mode

Saving a polymorphic comment:

$post->comments()->create(['body' => 'Great post!']);
Enter fullscreen mode Exit fullscreen mode

3. Querying Related Data

Eloquent provides powerful methods to retrieve related data efficiently.

Eager Loading

Preload related data to optimize queries.

$users = User::with('profile')->get();
Enter fullscreen mode Exit fullscreen mode

Lazy Loading

Loads related data only when accessed.

$user = User::find(1);
$profile = $user->profile;
Enter fullscreen mode Exit fullscreen mode

Constraining Eager Loading
You are able to give a condition to what relationship you want to be eager loaded on your model.

$users = User::with(['posts' => function ($query) {
$query->where('status', 'published');
}])->get();

4. Best Practices

  • Use fillable or guarded to prevent mass assignment vulnerabilities.

  • Use eager loading to optimize database queries and reduce N+1 query issues.

  • Follow naming conventions. Eloquent assumes table names and foreign keys based on model names. table name should be plural, model name should singular, foreign fields are in snake case, like user_id

  • Use relationships instead of raw joins for cleaner and maintainable code.

Conclusion

Eloquent ORM in Laravel simplifies database interactions by providing an intuitive syntax for working with models and relationships. Mastering Eloquent will help you write efficient, maintainable, and scalable Laravel applications.

Top comments (0)