I checked the code of the custom error middleware: https://www.slimframework.com/docs/v4/middleware/error-handling.html
It is far from obvious how I can use the PhpRenderer (or any renderer compatible with SLIM) with my current layout and menu to add a custom error page. Is there anyone who managed to do this?
I instantiate my renderer this way after I set up error handling.
$this->renderer = new PhpRenderer(__DIR__ . '/template');
$this->renderer->setLayout("layout.php");
$this->renderer->addAttribute('csrf', $this->getCrossSiteRequestForgeryPreventionToken());
$this->renderer->addAttribute('flash', $this->getFlashMessages());
$this->renderer->addAttribute('html', new HTMLHelper($this->renderer));
While calling the error renderer looks like this:
$errorMiddleware = $application->addErrorMiddleware($this->getConfiguration()->isDisplayingErrors(), $logErrors = true, $logErrorDetails = true);
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->registerErrorRenderer('text/html', ErrorRenderer::class);
And the class itself looks like this:
use SlimExceptionHttpNotFoundException;
use SlimInterfacesErrorRendererInterface;
use Throwable;
class ErrorRenderer implements ErrorRendererInterface {
public function __invoke(Throwable $exception, bool $displayErrorDetails):string{
$title = 'Error';
$message = 'An error has occurred.';
$trace = '';
if ($exception instanceof HttpNotFoundException) {
$title = 'Page not found';
$message = 'This page could not be found.';
}
if ($displayErrorDetails){
$message = $exception->getMessage();
$trace = $exception->getTraceAsString();
}
return $this->renderHtmlPage($title, $message, $trace);
}
public function renderHtmlPage(string $title='', string $message='', string $trace=''):string {
$title = htmlentities($title, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8');
$message = htmlentities($message, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8');
$trace = htmlentities($trace, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8');
$trace = preg_replace('%
%usD', '<br/>', $trace);
return <<<EOT
<!DOCTYPE html>
<html>
<head>
<title>$title - My website</title>
</head>
<body>
<h1>$title</h1>
<p>$message</p>
<p>$trace</p>
</body>
</html>
EOT;
}
}
I could reuse at least the HTMLHelper and do $html->addText(...)
instead of using htmlentities
directly. Adding the layout would be awesome too.
Yet another question that we appear to have 2 error pages, because if everything fails we fall back to the PHP error page if the php.ini allows it. So is there a way to avoid it?
2
Answers
What I did is using dependency injection as @odan suggested.
After it I used the fetch method on the layout and set the content parameter.
This way I don't need to use the render method to have a layout, because that one requires a response object which the error renderer does not provide.
You can integrate your renderer into the error rendering process via dependency injection.
In your template that includes your layout:
Note: Replace the
html
function with your implementation.