In the world of web development, managing relationships between data entities is a fundamental aspect. Laravel, a powerful PHP framework, offers an elegant and intuitive way to handle database relationships. This is done through its Eloquent ORM (Object-Relational Mapping) system. The Laravel eloquent relationship plays a pivotal role in structuring and organizing your database models. There are different types of relationships provided by Laravel. Like hasOne, hasMany, belongsTo, etc. In this post, mainly, we will be focusing on the hasOne relationship in Laravel 10. However, we will see others as well in the upcoming posts in this series.
So, we are going to achieve this listing with hasOne Relationship in Laravel 10.
Hence, let’s proceed to the post quickly.
Prerequisites
In this post, we are going to discuss the Laravel Eloquent relationship. Inside this, we will be implementing the hasOne 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.
How to Create a Pagination Using Bootstrap in Laravel 10
Step 1 – Project Setup to Implement hasOne Relationship in Laravel 10
This step is optional in case if you already have a project setup. If not, then you can go ahead for creating a project.
composer create-project --prefer-dist laravel/laravel laravel-relation
Once, you are done with the project setup, let’s configure the database.
Step 2 – Create and Configure a Database in Laravel 10
In this step, we will create a database and then will connect it with our application. Hence, for connecting the database, navigate to the .env file. Thereafter add the DB credentials under the DB section.
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 to have at least two models and migrations to create a hasOne relationship in Laravel 10.
How to Use Tailwind CSS in Laravel 10 For Interactive Designs
Step 3 – Create Models and Migrations in Laravel 10
We will be creating a hasOne relationship in Laravel 10. For this, you will require two models so that we can make a relation using eloquent between these two models.
I will try to demonstrate the relation from User to Profile. create tw
php artisan make:model User -m
php artisan make:model UserProfile -m
By default, Laravel comes up with the User model and migration. Therefore, you can skip that model creation.
Step 4 – Add Schema in the Migrations and Setup Foreign Key
We have two migrations one is for the users and the second one we created for user profile. So, let’s start adding the schema from the user table itself.
<?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');
}
};
Next, you have to add the schema in the user_profiles_table migration. This table will consists a foreign key for users table. Hence, take a look at the below schema and add the same.
<?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('user_profiles', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->string('phone_number', 25)->nullable();
$table->string('alternate_phone', 25)->nullable();
$table->string('alternate_email', 50)->nullable();
$table->string('address', 100)->nullable();
$table->string('city', 50)->nullable();
$table->string('zip_code', 15)->nullable();
$table->string('state', 50)->nullable();
$table->string('country', 50)->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_profiles');
}
};
After adding the above migrations, you need to migrate the schema using the below command.
php artisan migrate
Next, you need to add a fillable data array in each model. So, let’s do that.
How to Create and Use Custom Helper Function in Laravel 10
Step 5 – Add Mass Assignment in Models
Navigate to the models. Start from the User model and add the below fillable properties.
<?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',
];
}
Similarly, you need to add in the User Profile model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class UserProfile extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'phone_number',
'alternate_phone',
'alternate_email',
'address',
'city',
'zip_code',
'country',
];
}
The model fillable property is done. Thereafter, you need to create a relation function in the User model.
Get the Last Inserted Id in Laravel 10 Using Different Methods
Step 6 – Create hasOne Relationship in Laravel 10
The hasOne relationship works upon one-to-one relation between two tables. For establishing this relation, we already have two models, and based on that we defined the foreign key as well. Now, we have to work on the data using hasOne relation.
According to our migration schema, we created the foreign key relation from Users table to User Profiles table. So, every user will have one profile detail. Which is referring to the user profiles table.
Take a look at the below snippet. I have created a function in which I have defined a hasOne relation in the User model class.
public function userProfile() {
return $this->hasOne(UserProfile::class, 'user_id', 'id');
}
After adding this relation, the 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 : hasOne Relation for user profile
*/
public function userProfile() {
return $this->hasOne(UserProfile::class, 'user_id', 'id');
}
}
We have defined the relation successfully. However, we don’t have the data yet to test this relation flow. Hene, let’s create some dummy data using the factory class.
Step 7 – Create Factory Class For Creating Dummy Records in Laravel 10
For testing purposes, we will be using the faker property through the factory class to feed data in both tables. Therefore, you need to create these two factory classes using the below command.
By default, Laravel provides a UserFactory class for seeding dummy data for the users table.
php artisan make:factory UserFactory --model=User
You need to create another one for feeding user profile data.
php artisan make:factory UserProfileFactory --model=UserProfile
So, you can take a look at the below screenshot. I have created only the UserProfileFactory class.
After that, you will have to add fake attributes as per the specified columns in the migrations.
Step 8 – Add Fake Attribute For Inserting Records in Factory Class
In order to create fake data for corresponding columns, you will have to specify the type of data. The fake() class, provides various data types attribute as shown below.
<?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 have to add in the UserProfileFactory class.
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\UserProfile>
*/
class UserProfileFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'phone_number' => fake()->phoneNumber(),
'alternate_phone' => fake()->phoneNumber(),
'alternate_email' => fake()->unique()->safeEmail(),
'address' => fake()->address(),
'city' => fake()->city(),
'zip_code' => fake()->postcode(),
'state' => fake()->city(),
'country' => fake()->country(),
];
}
}
After adding the fake properties the next challenge is to save the dummy data along with the relation. However, we can achieve this. So, let’s jump to the next step quickly.
Step 9 – Seed Dummy Data with hasOne Relationship in Laravel 10
We are ready with factory classes to create dummy data for each table. But we are working on a relation and defined it already using foreign key concepts. Therefore the data must be saved in the same order using the factory class.
Let’s see how you can achieve this in Laravel using Seeder.
By default, Laravel provides a seeder class named DatabaseSeeder.php. So, navigate to this file and add the below snippet over there.
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\UserProfile;
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(
UserProfile::factory(1)->count(1)
)->create();
}
}
Let me explain the above line.
- I have called the factory() class for the user and passed the count. This counts specifies the dummy records which are going to be inserted in the users table.
- Along with this, I have used has() function in which I have passed the next model which is UserProfile. This model is the relation of the User model. Also, we already defined the relationship in the User model. Hence Laravel will understand automatically that every user hasOne user profile.
That’s it, now next, you have to run the seeder.
Step 10 – Run the Seeder in Laravel 10 to Create Dummy Records
For seeding data in both tables using the seeder, you will have to run the below command.
php artisan db:seed
The command will execute both factory classes added in the database seeder class.
After seeding the database, you can fetch the user records along with the user profile.
Step 11 – Use hasOne Relation to Fetch Data From Database Model
You need to create a controller at this step to write an eloquent query.
php artisan make:controller UserController
After creating the controller, let’s put a function to fetch data.
<?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('userProfile')->get();
return view('users', compact('users'));
}
}
In the above code, I have fetched the users data along with the profile details and then returned the data into the view.
Step 12 – Create a View to Render Data Using hasOne Relationship in Laravel 10
Inside the views folder, simply create a view named users.blade.php. After that add the below snippet.
<!doctype html>
<html lang="en">
<head>
<title>Has One 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 One Relationship in Laravel 10 </h4>
<div class="table-responsive pt-5">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Phone Number</th>
<th>Address</th>
</tr>
</thead>
<tbody>
@forelse ($users as $user)
<tr>
<td>{{ $user->id }} </td>
<td>{{ $user->name }} </td>
<td>
<p>Primary: {{ $user->email }} <br />
Alternate: {{ $user->userProfile->alternate_email ?? '-' }}
</p>
</td>
<td>
<p>Primary: {{ $user->userProfile->phone_number }} <br />
Alternate: {{ $user->userProfile->alternate_phone ?? '-' }}
</p>
</td>
<td>
<p>Address: {{ $user->userProfile->address }} <br />
City: {{ $user->userProfile->city }} <br />
State: {{ $user->userProfile->state }} <br />
Country: {{ $user->userProfile->country }} <br />
{{ $user->userProfile->zip_code }}
</p>
</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>
At last, add a route for this.
Step 13 – Add Route to Render hasOne Relation Data
Navigate to the web.php file and add the below route over there.
<?php
use App\Http\Controllers\UserController;
use Illuminate\Support\Facades\Route
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/
Route::get('users', [UserController::class, 'index']);
That’s it for the functionality. Now, you can run the application to test the result.
I am wrapping up this post. If you have any doubts or suggestions then don’t forget to write us in the comment section. I will try. to resolve your queries.
Leave a Reply