Courses

Roles and Permissions in Laravel 12

Adding Spatie/Laravel-Permission Package

You're reading a FREE PREVIEW of a PREMIUM course.
Summary of this lesson:
- Installing and configuring spatie/laravel-permission
- Converting custom roles to Spatie implementation
- Updating Policy to use Spatie role checks
- Modifying user registration for default role
- Adapting tests to work with Spatie methods

Video Version of the Lesson

[Only for premium members]

Link to the repository

[Only for premium members]

One of the most typical questions I received when preparing for this course was, "Will you use the Spatie Permissions package?"

And I thought, "Why not BOTH". So, first, I've shown you how to use gates/policies without any packages, and now it's time to show the "other side".


Starting Point

We will work on the same project but take its "earlier" point. Imagine we have Gates without Policies.

app/Http/Controllers/TaskController.php

class TaskController extends Controller
{
public function index(): View
{
$tasks = Task::with('user')->get();
 
return view('tasks.index', compact('tasks'));
}
 
public function create(): View
{
Gate::authorize('create', Task::class);
 
return view('tasks.create');
}
 
public function store(Request $request): RedirectResponse
{
Gate::authorize('create', Task::class);
 
Task::create($request->only('name', 'due_date')
+ ['user_id' => auth()->id()]);
 
return redirect()->route('tasks.index');
}
 
public function edit(Task $task): View
{
Gate::authorize('update', $task);
 
return view('tasks.edit', compact('task'));
}
 
public function update(Request $request, Task $task): RedirectResponse
{
Gate::authorize('update', $task);
 
$task->update($request->only('name', 'due_date'));
 
return redirect()->route('tasks.index');
}
 
public function destroy(Task $task): RedirectResponse
{
Gate::authorize('delete', $task);
 
$task->delete();
 
return redirect()->route('tasks.index');
}
}

And then we have @can checks in the Blade file.

resources/views/tasks/index.blade.php

<div class="min-w-full align-middle">
@can('create', \App\Models\Task::class)
<a href="{{ route('tasks.create') }}" class="underline">Add new task</a>
<br /><br />
@endcan
<table class="min-w-full border divide-y divide-gray-200">
<thead>
...
</thead>
 
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
@foreach($tasks as $task)
<tr class="bg-white">
 
...
 
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
@can('update', $task)
<a href="{{ route('tasks.edit', $task) }}" class="underline">Edit</a>
@endcan
@can('delete', $task)
|
<form action="{{ route('tasks.destroy', $task) }}"
method="POST"
class="inline-block"
onsubmit="return confirm('Are you sure?')">
@method('DELETE')
@csrf
<button type="submit" class="text-red-600 underline">Delete</button>
</form>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
</div>

Now, let's install the package and configure its roles.


Installing Spatie Permissions Package

We'll do everything according to basic official documentation.

composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

Then, we need to add a trait to our User Model and remove our own roles implementation:

app/Models/User.php

use Spatie\Permission\Traits\HasRoles;
 
// ...
 
class User extends Authenticatable
{
use HasFactory, Notifiable;
use HasRoles;
 
// ...
 
protected $fillable = [
'name',
'email',
'password',
'role_id',
];
 
// ...
 
public function role(): BelongsTo
{
return $this->belongsTo(Role::class);
}
}

We also removed the role_id and the relationship we had in the beginning. It will all be saved in the...

The full lesson is only for Premium Members.
Want to access all 13 video+text lessons of this course? (57 min)

You also get:

  • 77 courses
  • Premium tutorials
  • Access to repositories
  • Private Discord