henzeb/laravel-pennant-gated
Composer 安装命令:
composer require henzeb/laravel-pennant-gated
包简介
A Pennant driver that gates per-scope features behind a global switch
README 文档
README
This package adds a gated driver for Laravel Pennant that wraps any
other Pennant store and turns its global (unscoped) value into a switch that governs every scope at once, without
ever touching their stored values.
Why
When you activate a Pennant feature for a scope, it becomes active for that scope immediately. There is no way to configure who a feature is intended for without also making it live for them right away, and no single switch that governs every scope a feature has ever been activated for:
Feature::for($betaUser)->activate('new-checkout'); Feature::for($betaUser)->active('new-checkout'); // true, live immediately
Pennant does provide Feature::deactivateForEveryone() to turn a feature off in a single call, but it does so by
overwriting the stored value for every scope with false. The information about which scopes it was active for is
gone. Turning the feature back on for the same scopes means activating each of them again.
The gated driver separates these two concerns. A scoped activation records who the feature is intended for,
while the global (unscoped) value determines whether that targeting is currently in effect. A scoped check is only
true when the feature is active both for that scope and globally:
// Configure who the feature is for. It is not active yet, because the // global value has not been activated. Feature::store('gated')->for($betaUser)->activate('new-checkout'); Feature::store('gated')->for($otherUser)->activate('new-checkout'); Feature::store('gated')->for($betaUser)->active('new-checkout'); // false // Activate the feature globally. Every scope that was already configured // becomes active immediately, without being activated individually. Feature::store('gated')->activate('new-checkout'); Feature::store('gated')->for($betaUser)->active('new-checkout'); // true Feature::store('gated')->for($otherUser)->active('new-checkout'); // true // Deactivate the feature globally. The scoped configuration is left // untouched. Feature::store('gated')->deactivate('new-checkout'); Feature::store('gated')->for($betaUser)->active('new-checkout'); // false // Activate it globally again. Both scopes are active again, with no // further changes required. Feature::store('gated')->activate('new-checkout'); Feature::store('gated')->for($betaUser)->active('new-checkout'); // true
Because the gated driver is a thin wrapper, it works with whichever store you already use for the feature's
underlying values, such as database or array, or a custom driver of your own.
Installation
composer require henzeb/laravel-pennant-gated
Add a gated entry to the stores section of config/pennant.php, pointing store at whichever other store
should be gated:
'stores' => [ 'gated' => [ 'driver' => 'gated', 'store' => 'database', ], // Pennant's built-in stores, e.g.: 'database' => [ 'driver' => 'database', ], ],
How it works
get($feature, $scope) on the underlying driver is checked twice:
get(feature, scope): if scope is null: return underlying->get(feature, null) // the global value, unchanged if not underlying->get(feature, null): return false // global kill-switch is off return underlying->get(feature, scope) // otherwise, defer to the scoped value
So:
Feature::active()(no scope) behaves exactly like the underlying driver.Feature::for($user)->active()istrueonly when the feature is active both globally and for$user.
This applies to value() too, since it shares the same gating: if the feature carries a payload rather than a plain
boolean, the scoped payload is only returned once the global gate is open.
Feature::store('gated')->activate('discount', ['percentage' => 10]); Feature::store('gated')->for($user)->activate('discount', ['percentage' => 25]); Feature::store('gated')->for($user)->value('discount'); // ['percentage' => 25] Feature::store('gated')->deactivate('discount'); Feature::store('gated')->for($user)->value('discount'); // false, the gate is closed
Everything else — define, set, setForAllScopes, delete, purge, and, where supported by the underlying
driver, definedFeaturesForScope, stored, setAll and flushCache — is delegated straight through to the
underlying store.
Testing this package
composer test
Security
If you discover any security related issues, please email henzeberkheij@gmail.com instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-05