DEV Community

Federica Ferletti
Federica Ferletti

Posted on

Relationship One To One in Laravel

this tutorial was made with laravel 9

There are 3 types of relationships:

  • One to One
  • One to Many
  • Many to Many

In this tutorial I will try to explain the One relation as best as possible
To One since during its realization I encountered different techniques (not always correct).

So we will create the migration, the model, the controller, seeder & factory and finally the test!

Let's begin

One To One

  1. Create a migration:

php artisan make:migration create_users_table

Schema::create('users', function (Blueprint $table) {
            $table->uuid("id")->primary();
            $table->string("name", 128);
            $table->string("surname", 128);
            $table->string("email")->unique();
            $table->string("photo")->nullable();
            $table->integer("level")->nullable();
            $table->string("password");
            $table->timestamps();
});

Schema::create('roles', function (Blueprint $table) {
            $table->uuid("id")->primary();
            $table->string("role")->unique();
            $table->uuid('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->timestamps();
});

//DOWN METHOD
public function down() n{
        Schema::drop('roles');
        Schema::drop('users');
}
Enter fullscreen mode Exit fullscreen mode

⚠️ It is important to put the deletion of the tables in the correct order, if in this example I had deleted the users table first I would have created an error as the roles table has the foreign key linked to the user.

  1. Create Model:

php artisan make:model UserModel

Models/User.php

// =====================================
// RELATIONSHIP
// =====================================

public function role()
{
    return $this->hasOne(Role::class);
}
Enter fullscreen mode Exit fullscreen mode

and now Model/Role.php

// =====================================
// RELATIONSHIP
// =====================================

public function user()
{
    return $this->belongsTo(User::class);
}
Enter fullscreen mode Exit fullscreen mode

And now we can create the updateRole method since it's the only one that cares about the relationship.
Methods like create, show, update and delete can normally be created outside the relationship.

Controller/UserController.php
php artisan make:controller UserController

use App\Models\User;
use App\Models\Role;

public function updateRole(Request $request, $uuid) {
        $user = User::find($uuid);
        $role = Role::where('user_id', $uuid)->firstOrFail();

        $validatedRoleUpdate = $request->validate([
            'role' => 'in:admin,user,student,educator',
        ]);

        $role->role = $validatedRoleUpdate['role'];
        $user->role()->save($role);

        return response()->json([
            'status' => true,
            'message' => 'User Role Update Successfully',
        ], 200);

}

Enter fullscreen mode Exit fullscreen mode

Well, now we do Seeder and Factory:
php artisan make:factory UserFactory
factories/UserFactory.php

public function definition(){
        return [ 
            'name' => fake()->name(),
            'surname' => fake()->name(),
            'email' => fake()->unique()->safeEmail(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        ];
}
Enter fullscreen mode Exit fullscreen mode

factories/RoleFactory.php

public function definition() {
        return [ 
            'role' => 'user',
        ];
}
Enter fullscreen mode Exit fullscreen mode

seeders/UserSeeder.php
php artisan make:seeder UserSeeder

$user = User::factory()
            ->has(Role::factory())
            ->create();
Enter fullscreen mode Exit fullscreen mode

Last step let's test the updateRole method
php artisan make:test UserTest --unit

/*
Command for run a specific test
./vendor/bin/phpunit --filter testUpdateRole tests/Unit/UserControllerTest.php
*/
public function testUpdateRole() {
        $id = User::all()->first()['id'];

        $response = $this->put("/api/users/{$id}/role", ['role' => 'student']);
        $response->assertStatus(200)->assertJson([
            'message' => 'User Role Update Successfully',
        ]);
}
Enter fullscreen mode Exit fullscreen mode

Well in our database we will now have a connected role created for each user and vice versa, each role has its own connected user.

For this personal project it had to be done this way, but it could just as well have added the 'role_id' field in the user table.

In the next articles I will explain how relationships between tables can get complicated!

Top comments (0)