Courses

[Mini-Course] Laravel 11: Breeze with User Role Areas

Role Model/Migrations, Seeder and Teacher Registration

Finally, let's move to the second role: teachers. Let's also enable registration for them. We will have a radio input on the register page to select a role.


Roles: Model and Migrations

First, we must take care of the backend. Let's introduce a role. We will have a Role Model and add a role relationship to the User Model. So, first, the Model with Migrations.

php artisan make:model Role -m
php artisan make:migration "add role id to users table"

app/Models/Role.php:

class Role extends Model
{
protected $fillable = [
'name',
];
}

database/migrations/xxx_create_roles_table.php:

Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});

database/migrations/xxx_add_role_id_to_users_table.php:

Schema::table('users', function (Blueprint $table) {
$table->foreignId('role_id')->constrained();
});

app/Models/User.php:

class User extends Authenticatable
{
use HasFactory, Notifiable;
 
protected $fillable = [
'name',
'email',
'password',
'role_id',
];
 
// ...
}

Now, let's seed student and teacher roles.

database/seeders/DatabaseSeeder.php:

use App\Models\Role;
 
class DatabaseSeeder extends Seeder
{
public function run(): void
{
Role::create(['name' => 'student']);
Role::create(['name' => 'teacher']);
}
}

Refresh the migrations with the seed.

php artisan migrate:fresh --seed

Registration Page: Choose Role

Next, let's add a radio input to select a role.

resources/views/auth/register.blade.php:

<x-guest-layout>
<form method="POST" action="{{ route('register') }}">
// ...
 
<!-- Role -->
<div class="mt-4">
<x-input-label for="role_id" :value="__('Register as:')" />
 
<label>
<input type="radio" name="role_id" value="1" checked /> Student
</label>
<label class="ml-2">
<input type="radio" name="role_id" value="2" /> Teacher
</label>
 
<x-input-error :messages="$errors->get('role_id')" class="mt-2" />
</div>
 
<div class="flex items-center justify-end mt-4">
<a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="{{ route('login') }}">
{{ __('Already registered?') }}
</a>
 
<x-primary-button class="ms-4">
{{ __('Register') }}
</x-primary-button>
</div>
</form>
</x-guest-layout>


Register Submit: Save Role

Finally, we must save the role to the database.

app/Http/Controllers/Auth/RegisteredUserController.php:

class RegisteredUserController extends Controller
{
// ...
 
public function store(Request $request): RedirectResponse
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
'role_id' => ['required', 'in:1,2'],
]);
 
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'role_id' => $request->role_id,
]);
 
event(new Registered($user));
 
Auth::login($user);
 
return redirect(route('student.timetable', absolute: false));
}
}

Notice: for the validation, we use the in validation rule instead of exists because we can only register with these two roles. We want users to refrain from registering with an admin role.

After registering with the teacher role in the database, we see that the correct role is set.


But now the teacher is still landing in the Student area? In the next lesson, we will start separating student and teacher areas.

Previous: Removing the Dashboard: Auto-Redirect to Student Timetable
avatar

After runing migrations, php artisan command to add role_id to users table was successful (I confirmed this using: php artisan migrate:status ) but when i chek mysql users database, I am unable to find the foreign key of role_id in users table.

I had to start the whole project again to be sure it wasn't my fault. I have also done research online as to why this is happening and also watched your youtube video titled, "Laravel Migrations: Table created but foreign key failed" but no luck

avatar

Can you show me the code of your migration file for this?

Should be:

$table->foreignId('role_id')->constrained();
avatar
You can use Markdown
avatar

is it justified to create separate table only for 2-10-N roles ? perhaps consts or enum is better ?

avatar

Yes! The key aspect when creating a separate table for roles is - flexibility. Sure, const or enum can do similar things, but over teh long run - you never know what will be needed :)

avatar
You can use Markdown
avatar
You can use Markdown