|
|
@ -382,64 +382,82 @@ class Engine
|
|
|
|
* Processes each routes middleware.
|
|
|
|
* Processes each routes middleware.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param Route $route The route to process the middleware for.
|
|
|
|
* @param Route $route The route to process the middleware for.
|
|
|
|
* @param string $event_name If this is the before or after method.
|
|
|
|
* @param string $eventName If this is the before or after method.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
protected function processMiddleware(Route $route, string $event_name): bool
|
|
|
|
protected function processMiddleware(Route $route, string $eventName): bool
|
|
|
|
{
|
|
|
|
{
|
|
|
|
$at_least_one_middleware_failed = false;
|
|
|
|
$atLeastOneMiddlewareFailed = false;
|
|
|
|
|
|
|
|
|
|
|
|
$middlewares = $event_name === Dispatcher::FILTER_BEFORE ? $route->middleware : array_reverse($route->middleware);
|
|
|
|
// Process things normally for before, and then in reverse order for after.
|
|
|
|
|
|
|
|
$middlewares = $eventName === Dispatcher::FILTER_BEFORE
|
|
|
|
|
|
|
|
? $route->middleware
|
|
|
|
|
|
|
|
: array_reverse($route->middleware);
|
|
|
|
$params = $route->params;
|
|
|
|
$params = $route->params;
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($middlewares as $middleware) {
|
|
|
|
foreach ($middlewares as $middleware) {
|
|
|
|
$middleware_object = false;
|
|
|
|
|
|
|
|
|
|
|
|
// Assume that nothing is going to be executed for the middleware.
|
|
|
|
if ($event_name === Dispatcher::FILTER_BEFORE) {
|
|
|
|
$middlewareObject = false;
|
|
|
|
// can be a callable or a class
|
|
|
|
|
|
|
|
$middleware_object = (is_callable($middleware) === true
|
|
|
|
// Closure functions can only run on the before event
|
|
|
|
? $middleware
|
|
|
|
if ($eventName === Dispatcher::FILTER_BEFORE && is_object($middleware) === true && ($middleware instanceof Closure)) {
|
|
|
|
: (method_exists($middleware, Dispatcher::FILTER_BEFORE) === true
|
|
|
|
$middlewareObject = $middleware;
|
|
|
|
? [$middleware, Dispatcher::FILTER_BEFORE]
|
|
|
|
|
|
|
|
: false
|
|
|
|
// If the object has already been created, we can just use it if the event name exists.
|
|
|
|
)
|
|
|
|
} elseif (is_object($middleware) === true) {
|
|
|
|
);
|
|
|
|
$middlewareObject = method_exists($middleware, $eventName) === true ? [ $middleware, $eventName ] : false;
|
|
|
|
} elseif ($event_name === Dispatcher::FILTER_AFTER) {
|
|
|
|
|
|
|
|
// must be an object. No functions allowed here
|
|
|
|
// If the middleware is a string, we need to create the object and then call the event.
|
|
|
|
if (
|
|
|
|
} elseif (is_string($middleware) === true && method_exists($middleware, $eventName) === true) {
|
|
|
|
is_object($middleware) === true
|
|
|
|
$resolvedClass = null;
|
|
|
|
&& !($middleware instanceof Closure)
|
|
|
|
|
|
|
|
&& method_exists($middleware, Dispatcher::FILTER_AFTER) === true
|
|
|
|
// if there's a container assigned, we should use it to create the object
|
|
|
|
) {
|
|
|
|
if ($this->dispatcher->mustUseContainer($middleware) === true) {
|
|
|
|
$middleware_object = [$middleware, Dispatcher::FILTER_AFTER];
|
|
|
|
$resolvedClass = $this->dispatcher->resolveContainerClass($middleware, $params);
|
|
|
|
|
|
|
|
// otherwise just assume it's a plain jane class, so inject the engine
|
|
|
|
|
|
|
|
// just like in Dispatcher::invokeCallable()
|
|
|
|
|
|
|
|
} elseif (class_exists($middleware) === true) {
|
|
|
|
|
|
|
|
$resolvedClass = new $middleware($this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If something was resolved, create an array callable that will be passed in later.
|
|
|
|
|
|
|
|
if ($resolvedClass !== null) {
|
|
|
|
|
|
|
|
$middlewareObject = [ $resolvedClass, $eventName ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($middleware_object === false) {
|
|
|
|
// If nothing was resolved, go to the next thing
|
|
|
|
|
|
|
|
if ($middlewareObject === false) {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$use_v3_output_buffering =
|
|
|
|
// This is the way that v3 handles output buffering (which captures output correctly)
|
|
|
|
|
|
|
|
$useV3OutputBuffering =
|
|
|
|
$this->response()->v2_output_buffering === false &&
|
|
|
|
$this->response()->v2_output_buffering === false &&
|
|
|
|
$route->is_streamed === false;
|
|
|
|
$route->is_streamed === false;
|
|
|
|
|
|
|
|
|
|
|
|
if ($use_v3_output_buffering === true) {
|
|
|
|
if ($useV3OutputBuffering === true) {
|
|
|
|
ob_start();
|
|
|
|
ob_start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// It's assumed if you don't declare before, that it will be assumed as the before method
|
|
|
|
// Here is the array callable $middlewareObject that we created earlier.
|
|
|
|
$middleware_result = $middleware_object($params);
|
|
|
|
// It looks bizarre but it's really calling [ $class, $method ]($params)
|
|
|
|
|
|
|
|
// Which loosely translates to $class->$method($params)
|
|
|
|
|
|
|
|
$middlewareResult = $middlewareObject($params);
|
|
|
|
|
|
|
|
|
|
|
|
if ($use_v3_output_buffering === true) {
|
|
|
|
if ($useV3OutputBuffering === true) {
|
|
|
|
$this->response()->write(ob_get_clean());
|
|
|
|
$this->response()->write(ob_get_clean());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($middleware_result === false) {
|
|
|
|
// If you return false in your middleware, it will halt the request
|
|
|
|
$at_least_one_middleware_failed = true;
|
|
|
|
// and throw a 403 forbidden error by default.
|
|
|
|
|
|
|
|
if ($middlewareResult === false) {
|
|
|
|
|
|
|
|
$atLeastOneMiddlewareFailed = true;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $at_least_one_middleware_failed;
|
|
|
|
return $atLeastOneMiddlewareFailed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////
|
|
|
|
////////////////////////
|
|
|
@ -475,7 +493,7 @@ class Engine
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Route the request
|
|
|
|
// Route the request
|
|
|
|
$failed_middleware_check = false;
|
|
|
|
$failedMiddlewareCheck = false;
|
|
|
|
|
|
|
|
|
|
|
|
while ($route = $router->route($request)) {
|
|
|
|
while ($route = $router->route($request)) {
|
|
|
|
$params = array_values($route->params);
|
|
|
|
$params = array_values($route->params);
|
|
|
@ -506,18 +524,18 @@ class Engine
|
|
|
|
|
|
|
|
|
|
|
|
// Run any before middlewares
|
|
|
|
// Run any before middlewares
|
|
|
|
if (count($route->middleware) > 0) {
|
|
|
|
if (count($route->middleware) > 0) {
|
|
|
|
$at_least_one_middleware_failed = $this->processMiddleware($route, 'before');
|
|
|
|
$atLeastOneMiddlewareFailed = $this->processMiddleware($route, 'before');
|
|
|
|
if ($at_least_one_middleware_failed === true) {
|
|
|
|
if ($atLeastOneMiddlewareFailed === true) {
|
|
|
|
$failed_middleware_check = true;
|
|
|
|
$failedMiddlewareCheck = true;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$use_v3_output_buffering =
|
|
|
|
$useV3OutputBuffering =
|
|
|
|
$this->response()->v2_output_buffering === false &&
|
|
|
|
$this->response()->v2_output_buffering === false &&
|
|
|
|
$route->is_streamed === false;
|
|
|
|
$route->is_streamed === false;
|
|
|
|
|
|
|
|
|
|
|
|
if ($use_v3_output_buffering === true) {
|
|
|
|
if ($useV3OutputBuffering === true) {
|
|
|
|
ob_start();
|
|
|
|
ob_start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -527,17 +545,17 @@ class Engine
|
|
|
|
$params
|
|
|
|
$params
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if ($use_v3_output_buffering === true) {
|
|
|
|
if ($useV3OutputBuffering === true) {
|
|
|
|
$response->write(ob_get_clean());
|
|
|
|
$response->write(ob_get_clean());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Run any before middlewares
|
|
|
|
// Run any before middlewares
|
|
|
|
if (count($route->middleware) > 0) {
|
|
|
|
if (count($route->middleware) > 0) {
|
|
|
|
// process the middleware in reverse order now
|
|
|
|
// process the middleware in reverse order now
|
|
|
|
$at_least_one_middleware_failed = $this->processMiddleware($route, 'after');
|
|
|
|
$atLeastOneMiddlewareFailed = $this->processMiddleware($route, 'after');
|
|
|
|
|
|
|
|
|
|
|
|
if ($at_least_one_middleware_failed === true) {
|
|
|
|
if ($atLeastOneMiddlewareFailed === true) {
|
|
|
|
$failed_middleware_check = true;
|
|
|
|
$failedMiddlewareCheck = true;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -558,7 +576,7 @@ class Engine
|
|
|
|
$response->clearBody();
|
|
|
|
$response->clearBody();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($failed_middleware_check === true) {
|
|
|
|
if ($failedMiddlewareCheck === true) {
|
|
|
|
$this->halt(403, 'Forbidden', empty(getenv('PHPUNIT_TEST')));
|
|
|
|
$this->halt(403, 'Forbidden', empty(getenv('PHPUNIT_TEST')));
|
|
|
|
} elseif ($dispatched === false) {
|
|
|
|
} elseif ($dispatched === false) {
|
|
|
|
$this->notFound();
|
|
|
|
$this->notFound();
|
|
|
|