Completed
Push — master ( a3cce1...d6fbcc )
by Marcel
09:39
created

ApiExceptionSubscriber::onKernelException()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 45
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 27.8133

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 45
ccs 4
cts 26
cp 0.1538
crap 27.8133
rs 8.8657
1
<?php
2
3
namespace App\EventSubscriber;
4
5
use App\Response\ErrorResponse;
6
use App\Response\Violation;
7
use App\Response\ViolationListResponse;
8
use App\Rest\ValidationFailedException;
9
use JMS\Serializer\SerializerInterface;
10
use Psr\Log\LoggerInterface;
11
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
12
use Symfony\Component\HttpFoundation\Response;
13
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
14
use Symfony\Component\HttpKernel\Exception\HttpException;
15
use Symfony\Component\HttpKernel\KernelEvents;
16
17
class ApiExceptionSubscriber implements EventSubscriberInterface {
18
19
    private const JsonContentType = 'application/json';
20
21
    private $serializer;
22
    private $logger;
23
24 13
    public function __construct(SerializerInterface $serializer, LoggerInterface $logger) {
25 13
        $this->serializer = $serializer;
26 13
        $this->logger = $logger;
27 13
    }
28
29 1
    public function onKernelException(ExceptionEvent $event) {
30 1
        $request = $event->getRequest();
31
32 1
        if(!in_array(static::JsonContentType, $request->getAcceptableContentTypes())) {
33 1
            return;
34
        }
35
36
        $throwable = $event->getThrowable();
37
        $code = Response::HTTP_INTERNAL_SERVER_ERROR;
38
39
        // Case 1: general HttpException (Authorization/Authentication) or BadRequest
40
        if($throwable instanceof HttpException) {
41
            $code = $throwable->getStatusCode();
42
            $message = new ErrorResponse($throwable->getMessage(), get_class($throwable));
43
        } else if($throwable instanceof ValidationFailedException) { // Case 2: validation failed
44
            $code = Response::HTTP_BAD_REQUEST;
45
46
            $violations = [ ];
47
            foreach($throwable->getConstraintViolations() as $violation) {
48
                $violations[] = new Violation($violation->getPropertyPath(), (string)$violation->getMessage());
49
            }
50
51
            $message = new ViolationListResponse($violations);
52
        } else { // Case 3: General error
53
            $message = new ErrorResponse(
54
                'An unknown error occured.',
55
                get_class($throwable)
56
            );
57
58
            $this->logger->error($throwable->getMessage(), [
59
                'e' => $throwable
60
            ]);
61
        }
62
63
        $validStatusCodes = array_keys(Response::$statusTexts);
64
        if(!in_array($code, $validStatusCodes)) {
65
            $code = Response::HTTP_INTERNAL_SERVER_ERROR;
66
        }
67
68
        $response = new Response(
69
            $this->serializer->serialize($message, 'json'),
70
            $code
71
        );
72
73
        $event->setResponse($response);
74
    }
75
76
    /**
77
     * @inheritDoc
78
     */
79
    public static function getSubscribedEvents() {
80
        return [
81
            KernelEvents::EXCEPTION => 'onKernelException'
82
        ];
83
    }
84
}