8000 Get exception content according to request format · symfony/symfony@259fa20 · GitHub
[go: up one dir, main page]

Skip to content

Commit 259fa20

Browse files
committed
Get exception content according to request format
1 parent 4ad54da commit 259fa20

File tree

5 files changed

+184
-2
lines changed

5 files changed

+184
-2
lines changed

src/Symfony/Component/Debug/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ CHANGELOG
88
* added `Exception\FlattenException::getAsString` and
99
`Exception\FlattenException::getTraceAsString` to increase compatibility to php
1010
exception objects
11+
* added `ExceptionHandler::getFormattedContent()` to get the exception content
12+
according to given format (html, json, xml, txt)
1113

1214
4.0.0
1315
-----

src/Symfony/Component/Debug/ExceptionHandler.php

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Debug\Exception\FlattenException;
1515
use Symfony\Component\Debug\Exception\OutOfMemoryException;
16+
use Symfony\Component\HttpFoundation\Response;
1617
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
1718

1819
/**
@@ -189,6 +190,160 @@ public function sendPhpResponse($exception)
189190
echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
190191
}
191192

193+
/**
194+
* Gets the content associated with the given exception.
195+
*
196+
* @param \Exception|FlattenException $exception An \Exception or FlattenException instance
197+
* @param string $format The request format (html, json, xml, txt)
198+
*
199+
* @return string The formatted content as a string
200+
*/
201+
public function getFormattedContent($exception, string $format): string
202+
{
203+
switch ($format) {
204+
case 'json':
205+
return $this->getJson($exception);
206+
case 'xml':
207+
case 'rdf':
208+
return $this->getXml($exception);
209+
case 'txt':
210+
return $this->getTxt($exception);
211+
default:
212+
return $this->getHtml($exception);
213+
}
214+
}
215+
216+
/**
217+
* Gets the JSON content associated with the given exception.
218+
*
219+
* @param \Exception|FlattenException $exception An \Exception or FlattenException instance
220+
*
221+
* @return string The JSON content as a string
222+
*/
223+
public function getJson($exception): string
224+
{
225+
if (!$exception instanceof FlattenException) {
226+
$exception = FlattenException::create($exception);
227+
}
228+
229+
if (404 === $statusCode = $exception->getStatusCode()) {
230+
$title = 'Not Found';
231+
} elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) {
232+
$title = Response::$statusTexts[$statusCode];
233+
} else {
234+
$title = 'Internal Server Error';
235+
}
236+
237+
$content = [
238+
'title' => $title,
239+
'status' => $statusCode,
240+
'detail' => $this->escapeHtml($exception->getMessage()),
241+
];
242+
243+
if ($this->debug) {
244+
3419 $content['exceptions'] = $exception->toArray();
245+
}
246+
247+
return (string) json_encode($content);
248+
}
249+
250+
/**
251+
* Gets the XML content associated with the given exception.
252+
*
253+
* @param \Exception|FlattenException $exception An \Exception or FlattenException instance
254+
*
255+
* @return string The XML content as a string
256+
*/
257+
public function getXml($exception): string
258+
{
259+
if (!$exception instanceof FlattenException) {
260+
$exception = FlattenException::create($exception);
261+
}
262+
263+
if (404 === $statusCode = $exception->getStatusCode()) {
264+
$title = 'Not Found';
265+
} elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) {
266+
$title = Response::$statusTexts[$statusCode];
267+
} else {
268+
$title = 'Internal Server Error';
269+
}
270+
$message = $this->escapeHtml($exception->getMessage());
271+
272+
$exceptions = '';
273+
if ($this->debug) {
274+
$exceptions .= '<exceptions>';
275+
foreach ($exception->toArray() as $e) {
276+
$exceptions .= sprintf('<exception class="%s" message="%s"><traces>', $e['class'], $this->escapeHtml($e['message']));
277+
foreach ($e['trace'] as $trace) {
278+
$exceptions .= '<trace>';
279+
if ($trace['function']) {
280+
$exceptions .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], strip_tags($this->formatArgs($trace['args'])));
281+
}
282+
if (isset($trace['file'], $trace['line'])) {
283+
$exceptions .= strip_tags($this->formatPath($trace['file'], $trace['line']));
284+
}
285+
$exceptions .= '</trace>';
286+
}
287+
$exceptions .= '</traces></exception>';
288+
}
289+
$exceptions .= '</exceptions>';
290+
}
291+
292+
return <<<EOF
293+
<?xml version="1.0" encoding="{$this->charset}" ?>
294+
<problem xmlns="urn:ietf:rfc:7807">
295+
<title>{$title}</title>
296+
<status>{$statusCode}</status>
297+
<detail>{$message}</detail>
298+
{$exceptions}
299+
</problem>
300+
EOF;
301+
}
302+
303+
/**
304+
* Gets the TXT content associated with the given exception.
305+
*
306+
* @param \Exception|FlattenException $exception An \Exception or FlattenException instance
307+
*
308+
* @return string The TXT content as a string
309+
*/
310+
public function getTxt($exception): string
311+
{
312+
if (!$exception instanceof FlattenException) {
313+
$exception = FlattenException::create($exception);
314+
}
315+
316+
if (404 === $statusCode = $exception->getStatusCode()) {
317+
$title = 'Not Found';
318+
} elseif (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) {
319+
$title = Response::$statusTexts[$statusCode];
320+
} else {
321+
$title = 'Internal Server Error';
322+
}
323+
324+
$content = sprintf("[title] %s\n", $title);
325+
$content .= sprintf("[status] %s\n", $statusCode);
326+
$content .= sprintf("[detail] %s\n", $exception->getMessage());
327+
328+
if ($this->debug) {
329+
foreach ($exception->toArray() as $i => $e) {
330+
$content .= sprintf("[%d] %s: %s\n", $i + 1, $e['class'], $e['message']);
331+
332+
foreach ($e['trace'] as $trace) {
333+
if ($trace['function']) {
334+
$content .= sprintf('at %s%s%s(%s) ', $trace['class'], $trace['type'], $trace['function'], strip_tags($this->formatArgs($trace['args'])));
335+
}
336+
if (isset($trace['file'], $trace['line'])) {
337+
$content .= strip_tags($this->formatPath($trace['file'], $trace['line']));
338+
}
339+
$content .= "\n";
340+
}
341+
}
342+
}
343+
344+
return $content;
345+
}
346+
192347
/**
193348
* Gets the full HTML content associated with the given exception.
194349
*

src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,28 @@ public function testHandleOutOfMemoryException()
139139

140140
$handler->handle($exception);
141141
}
142+
143+
public function testJsonExceptionContent()
144+
{
145+
$handler = new ExceptionHandler(true);
146+
$content = $handler->getJson(new \RuntimeException('Foo'));
147+
148+
$this->assertStringMatchesFormat('{"title":"Internal Server Error","status":500,"detail":"Foo","exceptions":[{"message":"Foo","class":"RuntimeException"%S}]}', $content);
149+
}
150+
151+
public function testXmlExceptionContent()
152+
{
153+
$handler = new ExceptionHandler(true);
154+
$content = $handler->getXml(new \RuntimeException('Foo'));
155+
156+
$this->assertStringMatchesFormat('<?xml version="1.0" encoding="UTF-8" ?>%A<problem xmlns="urn:ietf:rfc:7807">%A<title>Internal Server Error</title>%A<status>500</status>%A<detail>Foo</detail>%A<exceptions><exception class="RuntimeException" message="Foo"><traces><trace>%A', $content);
157+
}
158+
159+
public function testTxtExceptionContent()
160+
{
161+
$handler = new ExceptionHandler(true);
162+
$content = $handler->getTxt(new \RuntimeException('Foo'));
163+
164+
$this->assertStringMatchesFormat("[title] Internal Server Error\n[status] 500\n[detail] Foo\n[1] RuntimeException: Foo\nin ExceptionHandlerTest.php line %A", $content);
165+
}
142166
}

src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,10 @@ protected function duplicateRequest(\Exception $exception, Request $request)
151151
{
152152
$attributes = [
153153
'exception' => $exception = FlattenException::create($exception),
154-
'_controller' => $this->controller ?: function () use ($exception) {
154+
'_controller' => $this->controller ?: function () use ($exception, $request) {
155155
$handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat);
156156

157-
return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders());
157+
return new Response($handler->getFormattedContent($exception, $request->getRequestFormat()), $exception->getStatusCode(), $exception->getHeaders());
158158
},
159159
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
160160
];

src/Symfony/Component/HttpKernel/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"conflict": {
4949
"symfony/browser-kit": "<4.3",
5050
"symfony/config": "<3.4",
51+
"symfony/debug": "<4.3",
5152
"symfony/dependency-injection": "<4.2",
5253
"symfony/translation": "<4.2",
5354
"symfony/var-dumper": "<4.1.1",

0 commit comments

Comments
 (0)
0