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:
- one to one
- one to many
- many to many
- has one of many
- has one through
- has many through
- one to one polymorphic
- one to many polymorphic
- many to many polymorphic
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.
Copyright 2023 ErrorGram