Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ErrorHandler
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 5
110
0.00% covered (danger)
0.00%
0 / 1
 __invoke
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getStatusCode
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 formatErrorPayload
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getErrorMessage
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 logError
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace BO\Zmscitizenapi\Utils;
6
7use BO\Zmscitizenapi\Utils\ClientIpHelper;
8use BO\Zmscitizenapi\Services\Core\LoggerService;
9use Psr\Http\Message\ResponseInterface;
10use Psr\Http\Message\ServerRequestInterface;
11use Slim\Exception\HttpException;
12use Slim\Interfaces\ErrorHandlerInterface;
13
14class ErrorHandler implements ErrorHandlerInterface
15{
16    #[\Override]
17    public function __invoke(
18        ServerRequestInterface $request,
19        \Throwable $exception,
20        bool $displayErrorDetails,
21        bool $logErrors,
22        bool $logErrorDetails
23    ): ResponseInterface {
24        $statusCode = $this->getStatusCode($exception);
25
26        if ($logErrors) {
27            $this->logError($exception, $request, $displayErrorDetails, $logErrorDetails);
28        }
29
30        $response = new \Slim\Psr7\Response();
31        $payload = $this->formatErrorPayload($exception, $displayErrorDetails);
32
33        $response->getBody()->write(json_encode($payload));
34
35        return $response
36            ->withHeader('Content-Type', 'application/json')
37            ->withStatus($statusCode);
38    }
39
40    private function getStatusCode(\Throwable $exception): int
41    {
42        if ($exception instanceof HttpException) {
43            return $exception->getCode();
44        }
45
46        return 500;
47    }
48
49    private function formatErrorPayload(\Throwable $exception, bool $displayErrorDetails): array
50    {
51        $error = [
52            'message' => $this->getErrorMessage($exception, $displayErrorDetails),
53            'code' => $exception->getCode()
54        ];
55
56        if ($displayErrorDetails) {
57            $error['type'] = get_class($exception);
58            $error['file'] = $exception->getFile();
59            $error['line'] = $exception->getLine();
60            $error['trace'] = $exception->getTrace();
61        }
62
63        return ['error' => $error];
64    }
65
66    private function getErrorMessage(\Throwable $exception, bool $displayErrorDetails): string
67    {
68        if ($displayErrorDetails) {
69            return $exception->getMessage();
70        }
71
72        if ($exception instanceof HttpException) {
73            return $exception->getMessage();
74        }
75
76        return 'An internal error has occurred.';
77    }
78
79    private function logError(
80        \Throwable $exception,
81        ServerRequestInterface $request,
82        bool $displayErrorDetails,
83        bool $logErrorDetails
84    ): void {
85        LoggerService::logError($exception, $request, null, [
86            'displayErrorDetails' => $displayErrorDetails,
87            'logErrorDetails' => $logErrorDetails,
88            'uri' => (string)$request->getUri(),
89            'method' => $request->getMethod(),
90            'ip' => ClientIpHelper::getClientIp()
91        ]);
92    }
93}