yaroslavpopovic / laravel-policy-soft-cache
Fork of innoge/laravel-policy-soft-cache that keys cache entries by spl_object_id, removing the json_encode + sha512 overhead for high-volume policy checks.
Package info
github.com/yaroslavpopovic/laravel-policy-soft-cache
pkg:composer/yaroslavpopovic/laravel-policy-soft-cache
Requires
- php: ^8.1
- illuminate/contracts: ^9.0|^10.0|^11.0|^12.0|^13.0
- spatie/laravel-package-tools: ^1.13.0
Requires (Dev)
- laravel/pint: ^1.0
- nunomaduro/larastan: ^2.0.1
- orchestra/testbench: ^7.0|^8.25|^9.6|^10.0|^11.0
- pestphp/pest: ^1.0|^2.0|^3.0
- pestphp/pest-plugin-laravel: ^1.0|^2.0|^3.0
README
This is a fork of
innoge/laravel-policy-soft-cacheby Tim Geisendörfer. All credit for the original design, API, and implementation goes to the upstream author. This fork only diverges on the cache-key strategy — see below.
Optimize your Laravel application's performance with soft caching for policy checks. This package caches policy invocations to prevent redundant checks within the same request lifecycle, enhancing your application's response times.
Why this fork
The upstream package keys its in-memory cache by hashing every argument with hash_hmac('sha512', json_encode($args), config('app.key')). That's robust against in-request model mutations (any attribute change invalidates the key automatically), but on workloads that perform many policy checks per request — for example a Filament 5 table where each row renders an ActionGroup with 7+ actions and Filament re-evaluates isVisible() / isDisabled() / isAuthorized() multiple times per action — the key generation cost alone becomes the bottleneck.
In a real-world Filament list page (≈40 records, ~760 Gate::check calls during a single unmountAction re-render), we measured:
| Key strategy | Cost per Gate::check |
Overhead for the whole request |
|---|---|---|
hash_hmac('sha512', json_encode($args), app.key) (upstream) |
~0.72 ms | ~550 ms |
spl_object_id($model) (this fork) |
~0.0003 ms | <1 ms |
End-to-end the difference moved the same Livewire unmountAction request from 9.95 s → 6.6 s in the application that motivated the fork.
This fork swaps the key strategy: object arguments are fingerprinted by get_class($obj).':'.spl_object_id($obj), scalars are stringified, and non-Eloquent objects/arrays still fall back to a fast xxh3 hash. The cache is hit only for the same in-memory instance — which is what Filament (and most rendering loops) actually pass during a single render, so the practical hit rate is unchanged for the use case the package was built for.
If you need staleness-on-mutation semantics (the cache key invalidating when a model attribute changes within the same request) please use the upstream package — that's exactly what its json strategy is for.
Requirements
PHP ≥ 8.1, Laravel 9 / 10 / 11 / 12 / 13.
Installation
composer require yaroslavpopovic/laravel-policy-soft-cache
Optionally publish the config file:
php artisan vendor:publish --provider="Innoge\LaravelPolicySoftCache\LaravelPolicySoftCacheServiceProvider"
return [ /* * When enabled, the package will cache the results of all Policies in your Laravel application */ 'cache_all_policies' => env('CACHE_ALL_POLICIES', true), ];
Usage
By default, all policy calls are cached for the lifetime of the current request. To opt in selectively instead, set CACHE_ALL_POLICIES=false and mark the policies you want cached with Innoge\LaravelPolicySoftCache\Contracts\SoftCacheable:
use Innoge\LaravelPolicySoftCache\Contracts\SoftCacheable; class UserPolicy implements SoftCacheable { // ... }
Clearing the cache
\Innoge\LaravelPolicySoftCache\LaravelPolicySoftCache::flushCache();
Known issues
Gate::before and Service Provider load order
If your application registers a Gate::before callback (typically in AuthServiceProvider), Laravel's package auto-discovery may load this provider before yours, which means your Gate::before runs first and can short-circuit the cache. To enforce explicit load order, register the provider manually and disable auto-discovery for this package:
-
Add
\Innoge\LaravelPolicySoftCache\LaravelPolicySoftCacheServiceProvider::classat the end ofbootstrap/providers.php(Laravel 11+) orconfig/app.phpprovidersarray. -
In your
composer.json:"extra": { "laravel": { "dont-discover": ["yaroslavpopovic/laravel-policy-soft-cache"] } }
-
Run
composer installso the change takes effect.
Testing
composer test
Credits
- Tim Geisendörfer — original author of
innoge/laravel-policy-soft-cache. All the package architecture, theSoftCacheableinterface, and theGate::beforehook strategy are his work. - Yaroslav Popovic — fork maintainer, swapped the cache-key strategy to
spl_object_idfor high-throughput rendering use cases. - Upstream contributors
License
MIT. See LICENSE.md.