Completed
Push — master ( 665986...1514e7 )
by Guilh
08:09 queued 05:04
created

ExceptionController::showAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
cc 1
eloc 7
nc 1
nop 3
crap 1
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\ExceptionValueMap;
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
    /**
29
     * @var ViewHandlerInterface
30
     */
31
    private $viewHandler;
32
33
    /**
34
     * @var ExceptionValueMap
35
     */
36
    private $exceptionCodes;
37
38
    /**
39
     * @var bool
40
     */
41
    private $showException;
42
43 9
    public function __construct(
44
        ViewHandlerInterface $viewHandler,
45
        ExceptionValueMap $exceptionCodes,
46
        $showException
47
    ) {
48 9
        $this->viewHandler = $viewHandler;
49 9
        $this->exceptionCodes = $exceptionCodes;
50 9
        $this->showException = $showException;
51 9
    }
52
53
    /**
54
     * Converts an Exception to a Response.
55
     *
56
     * @param Request                   $request
57
     * @param \Exception|\Throwable     $exception
58
     * @param DebugLoggerInterface|null $logger
59
     *
60
     * @throws \InvalidArgumentException
61
     *
62
     * @return Response
63
     */
64 9
    public function showAction(Request $request, $exception, DebugLoggerInterface $logger = null)
65
    {
66 9
        $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
67 9
        $code = $this->getStatusCode($exception);
68 9
        $templateData = $this->getTemplateData($currentContent, $code, $exception, $logger);
69
70 9
        $view = $this->createView($exception, $code, $templateData, $request, $this->showException);
71 9
        $response = $this->viewHandler->handle($view);
72
73 9
        return $response;
74
    }
75
76
    /**
77
     * @param \Exception $exception
78
     * @param int        $code
79
     * @param array      $templateData
80
     * @param Request    $request
81
     * @param bool       $showException
82
     *
83
     * @return View
84
     */
85 9
    protected function createView(\Exception $exception, $code, array $templateData, Request $request, $showException)
86
    {
87 9
        $view = new View($exception, $code, $exception instanceof HttpExceptionInterface ? $exception->getHeaders() : []);
88 9
        $view->setTemplateVar('raw_exception');
89 9
        $view->setTemplateData($templateData);
90
91 9
        return $view;
92
    }
93
94
    /**
95
     * Determines the status code to use for the response.
96
     *
97
     * @param \Exception $exception
98
     *
99
     * @return int
100
     */
101 9
    protected function getStatusCode(\Exception $exception)
102
    {
103
        // If matched
104 9
        if ($statusCode = $this->exceptionCodes->resolveException($exception)) {
105
            return $statusCode;
106
        }
107
108
        // Otherwise, default
109 9
        if ($exception instanceof HttpExceptionInterface) {
110 1
            return $exception->getStatusCode();
111
        }
112
113 8
        return 500;
114
    }
115
116
    /**
117
     * Determines the parameters to pass to the view layer.
118
     *
119
     * Overwrite it in a custom ExceptionController class to add additionally parameters
120
     * that should be passed to the view layer.
121
     *
122
     * @param string               $currentContent
123
     * @param int                  $code
124
     * @param \Exception           $exception
125
     * @param DebugLoggerInterface $logger
126
     *
127
     * @return array
128
     */
129 9
    private function getTemplateData($currentContent, $code, \Exception $exception, DebugLoggerInterface $logger = null)
130
    {
131
        return [
132 9
            'exception' => FlattenException::create($exception),
133 9
            'status' => 'error',
134 9
            'status_code' => $code,
135 9
            'status_text' => array_key_exists($code, Response::$statusTexts) ? Response::$statusTexts[$code] : 'error',
136 9
            'currentContent' => $currentContent,
137 9
            'logger' => $logger,
138 9
        ];
139
    }
140
141
    /**
142
     * Gets and cleans any content that was already outputted.
143
     *
144
     * This code comes from Symfony and should be synchronized on a regular basis
145
     * see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php
146
     *
147
     * @return string
148
     */
149 9
    private function getAndCleanOutputBuffering($startObLevel)
150
    {
151 9
        if (ob_get_level() <= $startObLevel) {
152 9
            return '';
153
        }
154
        Response::closeOutputBuffers($startObLevel + 1, true);
155
156
        return ob_get_clean();
157
    }
158
}
159