Created
June 19, 2019 09:20
-
-
Save bwaidelich/485172fb7c01c7aedf4e93b43875d98f to your computer and use it in GitHub Desktop.
Render Neos / Flow exceptions as JSON if a corresponding Accept / Content-Type header is set
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Some\Package\Error; | |
use Neos\Flow\Annotations as Flow; | |
use Neos\Flow\Http\Helper\ResponseInformationHelper; | |
use Neos\Flow\Http\Request; | |
use Neos\Flow\Mvc\Controller\ControllerContext; | |
use Neos\Flow\Mvc\View\ViewInterface; | |
use Neos\Utility\MediaTypes; | |
/** | |
* A View that can be used as exception view and that renders exceptions as JSON if the current HTTP request | |
* sends a corresponding "Accept" or "Content-Type" header. | |
* | |
* Example configuration: | |
* | |
* Flow: | |
* error: | |
* exceptionHandler: | |
* defaultRenderingOptions: | |
* viewClassName: 'Some\Package\Error\JsonCapableExceptionView' | |
* templatePathAndFilename: 'this-is-required' | |
* | |
* @Flow\Proxy(false) | |
*/ | |
final class JsonCapableExceptionView implements ViewInterface | |
{ | |
/** | |
* @var ControllerContext | |
*/ | |
private $controllerContext; | |
/** | |
* @var array | |
*/ | |
private $variables = []; | |
public static function createWithOptions(array $options): self | |
{ | |
return new static(); | |
} | |
public function setControllerContext(ControllerContext $controllerContext): void | |
{ | |
$this->controllerContext = $controllerContext; | |
} | |
public function assign($key, $value): self | |
{ | |
$this->variables[$key] = $value; | |
return $this; | |
} | |
public function assignMultiple(array $values): self | |
{ | |
foreach ($values as $key => $value) { | |
$this->assign($key, $value); | |
} | |
return $this; | |
} | |
public function canRender(ControllerContext $controllerContext): bool | |
{ | |
return true; | |
} | |
public function render(): string | |
{ | |
$statusCode = $this->variables['statusCode'] ?? 500; | |
$referenceCode = $this->variables['referenceCode'] ?? null; | |
$statusMessage = ResponseInformationHelper::getStatusMessageByCode($statusCode); | |
$referenceCodeMessage = ($referenceCode !== null) ? '<p>When contacting the maintainer of this application please mention the following reference code:<br /><br />' . $referenceCode . '</p>' : ''; | |
if ($this->isJsonRequest()) { | |
header('Content-Type: application/json'); | |
$error = [ | |
'message' => $statusMessage, | |
'code' => $statusCode, | |
'referenceCode' => $referenceCode, | |
]; | |
return json_encode($error); | |
} | |
return '<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<title>' . $statusCode . ' ' . $statusMessage . '</title> | |
<style type="text/css"> | |
body { | |
font-family: Helvetica, Arial, sans-serif; | |
margin: 50px; | |
} | |
h1 { | |
color: #00ADEE; | |
font-weight: normal; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>' . $statusCode . ' ' . $statusMessage . '</h1> | |
<p>An internal error occurred.</p> | |
' . $referenceCodeMessage . ' | |
</body> | |
</html>'; | |
} | |
private function isJsonRequest(): bool | |
{ | |
$request = Request::createFromEnvironment(); | |
$mediaTypeHeader = $request->hasHeader('Accept') && $request->getHeader('Accept') !== '*/*' ? $request->getHeader('Accept') : $request->getHeader('Content-Type'); | |
if ($mediaTypeHeader === null) { | |
return false; | |
} | |
$mediaType = MediaTypes::parseMediaType($mediaTypeHeader); | |
return $mediaType['subtype'] === 'json'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Neos: | |
Flow: | |
error: | |
exceptionHandler: | |
defaultRenderingOptions: | |
viewClassName: 'Some\Package\Error\JsonCapableExceptionView' | |
templatePathAndFilename: 'this-is-required' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment