diff --git a/README.md b/README.md index 63ae453..52b9420 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Its recommended that you seed the features to your database before a new deploym ### Check If A Feature Is Enabled #### Blade View +Use the `@feature` blade directive anywhere in your view files. ```php @feature('search-v2') // new search goes here @@ -67,6 +68,7 @@ Its recommended that you seed the features to your database before a new deploym ``` #### In Your Code +Use the `FeatureFlag` facade to conveniently check the state of a feature in your app code. ```php use Codinglabs\FeatureFlags\Facades\FeatureFlag; @@ -77,6 +79,19 @@ if (FeatureFlag::isOn('search-v2')) { } ``` +#### Middleware +Register `feature` as a route middleware in your HTTP Kernel to protect routes. A 404 response will be returned if the feature does not resolve to the on state. +```php +// app/Http/Kernel.php +protected $routeMiddleware = [ + // ... + 'feature' => \Codinglabs\FeatureFlags\Middleware\VerifyFeatureIsOn::class, +]; + +// routes/web.php +Route::get('search-v2', \App\Http\Controllers\SearchV2Controller::class)->middleware('feature:search-v2'); +``` + ### Check If A Feature Is Disabled #### Blade View ```php diff --git a/src/Middleware/VerifyFeatureIsOn.php b/src/Middleware/VerifyFeatureIsOn.php new file mode 100644 index 0000000..1b197a9 --- /dev/null +++ b/src/Middleware/VerifyFeatureIsOn.php @@ -0,0 +1,17 @@ +toBeFalse(); - expect(FeatureFlag::isOff('some-feature'))->toBeTrue(); - expect(cache()->store('array')->get('testing.some-feature'))->toBeNull(); + expect(FeatureFlag::isOn('some-feature'))->toBeFalse() + ->and(FeatureFlag::isOff('some-feature'))->toBeTrue() + ->and(cache()->store('array')->get('testing.some-feature'))->toBeNull(); }); it('resolves isOn to false when the features state is "off"', function () { @@ -54,9 +54,9 @@ 'state' => FeatureState::off() ]); - expect(FeatureFlag::isOn('some-feature'))->toBeFalse(); - expect(FeatureFlag::isOff('some-feature'))->toBeTrue(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::off()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeFalse() + ->and(FeatureFlag::isOff('some-feature'))->toBeTrue() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::off()->value); }); it('resolves isOn to true when the features state is "on"', function () { @@ -65,9 +65,9 @@ 'state' => FeatureState::on() ]); - expect(FeatureFlag::isOn('some-feature'))->toBeTrue(); - expect(FeatureFlag::isOff('some-feature'))->toBeFalse(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::on()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeTrue() + ->and(FeatureFlag::isOff('some-feature'))->toBeFalse() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::on()->value); }); it('resolves isOn to true when feature state is "dynamic" and the closure returns true', function () { @@ -80,9 +80,9 @@ return true; }); - expect(FeatureFlag::isOn('some-feature'))->toBeTrue(); - expect(FeatureFlag::isOff('some-feature'))->toBeFalse(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeTrue() + ->and(FeatureFlag::isOff('some-feature'))->toBeFalse() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); }); it('resolves isOn to false when feature state is "dynamic" and the closure returns false', function () { @@ -95,9 +95,9 @@ return false; }); - expect(FeatureFlag::isOn('some-feature'))->toBeFalse(); - expect(FeatureFlag::isOff('some-feature'))->toBeTrue(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeFalse() + ->and(FeatureFlag::isOff('some-feature'))->toBeTrue() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); }); it('uses the default dynamic closure if no feature specific closure has been defined', function () { @@ -110,9 +110,9 @@ return true; }); - expect(FeatureFlag::isOn('some-feature'))->toBeTrue(); - expect(FeatureFlag::isOff('some-feature'))->toBeFalse(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeTrue() + ->and(FeatureFlag::isOff('some-feature'))->toBeFalse() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::dynamic()->value); }); it('resolves isOn to false when feature state is "dynamic" and no dynamic closure has been defined', function () { @@ -121,8 +121,8 @@ 'state' => FeatureState::dynamic(), ]); - expect(FeatureFlag::isOn('some-feature'))->toBeFalse(); - expect(FeatureFlag::isOff('some-feature'))->toBeTrue(); + expect(FeatureFlag::isOn('some-feature'))->toBeFalse() + ->and(FeatureFlag::isOff('some-feature'))->toBeTrue(); }); it('resolves the current state', function () { @@ -139,9 +139,9 @@ 'state' => FeatureState::on() ]); - expect(FeatureFlag::getState('some-off-feature'))->toBe(FeatureState::off()); - expect(FeatureFlag::getState('some-dynamic-feature'))->toBe(FeatureState::dynamic()); - expect(FeatureFlag::getState('some-on-feature'))->toBe(FeatureState::on()); + expect(FeatureFlag::getState('some-off-feature'))->toBe(FeatureState::off()) + ->and(FeatureFlag::getState('some-dynamic-feature'))->toBe(FeatureState::dynamic()) + ->and(FeatureFlag::getState('some-on-feature'))->toBe(FeatureState::on()); }); it('can update a features state', function () { @@ -157,9 +157,9 @@ FeatureFlag::updateFeatureState('some-feature', FeatureState::on()); Event::assertDispatched(\Codinglabs\FeatureFlags\Events\FeatureUpdatedEvent::class); - expect(FeatureFlag::isOn('some-feature'))->toBeTrue(); - expect(FeatureFlag::isOff('some-feature'))->toBeFalse(); - expect(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::on()->value); + expect(FeatureFlag::isOn('some-feature'))->toBeTrue() + ->and(FeatureFlag::isOff('some-feature'))->toBeFalse() + ->and(cache()->store('array')->get('testing.some-feature'))->toBe(FeatureState::on()->value); }); it('uses the default cache store when cache store has not been set', function () {