samuelgfeller / slim-error-renderer
Slim 4 error handling middleware and exception page renderer
Fund package maintenance!
Ko Fi
Installs: 178
Dependents: 3
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:project
Requires
- php: ^8.2
- ext-json: *
Requires (Dev)
This package is auto-updated.
Last update: 2024-11-16 12:17:47 UTC
README
This package provides an alternative to the default Slim error handler and renderer.
It renders a styled error details page with the stack trace and the error message
or a generic error page for production.
Custom error page renderers can be created to change the design of the error pages
by implementing the ErrorDetailsPageRendererInterface
or GenericErrorPageRendererInterface
.
It also provides a middleware to make the project "exception-heavy", which means that it will throw exceptions with a stack trace for notices and warnings during development and testing like other frameworks such as Laravel or Symfony.
Preview
Requirements
- PHP 8.2+
- Composer
- A Slim 4 application
Installation
Install the package with composer
Open a terminal in your project's root directory and run the following command:
composer require samuelgfeller/slim-error-renderer
Configuration
The following configuration values are required in the settings. Modify accordingly in the development, production, and testing configuration files.
File: config/defaults.php
$settings['error'] = [ // Must be set to false in production 'display_error_details' => false, // Whether to log errors or not 'log_errors' => true, ];
Add the error handling middleware to the Slim app
Container instantiation
If you're using
Dependency Injection,
add the error handling middleware to
the container definitions (e.g. in the config/container.php
) file.
The ExceptionHandlingMiddleware
constructor accepts the following parameters:
- Required: instance of a response factory object implementing the
Psr\Http\Message\ResponseFactoryInterface
(see here for a default implementation of a response factory) - Optional: instance of a PSR 3 logger to log the error
- Optional: boolean to display error details (documentation: Error Handling)
- Optional: contact email for the "report error" button on the error page
- Optional: A custom generic error page renderer that
implements
SlimErrorRenderer\Interfaces\ProdErrorPageRendererInterface
- Optional: A custom error details page renderer that
implements
SlimErrorRenderer\Interfaces\ErrorDetailsPageRendererInterface
<?php use SlimErrorRenderer\Middleware\ExceptionHandlingMiddleware; return [ // ... ExceptionHandlingMiddleware::class => function (ContainerInterface $container) { $settings = $container->get('settings'); $app = $container->get(App::class); return new ExceptionHandlingMiddleware( $app->getResponseFactory(), $settings['error']['log_errors'] ? $container->get(LoggerInterface::class) : null, $settings['error']['display_error_details'], $settings['public']['main_contact_email'] ?? null ); }, // ... ];
Middleware stack
The middleware can now be added to the middleware stack in the config/middleware.php
file.
It should be the very last middleware in the stack to catch all exceptions (Slim middlewares
are executed in the
reverse order
they are added).
This replaces the default slim error middleware.
<?php use Slim\App; return function (App $app) { // ... // Handle exceptions and display error page $app->add(ExceptionHandlingMiddleware::class); }
"Exception-heavy" middleware
The NonFatalErrorHandlingMiddleware
promotes warnings and notices to exceptions
when the display_error_details
setting is set to true
in the
configuration.
This means that the error details for notices and warnings will be displayed
with the stack trace and error message.
Container instantiation
The NonFatalErrorHandlingMiddleware
also needs to be instantiated in the container.
The constructor takes three parameters:
- Required: bool to display error details
- Required: bool to log the warning / notice
- Optional: instance of a PSR 3 logger to log the warning / notice
<?php use SlimErrorRenderer\Middleware\NonFatalErrorHandlingMiddleware; return [ // ... NonFatalErrorHandlingMiddleware::class => function (ContainerInterface $container) { $settings = $container->get('settings'); return new NonFatalErrorHandlingMiddleware( $settings['error']['display_error_details'], $settings['error']['log_errors'] ? $container->get(LoggerInterface::class) : null, ); }, // ... ];
Add to middleware stack
The middleware should be added right above the ExceptionHandlingMiddleware
in
the stack.
File: config/middleware.php
use Slim\App; return function (App $app) { // ... // Promote warnings and notices to exceptions $app->add(NonFatalErrorHandlingMiddleware::class); // <- Add here // Handle exceptions and display error page $app->add(ExceptionHandlingMiddleware::class); }
Conclusion
Have a look a the slim-starter
for a default
implementation of this package and the
slim-example-project
for a custom
prod error page with layout.
Why use this package?
A reason this small library exists instead of using the default Slim error handler and a custom
error renderer,
is to provide the "exception-heavy" feature and better-looking error pages.
But these things can be achieved with a custom error renderer and middleware located in the project as well.
The issue with the default Slim\Handlers\ErrorHandler
is that while testing, the
$contentType
in the error handler is null
and instead of using any custom error renderer
its hardcoded to use the Slim\Error\Renderers\HtmlErrorRenderer
. This has two consequences:
- The error is not thrown while integration testing, which means debugging is harder.
- Tests where an exception is expected, fail with the
PHPUnit 11 warning
Test code or tested code did not remove its own error handlers
. A fix for this message is callingrestore_error_handler()
but this can't be done as the error handler doesn't allow for custom error renderers when testing.
So a custom handler is required anyway, and with the custom renderers and the handling of non-fatal errors, it made sense to put that in a separate small library.
License
This project is licensed under the MIT license — see the LICENSE file for details.