contenir / errors
Framework-agnostic admin-authored error-page content for Contenir CMS — admin writes per-status titles and bodies, Site renders.
Requires
- php: ^8.1 || ^8.2 || ^8.3
Requires (Dev)
- contenir/config: ^0.1.0
- phpunit/phpunit: ^11.0
- squizlabs/php_codesniffer: ^3.10
Suggests
- contenir/config: Required if you intend to use Repository\FileRepository (admin-side writer). Sites that read state from the merged Laminas/Mezzio config — and use Repository\InMemoryRepository — don't need it.
README
Framework-agnostic admin-authored error-page content for Contenir CMS.
The CMS lets an operator author per-status error pages (404, 500, 403, …). The consuming Site (Mezzio, Laminas MVC, anything else) reads those pages on every error and replaces the framework's default rendering with on-brand content.
This package provides the domain — an immutable per-status value plus
a repository interface, with file-based and in-memory implementations.
Framework-specific listeners/middleware come from sibling packages
(e.g. contenir/errors-laminas-mvc).
Install
composer require contenir/errors
Zero runtime dependencies — pure PHP 8.1+.
Usage
Reading pages
use Contenir\Errors\Repository\FileRepository; $repo = new FileRepository('/var/www/shared/errors.local.php'); $page = $repo->get(404); if ($page !== null && ! $page->isEmpty()) { // Render with $page->title and $page->body }
Writing pages (admin)
use Contenir\Errors\ErrorPage; $repo->save(new ErrorPage(404, 'Page not found', '<p>Try the homepage.</p>')); $repo->delete(404);
The body is expected to be a sanitized HTML fragment — inline elements only, no scripts/styles. Sanitization is the writer's responsibility; readers render raw and trust the contract.
File format
FileRepository reads/writes a PHP file that returns an array indexed
by HTTP status code:
<?php return [ 404 => [ 'title' => 'Page not found', 'body' => '<p>Try the <a href="/">homepage</a>.</p>', ], 500 => [ 'title' => 'Something went wrong', 'body' => '<p>We have been notified.</p>', ], ];
A missing or unreadable file resolves to no configured pages, so first-run and permission edge cases don't crash the consumer.
Testing
InMemoryRepository is shipped in src/ so consumers can use it in
their own test suites:
use Contenir\Errors\Repository\InMemoryRepository; use Contenir\Errors\ErrorPage; $repo = new InMemoryRepository([ new ErrorPage(404, 'Not found', '<p>Lost.</p>'), ]);