Write your policies fluently in Laravel.
<?php
class PostPolicy extends FluentPolicy
{
public function delete(User $user, Post $post): Response
{
return $this->denyWhen($post->user_id !== $user->id)
->denyWhen($post->published_at !== null)
->allow();
}
}You can install the package via composer:
composer require soyhuce/laravel-fluent-policyThe goal of this package is to write your policies more easily in a clean syntax.
For exemple, the following policy:
<?php
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
public function delete(User $user, Post $post): bool
{
if ($post->user_id !== $user->id) {
return false;
}
if ($post->published_at !== null) {
return false;
}
return true;
}
}can be re-written as:
<?php
use Illuminate\Auth\Access\Response;
use Soyhuce\FluentPolicy\FluentPolicy;
class PostPolicy extends FluentPolicy
{
public function delete(User $user, Post $post): Response
{
return $this->denyWhen($post->user_id !== $user->id)
->denyWhen($post->published_at !== null)
->allow();
}
}You can customise the response if needed :
return $this->denyWhen($post->published_at !== null, 'You cannot delete a published post')
->allow();You can also call another policy or gate this way :
return $this->authorize($user, 'update', $post)
->allowWhen($post->published_at === null)
->deny();You can deny the policy returning a custom http status code :
return $this->denyWithStatusWhen($post->user_id !== $user->id, 404)
->allow();
// or $this->>allowWhen(...)->denyWithStatus(404);In the case of 404 status code, you can use the shortcut
return $this->denyAsNotFoundWhen($post->user_id !== $user->id)
->allow();
// or $this->>allowWhen(...)->denyAsNotFound();The different branches allowWhen and denyWhen are evaluated lazily which mean that the following code is completely
correct :
<?php
use Illuminate\Auth\Access\Response;
use Soyhuce\FluentPolicy\FluentPolicy;
class PostPolicy extends FluentPolicy
{
public function delete(User $user, Post $post): Response
{
// Here, $post->published_at is Carbon or null
return $this->denyWhen($post->user_id !== $user->id)
->allowWhen($post->published_at === null) // 1
->allowWhen($post->published_at->isFuture()) // 2
->deny();
}
}2 will only be called if previous branches are all false. We are sure that here $post->published_at is not null
thanks to 1.
When running PHPStan on
public function delete(User $user, Post $post): Response
{
return $this->denyWhen($post->user_id !== $user->id)
->allowWhen($post->published_at === null) // 1
->allowWhen($post->published_at->isFuture()) // 2
->deny();
}an error is raised on 2 (Cannot call method isFuture on Carbon|null).
An extension is available to fix this issue and should be included in your phpstan.neon file.
includes:
- vendor/bin/soyhuce/laravel-fluent-policies/extension.neonUnfortunately, due to a PHPStan limitation, you still have to rewrite your policy a little bit :
public function delete(User $user, Post $post): Response
{
$this->denyWhen($post->user_id !== $user->id)
->allowWhen($post->published_at === null);
// From here, PHPStan understands that $post->published_at is not null
return $this->allowWhen($post->published_at->isFuture())
->deny();
}composer testPlease see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.