Laravel one to many Eloquent relationship tutorial

In a database structure, there are some tables are related to one another. For example in a blog application, a user have many posts and post may have many comments.

Laravel provides eloquent relationship which provides powerful query builders. In Laravel, eloquent relationships are defined in model classes. Laravel eloquent provides easy ways to create common relationships:

In this article, we will discuss on how to create one to many eloquent relationship between two models. This is a little complicated compared to one-to-one relationship. In this type of relationship, one parent model is associated with one or more child model. For example, One User model is related with one or more Post model.

Example:

In this example, we assume that you have created fresh Laravel application. We also assume that you have confiured database connection.

Migration

We already have users migration class at database/migrations directory, so we only need to create posts migration with following command:

php artisan make:migration create_posts_table

In the posts migration, we have defined the following fields. Note that we have added user_id(forengn_key) field which relates with the id(local_key) field of users table. Below is the posts migration fields:

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->integer('user_id')->unsigned();
        $table->integer('title');
        $table->boolean('body');
        $table->timestamps();

        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}

In this example, we don't need to add or modify users migration. Below are the users migration field.

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();
});

Run the migrate command to create tables into database.

php artisan migrate

Model

Laravel model located at app/Models directory. Create a Post model using following Artisan command.

php artisan make:model Post

Now, you need to create posts method into User model.

There is already User model in the new Laravel application. Open User model and add posts() method which will define relationship between User and Post model.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * Get the posts associated with the user.
     */
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

The eloquent will automatically checks that you have user_id field in the posts table which relates to id field of users table.

To define reverse relationship, i.e., if you already have post model and we want to find user model by relationship, we need to put user method into Post model.

<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

    /**
     * Get the user associated with the post.
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Route

In routes/web.php file, we have added new route for relationship testing.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/post', [PostController::class, 'index']);

Controller

As we have added route, also create PostController with following command.

php artisan make:controller PostController

Find all posts of a user

Open the controller at app/Http/Controllers/PostController and create index method.

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $posts = User::find(1)->posts;

    dd($posts);
}

This will return all posts record with the user_id of 1. As all the relationship serve as query builder, you may also constraints in posts() method.

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $posts = User::find(1)->posts()
        ->where('title', 'like', '%Laravel%')
        ->get();

    dd($posts);
}

Find user record that is belongs to post model

Now suppose you want to find user record by post model, i.e., reverse relationship, here is how to access user record.

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $user = Post::find(1)->user;

    dd($user);
}

You can even get single value from the relationship, for example, you only want user email address of application, you may get only email address of application.

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $email = User::find(1)->user->email;

    dd($email);
}

I hope this will help you to understand one to many eloquent relationship.