Subscribe to PHP Freaks RSS

Displaying errors in Expressive with Twig

syndicated from planet-php.net on October 18, 2017

If you're not using the Whoops error handler with Expressive and are using the Twig renderer, then you are given no information about the problem that occurred, even in debug mode.

To fix this, I changed error.html.twig to this:

{% extends '@layout/default.html.twig' %}

{% block title %}{{ status }} {{ reason }}{% endblock %}

{% block content %} <h1>Oops!</h1> <h2>This is awkward.</h2> <p>We encountered a {{ status }} {{ reason }} error.</p> {% if status == 404 %} <p> You are looking for something that doesn't exist or may have moved. Check out one of the links on this page or head back to <a href="{{ path('home') }}">Home</a>. </p> {% endif %}

{% if error %} <h2>Error details</h2> <p>Message: <strong>{{ error.getMessage() }}</strong></p> <p>in <tt>{{ error.getFile() }}:{{ error.getLine() }}</tt></p> <p>Trace:</p> <pre>{{ error.getTraceAsString() }}</pre>

{% set prev = error.getPrevious() %} {% for i in 1..10000 if prev %} <h3>Previous error</h3> <p>Message: <strong>{{ prev.getMessage() }}</strong></p> <p>in <tt>{{ prev.getFile() }}:{{ prev.getLine() }}</tt></p> <p>Trace:</p> <pre>{{ prev.getTraceAsString() }}</pre> {% set prev = prev.getPrevious() %} {% endfor %} {% endif %} {% endblock %}

The new part is the within the {% if error %} block. In debug mode, error is set to the exception that was thown and is blank otherwise, so you won't leak sensitive information (as long as you don't enable debug in production).

Inside the {% if error %} block, I render the error message and where it happened and then iterate down through any previous errors and displays their information too. Interestingly, there isn't a while loop in Twig which would be ideal to recursively iterate through the previous errors. To solve this, I used the for..in..if construct which works nicely as long as I don't have more than 10,000 previous errors!

If you use the Zend-View or Plates rendering engines, I imagine similar code would work there too.