Laravel 12 One-to-One Relationship: Step-by-Step Eloquent Tutorial

Hey there! If you're working with Laravel 12 and want to understand how to set up a one-to-one relationship between two database tables, you're in the right place. In this beginner-friendly guide, I'll walk you through the process of creating a one-to-one relationship using Laravel's Eloquent ORM.

We'll use a simple example: a User who has one Profile. By the end, you'll know how to define models, migrations, and relationships, and how to retrieve related data.

Laravel 12 One-to-One Relationship

What is a One-to-One Relationship?

In a one-to-one relationship, a single record in one table is associated with exactly one record in another table. For example:

  1. A User has one Profile.
  2. A Profile belongs to one User.

This is useful for organizing data, like storing user details (e.g., bio, phone number) in a separate profiles table.

Prerequisites

Before we begin, ensure you have:

- A Laravel 12 project set up.

- A database configured (e.g., MySQL, SQLite).

- Basic knowledge of Laravel models, migrations, and controllers.

If you don't have a project yet, run:

laravel new example-app

Step 1: Set Up the Database and Migrations

We'll create two tables: users and profiles. The profiles table will have a foreign key linking to the users table.

Create the Users Migration

Laravel includes a default users migration. If you haven't modified it, it should already exist in database/migrations. Ensure it looks like this:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('users');
    }
};

Create the Profiles Migration

Run the following command to create a migration for the profiles table:

php artisan make:migration create_profiles_table

Open the generated migration file in database/migrations and update it:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('user_id')->unique();
            $table->string('phone')->nullable();
            $table->text('bio')->nullable();
            $table->timestamps();

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

    public function down(): void
    {
        Schema::dropIfExists('profiles');
    }
};

Explanation:

  1. user_id is a foreign key linking to the users table.
  2. The unique() constraint ensures each user has only one profile.
  3. onDelete('cascade') deletes the profile if the associated user is deleted.

Run the Migrations

Run the migrations to create the tables in your database:

php artisan migrate

Step 2: Create the Models

Next, we need to define the User and Profile models and set up their relationships.

Update the User Model

Open app/Models/User.php and add the hasOne relationship:

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Authenticatable
{
    protected $fillable = ['name', 'email', 'password'];

    public function profile(): HasOne
    {
        return $this->hasOne(Profile::class);
    }
}

Explanation: The hasOne method defines that a User has one Profile.

Create the Profile Model

Run this command to create the Profile model:

php artisan make:model Profile

Open app/Models/Profile.php and add the belongsTo relationship:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Profile extends Model
{
    protected $fillable = ['user_id', 'phone', 'bio'];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Explanation: The belongsTo method defines that a Profile belongs to a User.

Step 3: Set Up Routes and Controller

Let’s create a controller to test the one-to-one relationship and a route to access it.

Create a Controller

Run:

php artisan make:controller UserController

Open app/Http/Controllers/UserController.php and add the following code:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Profile;

class UserController extends Controller
{
    public function index()
    {
        // Create a user
        $user = User::create([
            'name' => 'John Doe',
            'email' => '[email protected]',
            'password' => bcrypt('password'),
        ]);

        // Create a profile for the user
        $user->profile()->create([
            'phone' => '123-456-7890',
            'bio' => 'Web developer and tech enthusiast.',
        ]);

        // Retrieve the user with their profile
        $userWithProfile = User::with('profile')->first();

        return response()->json([
            'user' => $userWithProfile->name,
            'email' => $userWithProfile->email,
            'profile' => [
                'phone' => $userWithProfile->profile->phone,
                'bio' => $userWithProfile->profile->bio,
            ],
        ]);
    }
}

Explanation:

  1. Creates a user and associates a profile.
  2. Uses with('profile') to eager-load the profile data.
  3. Returns a JSON response with the user and profile details.

Define a Route

Open routes/web.php and add:

<?php

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

Route::get('/test-relationship', [UserController::class, 'index'])->name('test.relationship');

Step 4: Test the Relationship

Start your Laravel server:

php artisan serve

Visit http://localhost:8000/test-relationship in your browser. You should see a JSON response like:

{
    "user": "John Doe",
    "email": "[email protected]",
    "profile": {
        "phone": "123-456-7890",
        "bio": "Web developer and tech enthusiast."
    }
}

This confirms the one-to-one relationship is working!

Step 5: Using the Relationship in Your Application

You can access related data in various ways:

Retrieve a User’s Profile

$user = User::find(1);
$profile = $user->profile; // Returns the associated Profile
echo $profile->phone; // Outputs: 123-456-7890

Retrieve a User from a Profile

$profile = Profile::find(1);
$user = $profile->user; // Returns the associated User
echo $user->name; // Outputs: John Doe

In a Blade Template

Create a Blade file resources/views/user.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>Laravel 12 One-to-One Relationship</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h3>User Profile</h3>
        <p><strong>Name:</strong> {{ $user->name }}</p>
        <p><strong>Email:</strong> {{ $user->email }}</p>
        <p><strong>Phone:</strong> {{ $user->profile->phone }}</p>
        <p><strong>Bio:</strong> {{ $user->profile->bio }}</p>
    </div>
</body>
</html>

Update the UserController to return the view:

public function index()
{
    $user = User::with('profile')->first();
    return view('user', compact('user'));
}

Visit http://localhost:8000/test-relationship to see the user’s profile displayed.

Conclusion

Setting up a one-to-one relationship in Laravel 12 is straightforward with Eloquent ORM! In this tutorial, you learned how to create migrations, define models, set up relationships, and retrieve related data.

Whether you're building user profiles or other linked data, this approach keeps your database organized and efficient. I hope this guide was easy to follow and helps you implement one-to-one relationships in your Laravel projects.

Frequently Asked Questions (FAQs)

Q1: What’s the difference between hasOne and belongsTo?
A: hasOne is used on the model that owns the relationship (e.g., User has one Profile). belongsTo is used on the model that is owned (e.g., Profile belongs to a User).

Q2: Why use a separate profiles table instead of adding columns to users?
A: A separate table keeps the users table clean and is useful when profile data is optional or complex. It also improves performance for queries that don’t need profile data.

Q3: What does onDelete('cascade') do?
A: It ensures that if a user is deleted, their associated profile is also deleted automatically, maintaining data integrity.

Q4: How do I handle cases where a user has no profile?
A: Check if the profile exists: $user->profile ? $user->profile->phone : 'No profile'. You can also use optional($user->profile)->phone to avoid errors.

Q5: Can I create the profile automatically when a user is created?
A: Yes! Use a model event or observer. For example, in User.php:

protected static function booted()
{
    static::created(function ($user) {
        $user->profile()->create(['phone' => 'N/A', 'bio' => 'No bio yet']);
    });
}

 


You might also like:

techsolutionstuff

Techsolutionstuff | The Complete Guide

I'm a software engineer and the founder of techsolutionstuff.com. Hailing from India, I craft articles, tutorials, tricks, and tips to aid developers. Explore Laravel, PHP, MySQL, jQuery, Bootstrap, Node.js, Vue.js, and AngularJS in our tech stack.

RECOMMENDED POSTS

FEATURE POSTS