Skip to content

Commit

Permalink
[9.x] Controller middleware without resolving controller (#44516)
Browse files Browse the repository at this point in the history
* controller middleware without resolving controller

* update logic

* add tests

* Apply fixes from StyleCI

Co-authored-by: StyleCI Bot <bot@styleci.io>
  • Loading branch information
taylorotwell and StyleCIBot authored Oct 10, 2022
1 parent 5fb31a5 commit 6cdf03e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/Illuminate/Routing/ControllerDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function getMiddleware($controller, $method)
* @param array $options
* @return bool
*/
protected static function methodExcludedByOptions($method, array $options)
public static function methodExcludedByOptions($method, array $options)
{
return (isset($options['only']) && ! in_array($method, (array) $options['only'])) ||
(! empty($options['except']) && in_array($method, (array) $options['except']));
Expand Down
13 changes: 13 additions & 0 deletions src/Illuminate/Routing/Controllers/HasMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Illuminate\Routing\Controllers;

interface HasMiddleware
{
/**
* Get the middleware that should be assigned to the controller.
*
* @return \Illuminate\Routing\Controllers\Middleware|array
*/
public static function middleware();
}
67 changes: 67 additions & 0 deletions src/Illuminate/Routing/Controllers/Middleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Illuminate\Routing\Controllers;

use Closure;
use Illuminate\Support\Arr;

class Middleware
{
/**
* The middleware that should be assigned.
*
* @var \Closure|string|array
*/
public $middleware;

/**
* The controller methods the middleware should only apply to.
*
* @var array|null
*/
public $only;

/**
* The controller methods the middleware should not apply to.
*
* @var array|null
*/
public $except;

/**
* Create a new controller middleware definition.
*
* @param \Closure|string|array $middleware
* @return void
*/
public function __construct(Closure|string|array $middleware)
{
$this->middleware = $middleware;
}

/**
* Specify the only controller methods the middleware should apply to.
*
* @param array|string $only
* @return $this
*/
public function only(array|string $only)
{
$this->only = Arr::wrap($only);

return $this;
}

/**
* Specify the controller methods the middleware should not apply to.
*
* @param array|string $only
* @return $this
*/
public function except(array|string $except)
{
$this->except = Arr::wrap($except);

return $this;
}
}
38 changes: 35 additions & 3 deletions src/Illuminate/Routing/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Http\Request;
use Illuminate\Routing\Contracts\CallableDispatcher;
use Illuminate\Routing\Contracts\ControllerDispatcher as ControllerDispatcherContract;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Matching\HostValidator;
use Illuminate\Routing\Matching\MethodValidator;
use Illuminate\Routing\Matching\SchemeValidator;
Expand Down Expand Up @@ -1081,9 +1082,40 @@ public function controllerMiddleware()
return [];
}

return $this->controllerDispatcher()->getMiddleware(
$this->getController(), $this->getControllerMethod()
);
[$controllerClass, $controllerMethod] = [
$this->getControllerClass(),
$this->getControllerMethod(),
];

if (is_a($controllerClass, HasMiddleware::class, true)) {
return $this->staticallyProvidedControllerMiddleware(
$controllerClass, $controllerMethod
);
}

if (is_a($controllerClass, Controller::class, true)) {
return $this->controllerDispatcher()->getMiddleware(
$this->getController(), $controllerMethod
);
}

return [];
}

/**
* Get the statically provided controller middleware for the given class and method.
*
* @param string $class
* @param string $method
* @return array
*/
protected function staticallyProvidedControllerMiddleware(string $class, string $method)
{
return collect($class::middleware())->reject(function ($middleware) use ($method) {
return $this->controllerDispatcher()::methodExcludedByOptions(
$method, ['only' => $middleware->only, 'except' => $middleware->except]
);
})->map->middleware->values()->all();
}

/**
Expand Down
41 changes: 41 additions & 0 deletions tests/Integration/Routing/HasMiddlewareTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Illuminate\Tests\Integration\Routing;

use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
use Illuminate\Support\Facades\Route;
use Orchestra\Testbench\TestCase;

class HasMiddlewareTest extends TestCase
{
public function test_has_middleware_is_respected()
{
$route = Route::get('/', [HasMiddlewareTestController::class, 'index']);
$this->assertEquals($route->controllerMiddleware(), ['all', 'only-index']);

$route = Route::get('/', [HasMiddlewareTestController::class, 'show']);
$this->assertEquals($route->controllerMiddleware(), ['all', 'except-index']);
}
}

class HasMiddlewareTestController implements HasMiddleware
{
public static function middleware()
{
return [
new Middleware('all'),
(new Middleware('only-index'))->only('index'),
(new Middleware('except-index'))->except('index'),
];
}

public function index()
{
//
}

public function show()
{
}
}

0 comments on commit 6cdf03e

Please sign in to comment.