Починається все з простого $user->is_admin, далі зʼявляється редактор, потім модератор - і умови розповзаються по коду.
Крок перший - роль як enum:
enum Role: string
{
case Admin = 'admin';
case Editor = 'editor';
case Author = 'author';
}
Це вже краще за рядки, але перевірки виду $user->role === Role::Editor розкидані по контролерах ламаються, щойно права ролі змінюються.
Крок другий - права, а не ролі. Код питає «чи можна публікувати», а не «чи ти редактор»:
Gate::define('publish', fn (User $user) => $user->hasPermission('publish'));
Роль стає лише набором прав, і зміна набору не потребує правок у коді.
Policy для дій над моделлю:
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->hasPermission('posts.update')
|| $post->author_id === $user->id;
}
}
before() для суперкористувача - щоб не дублювати перевірку в кожному методі:
public function before(User $user): ?bool
{
return $user->isAdmin() ? true : null;
}
Повертати треба саме null, а не false: false заборонить дію остаточно й не дасть іншим методам відпрацювати.
Коли брати пакет. spatie/laravel-permission дає ролі, права й кеш перевірок з коробки. Він доречний, коли набір прав змінюють з адмінки; якщо ролей три й вони зашиті в код, enum із Policy простіший.
Що не забути: перевірки прав кешуються не самі - на кожен запит це кілька звернень до бази, тому права користувача варто завантажувати разом із ним.