fatcode/http-server

View on GitHub
src/Server/ErrorMiddleware.php

Summary

Maintainability
A
55 mins
Test Coverage
<?php declare(strict_types=1);

namespace FatCode\HttpServer\Server;

use ErrorException;
use FatCode\HttpServer\Exception\HttpException;
use FatCode\HttpServer\HttpStatusCode;
use FatCode\HttpServer\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Throwable;

/**
 * Middleware for error handling. If an exception is thrown and not catch during the request cycle,
 * it will appear here. Middleware will catch it and return response with status code (500) and exception message
 * as a body.
 */
final class ErrorMiddleware implements MiddlewareInterface
{
    private $errorHandler;

    public function __construct(callable $errorHandler = null)
    {
        $this->errorHandler = $errorHandler;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $next) : ResponseInterface
    {
        $this->setErrorHandler();

        try {
            $response = $next->handle($request);
        } catch (Throwable $exception) {
            if ($this->errorHandler !== null) {
                $result = ($this->errorHandler)($exception);
                if ($result instanceof Throwable) {
                    $exception = $result;
                }
            }

            if ($exception instanceof HttpException) {
                $response = $exception->toResponse();
            } else {
                $response = new Response('Internal Server Error', HttpStatusCode::INTERNAL_SERVER_ERROR());
            }
        }
        $this->restoreErrorHandler();

        return $response;
    }


    private function setErrorHandler() : void
    {
        set_error_handler(function (int $number, string $message, string $file, int $line) {

            if (!(error_reporting() & $number)) {
                return;
            }

            throw new ErrorException($message, 0, $number, $file, $line);
        });
    }

    private function restoreErrorHandler() : void
    {
        restore_error_handler();
    }
}