Laravel has one of many Eloquent relationship tutorial

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:

Earlier, we have discussed one-to-many relationship between two models, we can retrieve all related records of the specific model. But sometimes, we only want to retrieve specific related record of the relationship. Let's take an example. A User model may have many Post model and we want to retrieve a latest or popular Post of specific User.

From the Laravel 8.42 version, a new has one of many relationship was included. Has one of many relation provides easy way to retrieve most recent or most oldest model from the relationship. In this example tutorial, we have describes how we can get most recent Post from specific User 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:

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->integer('user_id')->unsigned();
        $table->string('title');
        $table->integer('views');
        $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

There is already User model in the new Laravel application. Now define latestPost() method which will return hasOne relationship type combined with the ofMany method: 

<?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 latest post associated with the user.
     */
    public function latestPost()
    {
        return $this->hasOne(Post::class)->latestOfMany();
    }
}

In the same way, you may define a method which will retrieve oldest post of a relationship:

/**
 * Get the oldest post associated with the user.
 */
public function oldestPost()
{
    return $this->hasOne(Post::class)->oldestOfMany();
}

By default, the latestOfMany and oldestOfMany methods will retrieve the latest or oldest record. But, sometimes you may want to retrieve a specific record using different condition. For example you may want to retrieve the user's post with highest number of views. You can define it something like below:

/**
 * Get the user's popular post.
 */
public function popularPost()
{
    return $this->hasOne(Post::class)->ofMany('views', 'max');
}

You can even provide a clousure function as a second argument. This will provide a advance filter to result. For example, we want to retrieve a post with highest number of views but not greater than 1000 views.

/**
 * Get the user's popular post.
 */
public function popularPost()
{
    return $this->hasOne(Post::class)->ofMany(['views', 'max'], function($query) {
        $query->where('views', '<', '1000');
    });
}

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

Open the controller at app/Http/Controllers/PostController and create index method. To retrieve the latest post of the user, access latestPost property of User model.

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

    dd($post);
}

This will return latest post with the user_id of 1. Now if you want to retrieve the oldest post the user, you can use oldestPost from the User model.

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

    dd($post);
}

Or you may retrieve the post with highest number of views.

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

    dd($post);
}

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

Was this article helpful?

0 out of 0 person found this article helpful.

Leave a comment

Or

No Comment