Jak si vytvořit vlastní 404 stránku

Laravel nabízí ve výchozím nastavení chybovou šablonu pro errory typu 404 či 500. Často nám ale tyto šablony nevyhovují a potřebujeme si vracet vlastní, případně zobrazovat zcela jinou stránku při vlastní výjimce. V tomto článku si vysvětlíme jak a kde zachytávat obecné i vlastní výjimky a vracet vlastní šablony.

Všechny výjimky, které se v aplikaci vyhodí, se zachytávají ve třídě app/Exceptions/Handler.php. Díky tomu lze prakticky v tomto souboru reagovat na jakoukoliv výjimku a vrátit potřebnou odpověď.

Výchozí chybové stránky

Při prvním nainstalování Laravelu na žádné chybové stránky nenarazíte. Přesto pokud kdekoliv v běhu aplikace zavoláte helpery abort(404);, abort(500) či abort(403, 'Neautorizovaná akce.');, Laravel vám vrátí chybovou stránku. To proto, že framework na základě chybového kódu zavolá určitou šablonu, která se nachází až hluboko v /vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views. Pokud bychom chtěli tyto šablony využít a upravit si podle svého, stačí zavolat tento Artisan příkaz:

php artisan vendor:publish --tag=laravel-errors

Díky tomu se šablony překopírují do adresáře resources/views/errors, kde si je dle libosti můžete upravit. Tyto šablony se pak automaticky zavolají podle chybového statusu a není potřeba nic dalšího řešit.

Vlastní 404 stránka

Pokud nám ale výchozí chybová stránka nevyhovuje, tak ve třídě app/Exceptions/Handler.php si upravíme metodu render(). Ta je právě zodpovědná za zkonvertování výjimky do HTTP odpovědi, která bude odeslána zpět prohlížeči. Defaultně je výjimka předána rodičovské třídě, která vše vygeneruje za vás. My si ale chceme vygenerovat vlastní šablonu a proto si metodu upravíme po svém:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)
{
    if ($this->isHttpException($exception)) {
        if ($exception->getStatusCode() == 404) {
            return response()->view('errors.404', [], 404);
        }
    }
 
    return parent::render($request, $exception);
}

V této metodě jako první kontrolujeme, jestli se jedná o HTTP výjimku. Tato kontrola je velmi důležitá, protože jako dále kontrolujeme chybový kód 404 pomocí metody getStatusCode(), která je dostupná pouze při HTTP výjimkách. Pokud jsou všechny podmínky splněny, tak jednoduše vrátíme v odpovědi naši požadovanou šablonu. Pokud nějaká z podmínek selže, vrátíme defaultní chybovou stránku.

Při vyhození chyby 404 voláme šablonu v adresáři resources/errors/404.blade. Ta ale neexistuje a proto si ji musíme vytvořit:

<!DOCTYPE html>
<html>
<head>
    <title>404 - stránka nebyla nalezena</title>
</head>
<body>
 
Stránka, kterou hledáte, nebyla nalezena. Sorry jako.
 
</body>
</html>

Úplně stejným postupem můžeme zachytávat jakékoliv další chybové kódy jako jsou např. 500 nebo 403 a na základě toho vracet zcela jiné šablony a odpovědi. Odpověď si samozřejmě můžeme nechat dynamicky generovat, abychom nemuseli pro každý kód vytvářet vlastní podmínku:

public function render($request, Exception $exception)
{
    if ($this->isHttpException($exception)) {
        if (view()->exists('errors.' . $exception->getStatusCode())) {
            return response()->view('errors.' . $exception->getStatusCode(), [], $exception->getStatusCode());
        }
    }
 
    return parent::render($request, $exception);
}

Stránky pro vlastní výjimky

Máme vlastní výjimku, pro kterou chceme zobrazovat si unikátní chybovou stránku. Příkladem může být třeba vyhledávání, kdy v případě, že nebylo nic nalezeno, vyhodíme vlastní výjimku NotFoundException. I v tomto případě se výjimka zachytává ve třídě Handler.php, kterou tak potřebujeme upravit:

public function render($request, Exception $exception)
{
    if ($exception instanceof NotFoundException) {
        return response()->view('errors.empty-result');
    }
    return parent::render($request, $exception);
}

Tedy v případě vyhození vlastní výjimky si zkontrolujeme, jestli se opravdu jedná o danou instanci a poté si vrátíme vlastní šablonu. Tímto postupem můžeme zachytávat jakékoliv typy výjimek.