Skip to content
This repository has been archived by the owner on Mar 12, 2024. It is now read-only.

Add support for multiple features in the middleware #2

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -149,6 +149,14 @@ You can change the status code using the `middleware.code` configuration option.

If you would prefer to redirect instead of aborting, set `middleware.behaviour` to `MiddlewareBehaviour::Redirect` and `middleware.redirect` to your preferred redirect location.

#### Multiple features

If you wish, you may protect your routes behind multiple feature flags. You can do this by comma-separating the flags passed when defining the middleware on your route definition:

```php
Route::get('/feature', fn () => ...)->middleware('feature:verified,two-factor');
```

## Testing

```bash
Expand Down
16 changes: 9 additions & 7 deletions src/Middleware/HasFeature.php
Expand Up @@ -15,16 +15,18 @@ public function __construct(
) {
}

public function handle(Request $request, Closure $next, string $name)
public function handle(Request $request, Closure $next, string ...$features)
{
if (Features::enabled($name)) {
return $next($request);
}
foreach ($features as $feature) {
if (! Features::enabled($feature)) {
if ($this->features->getMiddlewareBehaviour() === MiddlewareBehaviour::Abort) {
abort($this->features->getMiddlewareAbortCode());
}

if ($this->features->getMiddlewareBehaviour() === MiddlewareBehaviour::Abort) {
abort($this->features->getMiddlewareAbortCode());
return redirect()->to($this->features->getMiddlewareRedirect());
}
}

return redirect()->to($this->features->getMiddlewareRedirect());
return $next($request);
}
}
57 changes: 57 additions & 0 deletions tests/MiddlewareTest.php
Expand Up @@ -10,6 +10,9 @@
beforeEach(function () {
Route::get('/features', function () {
})->middleware(HasFeature::class . ':foo');

Route::get('/multi-features', function () {
})->middleware(HasFeature::class . ':foo,bar');
});

test('the middleware correctly aborts', function () {
Expand Down Expand Up @@ -54,3 +57,57 @@
get('/features')
->assertRedirect('/bar');
});

test('the middleware allows multiple features', function () {
Features::enable('foo');
Features::enable('bar');

get('/multi-features')
->assertOk();
});

test('the middleware correctly aborts for multiple features if one is not enabled', function () {
Features::enable('foo');
Features::enable('bar');

get('/multi-features')
->assertOk();

Features::disable('bar');

get('/multi-features')
->assertForbidden();
});

test('the middleware correctly aborts with custom code for multiple features if one is not enabled', function () {
config(['feature-flags.middleware.code' => 404]);

Features::enable('foo');
Features::enable('bar');

get('/multi-features')
->assertOk();

Features::disable('bar');

get('/multi-features')
->assertNotFound();
});

test('the middleware correctly redirects for multiple features if one is not enabled', function () {
config([
'feature-flags.middleware.behaviour' => MiddlewareBehaviour::Redirect,
'feature-flags.middleware.redirect' => '/bar',
]);

Features::enable('foo');
Features::enable('bar');

get('/multi-features')
->assertOk();

Features::disable('foo');

get('/multi-features')
->assertRedirect('/bar');
});