ErrorHandling brick
Без цього brick несподіваний збій виглядає як сирий PHP-фатал
або stack trace у браузері на проді. Два різні завдання:
повідомити (report у лог) і відмалювати
безпечну відповідь (Whoops локально / fallback HTML /
JSON envelope). addErrorHandling() на
ConceptStack підключає
extension-error-handler-whoops
і повертає ErrorHandlingBuilder. Рецепт —
Обробка помилок.
Renderer і reporter задаються окремо навмисно: можна
спочатку писати в error_log без Monolog, а пізніше
лише змінити setLogReporting — Whoops і fallback
не чіпаючи. withViewRenderer і
withJsonRenderer — XOR (один renderer на
capability): HTML-додаток vs чистий API.
Очікувані помилки форми (ValidationException,
CSRF) — не зона цього brick: їх ловлять middleware
у routes/*.php, інакше вони виглядали б як 500.
Методи ErrorHandlingBuilder:
| Метод | Параметри | Опис | Залежність |
|---|---|---|---|
setDebug() |
bool $debug = true, HandlerInterface|Closure|null $handler = null |
Whoops PrettyPage (або інший handler) для non-JSON HTTP | — |
setLogReporting() |
bool $logger = true, bool $phpErrorLog = true |
Report recipe: Logger і/або PHP error_log |
addLogging() якщо $logger |
setReporter() |
ExceptionReporterInterface|Closure |
Кастомний reporter | — |
withViewRenderer() |
string $fallbackPath = '' |
View + JSON Accept + PHP fallback files | addView() |
withJsonRenderer() |
— | Лише JSON error envelope (API без View) | addHttp() |
setRenderer() |
HttpErrorRendererInterface|Closure |
Кастомний renderer | — |
setDebug()
$stack->addErrorHandling()
->setDebug(true, new PrettyPageHandler());
Той самий прапорець, що APP_DEBUG у Docker: локально
розробнику потрібен Whoops (швидкий діагноз), на проді —
жоден stack trace у браузері. При $debug = true
для HTML-запитів показується Whoops (або переданий handler);
при false — обраний renderer (fallback / JSON).
JSON Accept завжди йде в безпечний JSON renderer, навіть у
debug — API-клієнту Whoops HTML не потрібен.
setLogReporting()
$stack->addErrorHandling()
->setLogReporting(); // logger + php error_log
// ->setLogReporting(true, false); // лише LoggerInterface
// ->setLogReporting(false, true); // лише error_log
Помилку все одно треба кудись записати, навіть коли сторінка
«спокійна». Хоча б один канал має бути true.
На кроці рецепта без Monolog ставлять
logger: false, phpErrorLog: true — свідомий
компроміс; коли з’явиться
Logging, увімкнете
logger: true без переробки Whoops і fallback.
З $logger = true Stack вимагає
addLogging().
setReporter()
$stack->addErrorHandling()
->setReporter(new MyExceptionReporter());
Коли стандартного «Logger і/або error_log» мало (Sentry,
власний bus): escape hatch замість
setLogReporting() — власний
ExceptionReporterInterface або factory-closure
з контейнера.
withViewRenderer()
$stack->addErrorHandling()
->withViewRenderer($rootPath . 'resources/views/errors/fallback');
Для HTML-додатка з View: спочатку пробує Twig
@frontend/errors/{code} (або namespace з route).
Якщо шаблону немає — PHP-файл
{fallbackPath}/{code}.php, інакше мінімальний HTML.
Fallback навмисно простий PHP, не Twig: production-відповідь
не залежить від того, чи зібрався Twig-кеш. JSON Accept →
jsonError. XOR із withJsonRenderer().
Потребує addView().
withJsonRenderer()
$stack->addErrorHandling()
->withJsonRenderer();
Коли View немає і клієнт завжди чекає JSON envelope — не
тягніть Twig лише заради 500-сторінки. Потребує
addHttp(). Не сумісний із
withViewRenderer() на тому ж builder.
setRenderer()
$stack->addErrorHandling()
->setRenderer(new MyHttpErrorRenderer());
Повний контроль над HTTP-відповіддю на помилку
(HttpErrorRendererInterface або factory), коли
ні view-, ні json-рецепт не підходять (наприклад, branded
error pages з власним pipeline).
Що реєструє brick
- Whoops / error handler wiring у kernel
ExceptionReporterInterfaceHttpErrorRendererInterface
Middleware на ValidationException / CSRF — у
routes/*.php, не в цьому brick: вони перетворюють
«очікувану» помилку на UX, а не на Whoops.
Рецепт — 7. Обробка помилок. Logging — Logging brick (окремий крок: спочатку render/report, потім Monolog).