Completed
Push — master ( 6744a4...ab6d26 )
by Guilh
7s
created

ExceptionController::getFormat()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.3332

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 14
ccs 6
cts 9
cp 0.6667
rs 9.4285
cc 3
eloc 9
nc 6
nop 2
crap 3.3332
1
<?php
2
3
/*
4
 * This file is part of the FOSRestBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\RestBundle\Controller;
13
14
use FOS\RestBundle\Util\ClassMapHandlerTrait;
15
use FOS\RestBundle\View\View;
16
use FOS\RestBundle\View\ViewHandlerInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\Debug\Exception\FlattenException;
20
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
21
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
22
23
/**
24
 * Custom ExceptionController that uses the view layer and supports HTTP response status code mapping.
25
 */
26
class ExceptionController
27
{
28
    use ClassMapHandlerTrait;
29
30
    private $viewHandler;
31
    private $exceptionCodes;
32
    private $showException;
33
34 4
    public function __construct(
35
        ViewHandlerInterface $viewHandler,
36
        array $exceptionCodes,
37
        $showException
38
    ) {
39 4
        $this->viewHandler = $viewHandler;
40 4
        $this->exceptionCodes = $exceptionCodes;
41 4
        $this->showException = $showException;
42 4
    }
43
44
    /**
45
     * Converts an Exception to a Response.
46
     *
47
     * @param Request                   $request
48
     * @param \Exception                $exception
49
     * @param DebugLoggerInterface|null $logger
50
     *
51
     * @throws \InvalidArgumentException
52
     *
53
     * @return Response
54
     */
55 4
    public function showAction(Request $request, \Exception $exception, DebugLoggerInterface $logger = null)
56
    {
57 4
        $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
58 4
        $code = $this->getStatusCode($exception);
59 4
        $templateData = $this->getTemplateData($currentContent, $code, $exception, $logger);
60
61 4
        $view = $this->createView($exception, $code, $templateData, $request, $this->showException);
62 4
        $response = $this->viewHandler->handle($view);
63
64 4
        return $response;
65
    }
66
67
    /**
68
     * @param \Exception $exception
69
     * @param int        $code
70
     * @param array      $templateData
71
     * @param Request    $request
72
     * @param bool       $showException
73
     *
74
     * @return View
75
     */
76 4
    protected function createView(\Exception $exception, $code, array $templateData, Request $request, $showException)
77
    {
78 4
        $view = new View($exception, $code, $exception instanceof HttpExceptionInterface ? $exception->getHeaders() : []);
79 4
        $view->setTemplateVar('raw_exception');
80 4
        $view->setTemplateData($templateData);
81
82 4
        return $view;
83
    }
84
85
    /**
86
     * Determines the status code to use for the response.
87
     *
88
     * @param \Exception $exception
89
     *
90
     * @return int
91
     */
92 4
    protected function getStatusCode(\Exception $exception)
93
    {
94
        // If matched
95 4
        if ($statusCode = $this->resolveValue(get_class($exception), $this->exceptionCodes)) {
96
            return $statusCode;
97
        }
98
99
        // Otherwise, default
100 4
        if ($exception instanceof HttpExceptionInterface) {
101
            return $exception->getStatusCode();
102
        }
103
104 4
        return 500;
105
    }
106
107
    /**
108
     * Determines the parameters to pass to the view layer.
109
     *
110
     * Overwrite it in a custom ExceptionController class to add additionally parameters
111
     * that should be passed to the view layer.
112
     *
113
     * @param string               $currentContent
114
     * @param int                  $code
115
     * @param \Exception           $exception
116
     * @param DebugLoggerInterface $logger
117
     *
118
     * @return array
119
     */
120 4
    private function getTemplateData($currentContent, $code, \Exception $exception, DebugLoggerInterface $logger = null)
121
    {
122
        return [
123 4
            'exception' => FlattenException::create($exception),
124 4
            'status' => 'error',
125 4
            'status_code' => $code,
126 4
            'status_text' => array_key_exists($code, Response::$statusTexts) ? Response::$statusTexts[$code] : 'error',
127 4
            'currentContent' => $currentContent,
128 4
            'logger' => $logger,
129 4
        ];
130
    }
131
132
    /**
133
     * Gets and cleans any content that was already outputted.
134
     *
135
     * This code comes from Symfony and should be synchronized on a regular basis
136
     * see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php
137
     *
138
     * @return string
139
     */
140 4
    private function getAndCleanOutputBuffering($startObLevel)
141
    {
142 4
        if (ob_get_level() <= $startObLevel) {
143 4
            return '';
144
        }
145
        Response::closeOutputBuffers($startObLevel + 1, true);
146
147
        return ob_get_clean();
148
    }
149
}
150