8000 Feature: allow middleware registration per action on resource and relations by lindyhopchris · Pull Request #268 · laravel-json-api/laravel · GitHub
[go: up one dir, main page]

Skip to content

Feature: allow middleware registration per action on resource and relations #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 14, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

8000 ### 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 getResou A3E2 rceAction(
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
FD64
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