CakePHP - Vlastní Exception Handler pro lepší přehled nad průšvihy
Článek je psán na verzi CakePHP 2.4.1 a snad mu porozumí začátečník i pokročilý. Pokud najdete chybku, nebo je něco nejasné, křičte na mě v komentářích!
Žádný program není bez chyb (teda alespoň ty moje...), ale je fajn se o nich dozvědět a občas s nimi něco udělat. Cake používá výjimky hlavně pro nenalezené stránky a špatné parametry, ale člověk je může vyvolávat kde chce a jak chce. Jen pozor na výkon, přece jen vytvoření objektu výjimky nějaké prostředky zabere, tak ať to stojí za to!
K věci: Vlastní Exception Handler pro více informací
V původním Exception Handleru toho Cake moc říct nechce. V podstatě jen loguje chybu se špetkou kontextu. Já chci ale vědět, o které URL se mluví a hlavně jak se tam uživatel dostal, takže jdeme vařit podle vlastní kuchařky!
V app/Lib si vytvoříme soubor AppExceptionHandler.php do kterého umístímě následující:
<?php
App::uses('ExceptionHandler', 'Error');
class AppExceptionHandler {
public static function handle(Exception $exception) {
CakeLog::write(LOG_ERR, self::_getMessage($exception));
ErrorHandler::handleException($exception);
}
protected static function _getMessage($exception) {
// chtělo by to vracet nějaké info
return print_r($exception, true);
}
}
Jednoduchá metoda handle vlastně jen přijme výjimku, pomocí CakeLog::write ji zaloguje a pak dá vědět návštěvníkovi, že něco rozbil. Nám je ale v tento moment návštěvník u samého konce trávícího traktu, chceme vytřískat co nejvíce informací z výjimky a proto doplníme metodu _getMessage o něco užitečnějšího.
protected static function _getMessage($exception) {
$message = sprintf("[%s] %s",
get_class($exception),
$exception->getMessage()
);
if (method_exists($exception, 'getAttributes')) {
$attributes = $exception->getAttributes();
if ($attributes) {
$message .= "\nException Attributes: " . var_export($exception->getAttributes(), true);
}
}
if (php_sapi_name() !== 'cli') {
$request = Router::getRequest();
if ($request) {
// přidám do zprávy kýžené URL
$message .= "\nRequest URL: " . $request->here();
$message .= "\nReferer URL: " . $request->referer();
}
}
// a přihodím seznam volaných funkcí, které mě k chybě dovedly
$message .= "\nStack Trace:\n" . $exception->getTraceAsString();
$message .= "\n---------------------------------------------";
return $message;
}
Abych byl upřímný, polovina kódu je pro mě černou magií zkopírovanou z původního exception handleru, ale důležité je, že si ukládám navíc Request URL a Referer URL, plus pro přehlednost přihodím hromadu pomlček, abych se v tom balastu lépe vyznal.
Integrace do aplikace je už maličkost
No, a nakonec je potřeba aplikaci o Exception handleru někde říct, takže v core.php změníme záznam s Configure::write('Exception',...) na toto:
Configure::write('Exception', array(
'handler' => 'AppExceptionHandler::handle',
'renderer' => 'ExceptionRenderer',
'log' => false
));
...a v bootstrap.php si někde na začátku handler načteme pomocí App::uses('AppExceptionHandler', 'Lib');. A je to!
Samozřejmě je možné si zobrazit i jiné věci z request objektu, ale nic užitečného mě nenapadá. Článek je inspirován oficiálním návodem a trochou zoufalství při odhalování bugů. Pokud máte nějaké dotazy nebo připomínky, rád si počtu v diskusi pod článkem!