New

Just launched: Vueblocks, a brand-new search engine for Vue packages! Explore Vueblocks →

soyhuce/laravel-fluent-policy

Write fluent policies in Laravel
14,214 2
Install
composer require soyhuce/laravel-fluent-policy
Latest Version:1.9.0
PHP:^8.3
Laravel:11 · 12
Older releases:9 · 10
License:MIT
Last Updated:Apr 21, 2026
Links: GitHub  ·  Packagist
Maintainer: SoyHuCe

Write fluent policies in Laravel

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status GitHub PHPStan Action Status Total Downloads

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();
    }
}

Installation

You can install the package via composer:

composer require soyhuce/laravel-fluent-policy

Usage

The 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();

Custom Http status

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();

Lazy evaluation

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.

PHPStan

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.neon

Unfortunately, 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();
}

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

Related Packages

soyhuce/phpstan-extension

Extra rules for phpstan analysis

23,747 1
soyhuce/dev-tools

Laravel dev-tools

17,145 1
soyhuce/laravel-testing

Helpers for Laravel tests

15,875 3
soyhuce/laravel-json-resources

An opinionated JsonResource for Laravel

15,204 2
soyhuce/laravel-model-injection

Extended Model injection for Laravel

14,848 0

Version History

Version Released PHP Laravel License
1.9.0 ^8.3 ^11.0|^12.0 MIT
1.8.0 ^8.3 ^11.0|^12.0 MIT
1.7.0 ^8.3 ^11.0 MIT
1.6.0 ^8.2 ^10.0 || ^11.0 MIT
1.5.0 ^8.2 ^10.0 MIT