The relationship management between data entities is a pivotal aspect of building robust applications. Laravel offers an elegant and efficient solution for dealing with database relationships through its Eloquent ORM. One such relationship is the hasMany relationship. It enables developers to establish and manage one-to-many associations between database tables. In our last post, we worked on the hasOne Relationship in Laravel 10 by implementing a demo application. In this article, we will delve into the concept of the hasMany relationship in Laravel 10. Also, we will understand its mechanics, and explore how to wield its power in your Laravel applications.
Before diving into the implementation of hasMany relationship, let’s quickly know what it is actually.
What is hasMany Relationship?
The hasMany relationship is a cornerstone of the Eloquent ORM in Laravel. It denotes a one-to-many relationship between two database tables. In this scenario, a record in the parent table can be associated with multiple records in the child table. This is used for creating a rich and interconnected data structure in Laravel projects.
Let’s take a look at what we are going to create in this post.
In this result, you can see that every user has 3 todos. So, it comes under a one-to-many relationship.
Now, let’s move ahead to the post to implement this functionality.
How to Create a Pagination Using Bootstrap in Laravel 10
Prerequisites
In this post, we are going to cover the Laravel Eloquent relationship. Inside this, we will be implementing the hasMany relationship in Laravel 10. Therefore, you will require to have the below configurations.
- PHP >=8.1
- Composer
- Apache/Nginx Server
- VS Code Editor (Optional)
- MySQL (version > 5)
Once, you are done with the above configuration, let’s have a project setup.
Step 1 – Create a Project For hasMany Relationship in Laravel 10
This step is optional if you already have a project setup. If not then create it using the below command.
composer create-project --prefer-dist laravel/laravel app
After the project setup, let’s configure the database.
How to Use Tailwind CSS in Laravel 10 For Interactive Designs
Step 2 – Configure a Database in Laravel 10
In order to configure a database, you will require a database first. So, I am assuming you’ve already created that.
Therefore navigate to the .env file and add the DB credentials.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_blog
DB_USERNAME={{ DATABASE_USERNAME }}
DB_PASSWORD={{ DATABASE_PASSWORD }}
Next, you will require models and migrations for creating tables and relationships.
Step 3 – Create Models and Migrations For hasMany Relationship in Laravel 10
We are going to achieve hasMany relationships in Laravel. Therefore you will require to have at least two models and migrations. Hence, let’s create them one by one.
With the Laravel project setup, there is a default model and migration for the user. You can use that one as well. However, you can create another model if needed.
Currently, I am going to use the user model. But will create a second model for Todos. I will create a relationship between the user and the todo table.
php artisan make model:Todo -m
The command will create a model and a migration for the todo.
After that, let’s add the schema in both migrations (user and todos).
How to Create and Use Custom Helper Function in Laravel 10
Step 4 – Add Schema in Migrations
Start adding migration from the users migration first. I am just going with the default fields for this migration just for demonstration purposes. However, you can add more fields in the migration as per your need.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
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();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
}
};
Similarly, add the below schema in the todos table migration.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('todos', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('title')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('todos');
}
};
After that, you will have to migrate the tables using the below command.
php artisan migrate
Next, you have to put the fillable property in these models.
Get the Last Inserted Id in Laravel 10 Using Different Methods
Step 4 – Add Fillable Data in Models
According to the migration fields, you will have to define the fillable property. So, add the below snippet in the respective models.
Start with the User model first.
<?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;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
Next, add the fillable property in the Todo model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Todo extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'title',
'description'
];
}
We are done with the model and migration. Next, you will need to create a hasMany relationship in Laravel 10.
How to Implement Repository Design Pattern in Laravel 10
Step 5 – Create hasMany Relationship in Laravel 10
We will be creating hasMany relationship between User and Todo. So, the relationship definition will be User has Many Todos. Therefore navigate to the User model and add the below function in that.
public function todos(): hasMany {
return $this->hasMany(Todo::class, 'user_id', 'id');
}
After adding this function, the User model will become like this.
<?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;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
/**
* Function : Relation for Todos
* @relationType : hasMany
* @return todos
*/
public function todos() {
return $this->hasMany(Todo::class, 'user_id', 'id');
}
}
With the above snippet, the relation is created. Now we can fetch the data based on this relation.
But, we don’t have data yet to test this flow. Therefore, we will be using the factory faker class to generate some dummy data based on this relation.
Step 6 – Create Factory Class For Generating Dummy Records
By default, there will be a factory class for the user model. Hence, we are required to create another factory class for the Todo model. Hence, let’s create it quickly.
php artisan make:factory UserFactory --model=User
and
php artisan make:factory TodosFactory --model=Todo
After having the factory classes, let’s put some property to generate dummy data.
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
Similarly, you will need to add this for the TodoFactory class.
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Todo>
*/
class TodoFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'title' => fake()->sentence(),
'description' => fake()->paragraph(),
];
}
}
Now, you are done with generating dummy data using the fake class for these two tables.
After that, you will need to execute these factory classes. So that it will save some data in the respective tables.
Here I will be using the seeder class to seed data into these tables.
Step 7 – Seed Dummy Data For hasMany Relationship in Laravel 10
For seeding the dummy data for testing purposes, you will have to navigate to the DatabaseSeeder.php file. This comes with Laravel by default. So, you can use this seeder class to generate dummy data.
Add the below snippet in it.
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\Todo;
use Illuminate\Database\Seeder;
use App\Models\User;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
User::factory(10)->has(
Todo::factory()->count(3)
)->create();
}
}
Through the above snippet, I will create 10 users record using the factory. For every user, there will be 3 todos. That’s why I have added the Todo model factory inside the User has property. Also, we already defined the relationship.
Next, you will need to run the seeder using the below command.
php artisan db:seed
After completing the seeding process, you can check the database tables.
Here, you can check in the users table, we have the 10 records. This is what we added to the seeder count.
Also, I have the data of 3 todos per user in the todos table.
We have the data in the database now. But, we have to fetch these data using the eloquent. Therefore, we will need a controller for this.
Step 8 – Create a Controller to Fetch Data Using hasMany Relationship in Laravel 10
I am going to create a controller with the name UserController.
php artisan make:controller UserController
After having a controller, let’s write the functionality.
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Function : Fetch Users
* @param NA
* @return response
*/
public function index() {
$users = User::with('todos')->get();
return view('user-todos', compact('users'));
}
}
In the above function, I have fetched all users data along with the todos relation. However, we already defined this relation in the User model.
Next, you need. to create a view to render these data.
Step 9 – Render Data Through hasMany Relationship in Laravel 10
Firstly, create a blade file named user-todos.blade.php inside the views folder. After that add the below snippet.
<!doctype html>
<html lang="en">
<head>
<title>Has Many Relationship in Laravel 10</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-iYQeCzEYFbKjA/T2uDLTpkwGzCiq6soy8tYaI1GyVh/UjpbCx/TYkiZhlZB6+fzT" crossorigin="anonymous">
<style>
.table {
vertical-align: middle;
}
</style>
</head>
<body>
<div class="container-fluid px-5 pt-3">
<h4 class="text-center fw-bold border-bottom pb-3"> Has Many Relationship in Laravel 10 </h4>
<div class="table-responsive pt-1">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="5%">Id</th>
<th width="20%">Name</th>
<th>Todos List</th>
</tr>
</thead>
<tbody>
@forelse ($users as $user)
<tr>
<td>{{ $user->id }} </td>
<td>{{ $user->name }} </td>
<td>
<ol>
@foreach ($user->todos as $todo)
<li>
<dt>{{$todo->title}} </dt>
<dd> <span>- {{ $todo->description }} </span></dd>
</li>
@endforeach
</ol>
</td>
</tr>
@empty
<tr>
<td colspan="6">
<p class="text-danger">No data found </p>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
<!-- Bootstrap JavaScript Libraries -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"
integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/js/bootstrap.min.js"
integrity="sha384-7VPbUDkoPSGFnVtYi0QogXtr74QeVeeIs99Qfg5YCF+TidwNdjvaKZX19NZ/e6oz" crossorigin="anonymous">
</script>
</body>
</html>
Lastly, you need to create a route in order to test this flow.
Step 10 – Create a Web Route in Laravel 10
Last but not least, you will have to navigate to the web.php file and add a route over there.
<?php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route;
Route::get('users', [UserController::class, 'index']);
That’s it, now you are good to go with the testing. Run the application and check the result.
Enjoy coding!
Leave a Reply