213 lines
6.4 KiB
PHP
213 lines
6.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Slim Framework (https://slimframework.com)
|
|
*
|
|
* @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Slim\Middleware;
|
|
|
|
use Psr\Http\Message\ResponseFactoryInterface;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Http\Server\MiddlewareInterface;
|
|
use Psr\Http\Server\RequestHandlerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Slim\Exception\HttpException;
|
|
use Slim\Handlers\ErrorHandler;
|
|
use Slim\Interfaces\CallableResolverInterface;
|
|
use Slim\Interfaces\ErrorHandlerInterface;
|
|
use Throwable;
|
|
|
|
use function get_class;
|
|
use function is_subclass_of;
|
|
|
|
class ErrorMiddleware implements MiddlewareInterface
|
|
{
|
|
protected CallableResolverInterface $callableResolver;
|
|
|
|
protected ResponseFactoryInterface $responseFactory;
|
|
|
|
protected bool $displayErrorDetails;
|
|
|
|
protected bool $logErrors;
|
|
|
|
protected bool $logErrorDetails;
|
|
|
|
protected ?LoggerInterface $logger = null;
|
|
|
|
/**
|
|
* @var ErrorHandlerInterface[]|callable[]|string[]
|
|
*/
|
|
protected array $handlers = [];
|
|
|
|
/**
|
|
* @var ErrorHandlerInterface[]|callable[]|string[]
|
|
*/
|
|
protected array $subClassHandlers = [];
|
|
|
|
/**
|
|
* @var ErrorHandlerInterface|callable|string|null
|
|
*/
|
|
protected $defaultErrorHandler;
|
|
|
|
public function __construct(
|
|
CallableResolverInterface $callableResolver,
|
|
ResponseFactoryInterface $responseFactory,
|
|
bool $displayErrorDetails,
|
|
bool $logErrors,
|
|
bool $logErrorDetails,
|
|
?LoggerInterface $logger = null
|
|
) {
|
|
$this->callableResolver = $callableResolver;
|
|
$this->responseFactory = $responseFactory;
|
|
$this->displayErrorDetails = $displayErrorDetails;
|
|
$this->logErrors = $logErrors;
|
|
$this->logErrorDetails = $logErrorDetails;
|
|
$this->logger = $logger;
|
|
}
|
|
|
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
|
{
|
|
try {
|
|
return $handler->handle($request);
|
|
} catch (Throwable $e) {
|
|
return $this->handleException($request, $e);
|
|
}
|
|
}
|
|
|
|
public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface
|
|
{
|
|
if ($exception instanceof HttpException) {
|
|
$request = $exception->getRequest();
|
|
}
|
|
|
|
$exceptionType = get_class($exception);
|
|
$handler = $this->getErrorHandler($exceptionType);
|
|
|
|
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
|
|
}
|
|
|
|
/**
|
|
* Get callable to handle scenarios where an error
|
|
* occurs when processing the current request.
|
|
*
|
|
* @param string $type Exception/Throwable name. ie: RuntimeException::class
|
|
* @return callable|ErrorHandler
|
|
*/
|
|
public function getErrorHandler(string $type)
|
|
{
|
|
if (isset($this->handlers[$type])) {
|
|
return $this->callableResolver->resolve($this->handlers[$type]);
|
|
}
|
|
|
|
if (isset($this->subClassHandlers[$type])) {
|
|
return $this->callableResolver->resolve($this->subClassHandlers[$type]);
|
|
}
|
|
|
|
foreach ($this->subClassHandlers as $class => $handler) {
|
|
if (is_subclass_of($type, $class)) {
|
|
return $this->callableResolver->resolve($handler);
|
|
}
|
|
}
|
|
|
|
return $this->getDefaultErrorHandler();
|
|
}
|
|
|
|
/**
|
|
* Get default error handler
|
|
*
|
|
* @return ErrorHandler|callable
|
|
*/
|
|
public function getDefaultErrorHandler()
|
|
{
|
|
if ($this->defaultErrorHandler === null) {
|
|
$this->defaultErrorHandler = new ErrorHandler(
|
|
$this->callableResolver,
|
|
$this->responseFactory,
|
|
$this->logger
|
|
);
|
|
}
|
|
|
|
return $this->callableResolver->resolve($this->defaultErrorHandler);
|
|
}
|
|
|
|
/**
|
|
* Set callable as the default Slim application error handler.
|
|
*
|
|
* The callable signature MUST match the ErrorHandlerInterface
|
|
*
|
|
* @see \Slim\Interfaces\ErrorHandlerInterface
|
|
*
|
|
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
|
|
* 2. Instance of \Throwable
|
|
* 3. Boolean $displayErrorDetails
|
|
* 4. Boolean $logErrors
|
|
* 5. Boolean $logErrorDetails
|
|
*
|
|
* The callable MUST return an instance of
|
|
* \Psr\Http\Message\ResponseInterface.
|
|
*
|
|
* @param string|callable|ErrorHandler $handler
|
|
*/
|
|
public function setDefaultErrorHandler($handler): self
|
|
{
|
|
$this->defaultErrorHandler = $handler;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set callable to handle scenarios where an error
|
|
* occurs when processing the current request.
|
|
*
|
|
* The callable signature MUST match the ErrorHandlerInterface
|
|
*
|
|
* Pass true to $handleSubclasses to make the handler handle all subclasses of
|
|
* the type as well. Pass an array of classes to make the same function handle multiple exceptions.
|
|
*
|
|
* @see \Slim\Interfaces\ErrorHandlerInterface
|
|
*
|
|
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
|
|
* 2. Instance of \Throwable
|
|
* 3. Boolean $displayErrorDetails
|
|
* 4. Boolean $logErrors
|
|
* 5. Boolean $logErrorDetails
|
|
*
|
|
* The callable MUST return an instance of
|
|
* \Psr\Http\Message\ResponseInterface.
|
|
*
|
|
* @param string|string[] $typeOrTypes Exception/Throwable name.
|
|
* ie: RuntimeException::class or an array of classes
|
|
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
|
|
* @param string|callable|ErrorHandlerInterface $handler
|
|
*/
|
|
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
|
|
{
|
|
if (is_array($typeOrTypes)) {
|
|
foreach ($typeOrTypes as $type) {
|
|
$this->addErrorHandler($type, $handler, $handleSubclasses);
|
|
}
|
|
} else {
|
|
$this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
|
|
* @param string|callable|ErrorHandlerInterface $handler
|
|
*/
|
|
private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void
|
|
{
|
|
if ($handleSubclasses) {
|
|
$this->subClassHandlers[$type] = $handler;
|
|
} else {
|
|
$this->handlers[$type] = $handler;
|
|
}
|
|
}
|
|
}
|