Skip to content

Commit

Permalink
feat: allow middleware registration per action on resource and relations
Browse files Browse the repository at this point in the history
Closes #265
  • Loading branch information
lindyhopchris committed Feb 14, 2024
1 parent 79ddd03 commit 3337678
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 21 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. This projec

## Unreleased

### Added

- [#265](https://github.com/laravel-json-api/laravel/issues/265) Allow registration of middleware per action on both
resource routes and relationship routes.

## [3.2.0] - 2023-11-08

### Added
Expand Down
25 changes: 22 additions & 3 deletions src/Routing/PendingRelationshipRegistration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
namespace LaravelJsonApi\Laravel\Routing;

use Illuminate\Routing\RouteCollection;
use Illuminate\Support\Arr;

class PendingRelationshipRegistration
{
Expand Down Expand Up @@ -155,12 +156,30 @@ public function name(string $method, string $name): self
/**
* Add middleware to the resource routes.
*
* @param string ...$middleware
* @param mixed ...$middleware
* @return $this
*/
public function middleware(string ...$middleware): self
public function middleware(...$middleware): self
{
$this->options['middleware'] = $middleware;
if (count($middleware) === 1) {
$middleware = Arr::wrap($middleware[0]);
}

if (array_is_list($middleware)) {
$this->options['middleware'] = $middleware;
return $this;
}

$this->options['middleware'] = Arr::wrap($middleware['*'] ?? null);

foreach ($this->map as $alias => $action) {
if (isset($middleware[$alias])) {
$middleware[$action] = $middleware[$alias];
unset($middleware[$alias]);
}
}

$this->options['action_middleware'] = $middleware;

return $this;
}
Expand Down
19 changes: 15 additions & 4 deletions src/Routing/PendingResourceRegistration.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

use Closure;
use Illuminate\Routing\RouteCollection;
use Illuminate\Support\Arr;
use InvalidArgumentException;
use function is_string;

Expand Down Expand Up @@ -180,12 +181,22 @@ public function parameter(string $parameter): self
/**
* Add middleware to the resource routes.
*
* @param string ...$middleware
* @param mixed ...$middleware
* @return $this
*/
public function middleware(string ...$middleware): self
public function middleware(...$middleware): self
{
$this->options['middleware'] = $middleware;
if (count($middleware) === 1) {
$middleware = Arr::wrap($middleware[0]);
}

if (array_is_list($middleware)) {
$this->options['middleware'] = $middleware;
return $this;
}

$this->options['middleware'] = Arr::wrap($middleware['*'] ?? null);
$this->options['action_middleware'] = $middleware;

return $this;
}
Expand All @@ -196,7 +207,7 @@ public function middleware(string ...$middleware): self
* @param string ...$middleware
* @return $this
*/
public function withoutMiddleware(string ...$middleware)
public function withoutMiddleware(string ...$middleware): self
{
$this->options['excluded_middleware'] = array_merge(
(array) ($this->options['excluded_middleware'] ?? []),
Expand Down
22 changes: 20 additions & 2 deletions src/Routing/RelationshipRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Illuminate\Contracts\Routing\Registrar as RegistrarContract;
use Illuminate\Routing\Route as IlluminateRoute;
use Illuminate\Routing\RouteCollection;
use Illuminate\Support\Arr;
use LaravelJsonApi\Contracts\Schema\Schema;
use LaravelJsonApi\Core\Support\Str;

Expand Down Expand Up @@ -272,9 +273,10 @@ private function getRelationshipAction(
$name = $this->getRelationRouteName($method, $defaultName, $options);

$action = ['as' => $name, 'uses' => $this->controller.'@'.$method];
$middleware = $this->getMiddleware($method, $options);

if (isset($options['middleware'])) {
$action['middleware'] = $options['middleware'];
if (!empty($middleware)) {
$action['middleware'] = $middleware;
}

if (isset($options['excluded_middleware'])) {
Expand All @@ -284,6 +286,22 @@ private function getRelationshipAction(
return $action;
}

/**
* @param string $action
* @param array $options
* @return array
*/
private function getMiddleware(string $action, array $options): array
{
$all = $options['middleware'] ?? [];
$actions = $options['action_middleware'] ?? [];

return [
...$all,
...Arr::wrap($actions[$action] ?? null),
];
}

/**
* @param string $fieldName
* @return string
Expand Down
24 changes: 21 additions & 3 deletions src/Routing/ResourceRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Illuminate\Contracts\Routing\Registrar as RegistrarContract;
use Illuminate\Routing\Route as IlluminateRoute;
use Illuminate\Routing\RouteCollection;
use Illuminate\Support\Arr;
use LaravelJsonApi\Contracts\Server\Server;
use LaravelJsonApi\Core\Support\Str;

Expand Down Expand Up @@ -337,13 +338,14 @@ private function getResourceAction(
string $method,
?string $parameter,
array $options
) {
): array {
$name = $this->getResourceRouteName($resourceType, $method, $options);

$action = ['as' => $name, 'uses' => $controller.'@'.$method];
$middleware = $this->getMiddleware($method, $options);

if (isset($options['middleware'])) {
$action['middleware'] = $options['middleware'];
if (!empty($middleware)) {
$action['middleware'] = $middleware;
}

if (isset($options['excluded_middleware'])) {
Expand All @@ -355,6 +357,22 @@ private function getResourceAction(
return $action;
}

/**
* @param string $action
* @param array $options
* @return array
*/
private function getMiddleware(string $action, array $options): array
{
$all = $options['middleware'] ?? [];
$actions = $options['action_middleware'] ?? [];

return [
...$all,
...Arr::wrap($actions[$action] ?? null),
];
}

/**
* Get the action array for the relationships group.
*
Expand Down
86 changes: 84 additions & 2 deletions tests/lib/Integration/Routing/HasManyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,95 @@ public function testMiddleware(string $method, string $uri): void
->middleware('foo')
->resources(function ($server) {
$server->resource('posts')->middleware('bar')->relationships(function ($relations) {
$relations->hasMany('tags')->middleware('baz');
$relations->hasMany('tags')->middleware('baz1', 'baz2');
});
});
});

$route = $this->assertMatch($method, $uri);
$this->assertSame(['api', 'jsonapi:v1', 'foo', 'bar', 'baz'], $route->action['middleware']);
$this->assertSame(['api', 'jsonapi:v1', 'foo', 'bar', 'baz1', 'baz2'], $route->action['middleware']);
}

/**
* @param string $method
* @param string $uri
* @dataProvider genericProvider
*/
public function testMiddlewareAsArrayList(string $method, string $uri): void
{
$server = $this->createServer('v1');
$schema = $this->createSchema($server, 'posts', '\d+');
$this->createRelation($schema, 'tags');

$this->defaultApiRoutesWithNamespace(function () {
JsonApiRoute::server('v1')
->prefix('v1')
->namespace('Api\\V1')
->middleware('foo')
->resources(function ($server) {
$server->resource('posts')->middleware('bar')->relationships(function ($relations) {
$relations->hasMany('tags')->middleware(['baz1', 'baz2']);
});
});
});

$route = $this->assertMatch($method, $uri);
$this->assertSame(['api', 'jsonapi:v1', 'foo', 'bar', 'baz1', 'baz2'], $route->action['middleware']);
}

/**
* @param string $method
* @param string $uri
* @param string $action
* @dataProvider genericProvider
*/
public function testActionMiddleware(string $method, string $uri, string $action): void
{
$actions = [
'*' => ['baz1', 'baz2'],
'showRelated' => 'showRelated1',
'showRelationship' => ['showRelationship1', 'showRelationship2'],
'updateRelationship' => 'updateRelationship1',
'attachRelationship' => ['attachRelationship1', 'attachRelationship2'],
'detachRelationship' => 'detachRelationship1',
];

$expected = [
'api',
'jsonapi:v1',
'foo',
'bar',
...$actions['*'],
...Arr::wrap($actions[$action]),
];

$server = $this->createServer('v1');
$schema = $this->createSchema($server, 'posts', '\d+');
$this->createRelation($schema, 'tags');

$this->defaultApiRoutesWithNamespace(function () use ($actions) {
JsonApiRoute::server('v1')
->prefix('v1')
->namespace('Api\\V1')
->middleware('foo')
->resources(function ($server) use ($actions) {
$server->resource('posts')->middleware('bar')->relationships(
function ($relations) use ($actions) {
$relations->hasMany('tags')->middleware([
'*' => $actions['*'],
'related' => $actions['showRelated'],
'show' => $actions['showRelationship'],
'update' => $actions['updateRelationship'],
'attach' => $actions['attachRelationship'],
'detach' => $actions['detachRelationship'],
]);
},
);
});
});

$route = $this->assertMatch($method, $uri);
$this->assertSame($expected, $route->action['middleware']);
}

/**
Expand Down
Loading

0 comments on commit 3337678

Please sign in to comment.