Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.00% covered (warning)
80.00%
24 / 30
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
BaseController
80.00% covered (warning)
80.00%
24 / 30
25.00% covered (danger)
25.00%
1 / 4
13.15
0.00% covered (danger)
0.00%
0 / 1
 __invoke
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
 getExceptionContext
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 readResponse
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createJsonResponse
76.92% covered (warning)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
7.60
1<?php
2
3declare(strict_types=1);
4
5namespace BO\Zmscitizenapi;
6
7use Psr\Http\Message\RequestInterface;
8use Psr\Http\Message\ResponseInterface;
9use BO\Zmscitizenapi\Utils\ErrorMessages;
10
11abstract class BaseController extends \BO\Slim\Controller
12{
13    public function __invoke(RequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
14    {
15        try {
16            $request = $this->initRequest($request);
17            $noCacheResponse = \BO\Slim\Render::withLastModified($response, time(), '0');
18            return $this->readResponse($request, $noCacheResponse, $args);
19        } catch (\RuntimeException $e) {
20        // Extract error details from the exception message
21            [$errorCode, $errorMessage] = explode(': ', $e->getMessage(), 2);
22            return $this->createJsonResponse($response, [
23                'errors' => [
24                    [
25                        'errorCode' => $errorCode,
26                        'errorMessage' => $errorMessage,
27                        'statusCode' => $e->getCode()
28                    ]
29                ]
30            ], $e->getCode() ?: 500);
31        }
32    }
33
34    protected function getExceptionContext(): string
35    {
36        $className = (new \ReflectionClass($this))->getShortName();
37        return str_replace('Controller', '', $className);
38    }
39
40    /**
41     * Hook method for handling responses in child controllers.
42     * Child classes should override this method to implement their specific response logic.
43     *
44     * @param RequestInterface $request The HTTP request
45     * @param ResponseInterface $response The HTTP response
46     * @param array $args Route parameters
47     * @return ResponseInterface The modified response
48     */
49    public function readResponse(RequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
50    {
51        return parent::__invoke($request, $response, $args);
52    }
53
54    protected function createJsonResponse(ResponseInterface $response, array $content, int $statusCode): ResponseInterface
55    {
56        if ($statusCode < 100 || $statusCode > 599) {
57            throw new \InvalidArgumentException('Invalid HTTP status code');
58        }
59
60        $response = $response->withStatus($statusCode)
61            ->withHeader('Content-Type', 'application/json; charset=utf-8');
62        if (isset($content['errors'])) {
63            foreach ($content['errors'] as &$error) {
64                if (isset($error['errorCode'])) {
65                    $error = ErrorMessages::get($error['errorCode']);
66                }
67            }
68        }
69
70        try {
71            $json = json_encode($content, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
72        } catch (\JsonException $e) {
73            throw new \RuntimeException('Failed to encode JSON response: ' . $e->getMessage(), 0, $e);
74        }
75
76        $response->getBody()->write($json);
77        return $response;
78    }
79}