skip to Main Content

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('%&NewLine;%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


  1. Chosen as BEST ANSWER

    What I did is using dependency injection as @odan suggested.

    protected $renderer;
    public function __construct(PhpRenderer $renderer){
        $this->renderer = $renderer;
    }
    

    After it I used the fetch method on the layout and set the content parameter.

        $content = $this->renderer->fetch('error.php', ['title' => $title, 'message' => $message, 'trace' => $trace]);
        return $this->renderer->fetch('layout.php', ['content' => $content]);
    

    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.


  2. You can integrate your renderer into the error rendering process via dependency injection.

    use SlimExceptionHttpNotFoundException;
    use SlimInterfacesErrorRendererInterface;
    use SlimViewsPhpRenderer;
    use Throwable;
    
    class ErrorRenderer implements ErrorRendererInterface
    {
        private $renderer;
    
        public function __construct(PhpRenderer $renderer)
        {
            $this->renderer = $renderer;
        }
    
        public function __invoke(Throwable $exception, bool $displayErrorDetails): string
        {
            // ...
        }
    
        public function renderHtmlPage(string $title = '', string $message = '', string $trace = ''): string
        {
            // Render the error page using your renderer and layout
            $this->renderer->addAttribute('title', $title);
            $this->renderer->addAttribute('message', $message);
            $this->renderer->addAttribute('trace', $trace);
    
           // Assuming 'error.php' is your custom error page template
            return $this->renderer->fetch('error.php');
        }
    }
    

    In your template that includes your layout:

    <?php $this->layout('layout.php') ?>
    
    <h1><?= html($title) ?></h1>
    <p><?= html($message) ?></p>
    <p><?= html($trace) ?></p>
    

    Note: Replace the html function with your implementation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search