Completed
Push — develop ( dc031d...86c271 )
by
unknown
14s
created

JsonExceptionListener::setLogger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: taachja1
5
 * Date: 13/04/16
6
 * Time: 10:16
7
 */
8
9
namespace Graviton\CoreBundle\Listener;
10
11
use Monolog\Logger;
12
use Symfony\Component\Debug\Exception\ContextErrorException;
13
use Symfony\Component\HttpFoundation\JsonResponse;
14
use Graviton\JsonSchemaBundle\Exception\ValidationException;
15
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
16
use Xiag\Rql\Parser\Exception\SyntaxErrorException;
17
use Graviton\ExceptionBundle\Exception\SerializationException;
18
19
/**
20
 * Class JsonExceptionListener
21
 * @package Graviton\CoreBundle\Listener
22
 */
23
class JsonExceptionListener
24
{
25
26
    /**
27
     * @var Logger
28
     */
29
    private $logger;
30
31
    /**
32
     * set Logger
33
     *
34
     * @param Logger $logger logger
35
     *
36
     * @return void
37
     */
38
    public function setLogger($logger)
39
    {
40
        $this->logger = $logger;
41
    }
42
43
    /**
44
     * Should not handle Validation Exceptions and only service exceptions
45
     *
46
     * @param GetResponseForExceptionEvent $event Sf Event
47
     *
48
     * @return void
49
     */
50
    public function onKernelException(GetResponseForExceptionEvent $event)
51
    {
52
        $exception = $event->getException();
53
54
        // Should return a error 400 bad request
55
        if ($exception instanceof ValidationException
56
         || $exception instanceof SyntaxErrorException) {
57
            return;
58
        }
59
60
        // Some Exceptions have status code and if 400 it should be handled by them
61
        if (method_exists($exception, 'getStatusCode')
62
            && (400 == (int)$exception->getStatusCode())) {
63
            return;
64
        }
65
66
        $data = $this->decorateKnownCases($exception);
67
68
        if (!is_array($data)) {
69
            $data = [
70
                'code' => $exception->getCode(),
71
                'message' => $exception->getMessage()
72
            ];
73
        }
74
75
        if ($this->logger instanceof Logger) {
76
            $this->logger->critical($exception);
77
        }
78
79
        $response = new JsonResponse($data);
80
        $event->setResponse($response);
81
    }
82
83
    /**
84
     * Here we can pick up known cases that can happen and render a more detailed error message for the client.
85
     * It may be cumbersome, but it's good to detail error messages then just to let general error messages
86
     * generate support issues and work for us.
87
     *
88
     * @param \Exception $exception exception
89
     *
90
     * @return array|null either a error message array or null if the general should be displayed
91
     */
92
    private function decorateKnownCases($exception)
93
    {
94
        if (
95
            $exception instanceof ContextErrorException &&
96
            strpos($exception->getMessage(), 'Undefined index: $id') !== false
97
        ) {
98
            return [
99
                'code' => $exception->getCode(),
100
                'message' => 'An incomplete internal MongoDB ref has been discovered that can not be rendered. '.
101
                    'Did you pass a select() RQL statement and shaved off on the wrong level? Try to select a level '.
102
                    'higher.'
103
            ];
104
        } elseif (
105
            $exception instanceof SerializationException &&
106
            strpos($exception->getMessage(), 'Cannot serialize content class') !== false
107
        ) {
108
            $error = $exception->getMessage();
109
            $message =  strpos($error, 'not be found.') !== false ?
110
                substr($error, 0, strpos($error, 'not be found.')).'not be found.' : $error;
111
            preg_match('/\bwith id: (.*);.*?\bdocument\\\(.*)".*?\bidentifier "(.*)"/is', $message, $matches);
112
            if (array_key_exists(3, $matches)) {
113
                $sentence = 'Internal Database reference error as been discovered. '.
114
                    'The object id: "%s" has a reference to document: "%s" with id: "%s" that could not be found.';
115
                $message = sprintf($sentence, $matches[1], $matches[2], $matches[3]);
116
            }
117
            return [
118
                'code' => $exception->getCode(),
119
                'message' => $message
120
            ];
121
        }
122
    }
123
}
124