Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij podzimní akce 30% výuky zdarma!
Pouze tento týden sleva až 80 % na e-learning týkající se JavaScript
JavaScript týden

Lekce 4 - Dokončení kalkulačky v Laravel

V minulé lekci, První aplikace v Laravel, jsme rozpracovali jednoduchou kalkulačku v Laravel. Vytvořili jsme si model, kontroler a pohled.

V dnešním kurzu si propojíme jednotlivé části naší aplikace a podíváme se také na validaci formuláře.

Routování

Abychom se mohli podívat, jak naše aplikace aktuálně vypadá, potřebujeme ke kontroleru přistoupit přes nějakou URL adresu. Na to nám slouží routování, jeho proces jsme si popsali v úvodní lekci. Pojďme si nyní definovat naší první routu, která kontroler napojí na nějakou adresu.

Definované routy pro náš web najdeme v souboru routes/web.php. Tento soubor je od instalace nezměněný:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Zatím máme jako výchozí definovanou pouze jednu routu. Jedná se o zobrazení hlavní stránky přes GET (statická metoda get() třídy Route) a zpracovává se anonymní funkcí. Takto můžeme zpracovávat jakoukoliv routu. My jsme si již vytvořili kontroler a ten také teď využijeme. Na konec souboru přidáme vlastní definování GET routy, kde místo vytvoření funkce odkážeme na akci našeho kontroleru:

Route::get('calculator', '[email protected]');

Nyní pokud zadáme do URL naší aplikace /calculator, uvidíme následující kalkulačku:

Kalkulačka v PHP frameworku Laravel

Je na čase si kalkulačku zprovoznit. Vrátíme se tedy ke kontroleru, kde zpracujeme POST formulář.

Zpracování odeslání formuláře

V našem kontroleru CalculatorController si definujeme novou metodu, kterou pojmenujeme calculate(). Ta nám bude přijímat požadavky z formuláře a následně zobrazovat výsledek:

/**
 * Zpracuj požadavek formuláře a zobraz výsledek spolu s formulářem kalkulačky.
 *
 * @param  Calculator $calculator
 * @return View
 */
public function calculate(Calculator $calculator): View
{
    $a = request()->input('a');
    $b = request()->input('b');
    $operation = request()->input('operation');
    $result = $calculator->calculate($operation, $a, $b);

    return view('calculator', [
        'operations' => $calculator->getOperations(),
        'result' => $result,
        'a' => $a,
        'b' => $b,
    ]);
}

Stejně jako u zobrazení kalkulačky, i zde získáváme instanci modelu Calculator do proměnné $calculator přes dependency injection. Ta zajímavá část ale začíná až uvnitř metody.

Pro získání odeslaných hodnot používáme metodu input() Laravel třídy Request, kterou získáme pomocí helper funkce request(). Následně získané hodnoty použijeme pro naší metodu calculate(), kterou jsme si definovali v minulé lekci v modelu Calculator. A dále zobrazíme pohled calculator.blade.php přes helper funkci view() stejně jako v metodě index(). Pohledu opět předáme dostupné operace kalkulačky, navrch jsme však přidali výsledek a odeslaná čísla přes formulář, abychom je opět mohli zobrazit.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Následně si vytvoříme novou routu v routovacím souboru webu routes/web.php stejně jako jsme to udělali výše. Nyní si však přidáme POST akci:

Route::post('calculator', '[email protected]');

Všimli jste si, že jsme definovali dvě routy se stejným názvem, ale jedna je GET a druhá POST? I přesto bude naše kalkulačka bez problému fungovat. Framework si sám zjistí, o jaký požadavek se jedná, a následně zavolá danou metodu kontroleru:

  • Pro zobrazení (GET) se tedy zavolá metoda index() v kontroleru CalculatorController.
  • Po odeslání formuláře (POST) se zavolá calculate() ve stejném kontroleru.

Pokud však zkusíme nyní formulář odeslat, dostaneme chybu 419 i přesto, že vše by mělo fungovat. Nebo ne?

CSRF token

Laravel chrání naše požadavky proti CSRF útoku. Tato ochrana je spuštěna pro všechny akce, které nejsou čtecí (všechny krom GET). A co že je vlastně ten CSRF útok?

Představte si situaci, kdy jsme vytvořili nějaký populární blog a někdo by vytvořil úplně jinou stránku, kam by dal formulář vybízející ke vkládání vulgárních příspěvků. Tento formulář by ovšem nenechal odesílat data na jeho stránku, nýbrž na náš blog. Nic netušící uživatelé by rázem psali příspěvky na náš blog, i když by se na této stránce vůbec nenacházeli a nevěděli, že tam něco posílají.

Musíme formulář tedy opatřit CSRF tokenem, pomocí kterého se ověřuje, že požadavek byl odeslán přes naší stránku a ne přes stránku cizí.

To se dělá pomocí Blade direktivy @csrf, která se přemění na {{ csrf_field() }} (tento delší zápis se používal ve starších verzích). Direktivou bude formuláři vygenerováno skryté pole s CSRF tokenem. Upravíme si tedy formulář v pohledu calculator.blade.php (ve složce resources/views):

<form method="POST" action="/calculator">
    @csrf

    Operace:

Pokud nyní zkusíme odeslat formulář, bude už vše fungovat tak, jak bychom si představovali.

CSRF ochrana pomocí middleware

CSRF ochrana je zajištěna jedním z middlewarů Laravel frameworku. To je vrstva, kterou se požadavek zpracuje ještě předtím, než se dostane ke kontroleru. Takovéto middlewary zpracovávající všechny akce najdeme definované v souboru app/Http/Kernel.php. Máme jich hned několik pro skupinu web:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

Přes tyto všechny middlewary projde náš požadavek, než se dostane k metodě našeho kontroleru. Můžeme vidět, že dalšími z nich jsou například šifrování cookies a vytvoření relace (session). Pokud někdy budete chtít vytvářet svůj vlastní middleware, toto je přesně místo, kde ho budete přidávat. Následně tak bude aplikován pro všechny akce na vaší webové stránce.

Validace formuláře

Jako programátor musíme předpokládat, že ne vždy uživatel vyplní do políčka to, co po něm požadujeme. Pokud zkusíme zadat do políčka s číslem text, naše aplikace vyvolá chybu, protože model dokáže přijímat pouze celá čísla:

Chyba Laravel kalkulačky při předání textu

Tomu se můžeme vyhnout validací. Validační pravidla lze definovat v kontroleru přímo v metodě dané akce. My využijeme pouze pár pravidel, všechny lze najít v oficiální dokumentaci. V našem případě se jedná o to, že všechna políčka musí být vyplněná a že požadujeme pouze celá čísla. Také vybraná operace musí být podporovaná naším modelem. Upravíme si tedy metodu calculate() v našem kontroleru:

/**
 * Zpracuj požadavek formuláře a zobraz výsledek spolu s formulářem kalkulačky.
 *
 * @param  Calculator $calculator
 * @return View
 * @throws ValidationException
 */
public function calculate(Calculator $calculator): View
{
    $this->validate(request(), [
        'a' => ['required', 'integer'],
        'b' => ['required', 'integer', 'not_in:0'],
        'operation' => [
            'required',
            Rule::in(array_keys($calculator->getOperations())),
        ],
    ]);

    $a = request()->input('a');

Začneme od anotace, kdy místo zpracování výjimky ValidationException ji předáme frameworku. Ten se o ní sám dokáže postarat, kdy uživatele přesměruje zpět i s chybami, kterých se dopustil.

Následně voláme metodu validate(), která je definovaná v třídě Controller a náš kontroler ji dědí. Té musíme předat instanci třídy Request, již lze získat opět přes helper funkci request(). Jako druhý parametr předáváme pole s nastavenými validačními pravidly. Ty mohou být definované pouze jako text. Pro jiné, jako například pravidlo in, je lepší použít třídu Rule. Také si všimněte, že jsme vyřešili problém pro dělení nulou, kdy druhé číslo nesmí být 0.

Myslím si, že další pravidla není třeba vysvětlovat, všechny jsou popsané v uvedené dokumentaci.

Pokud vaše prostředí nedokáže automaticky rozpoznat třídy z jiného jmenného prostoru, nezapomeňte si na začátek souboru třídy kontroleru přidat následující importy:

use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

Vypsání chyb

Nyní už stačí jen vypsat chyby v našem pohledu, abychom informovali uživatele o omylech, kterých se dopustil. Chyby jsou obsažené v proměnné $errors, ta je automaticky předávaná všem pohledům. Takovýchto "nedefinovaných" proměnných je více, nám však stačí zatím pouze tato. Upravíme si tedy náš pohled a pod nadpis přidáme výpis chyb:

<h1>Kalkulačka</h1>

@if ($errors->any())
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

<form method="POST" action="/calculator">

$errors je instance třídy ViewErrorBag. Pro zjištění, zda-li vůbec existují nějaké chybové hlášky, abychom nezobrazovali prázdný seznam, použijeme metodu any(). Všechny chybové hlášky poté získáme přes metodu all() a vypíšeme je. Pokud byste však chtěli získat chybovou hlášku pouze pro určité políčko, lze použít metodu first() a předat ji název políčka:

$errors->first('email')

Nám každopádně postačí i pouze seznam chyb :)

Pokud zkusíme zadat jako druhé číslo nulu a přes "Inspect element" (klávesa F12 v prohlížeči) vytvoříme neexistující operaci kalkulačky, dostaneme dvě chybové hlášky:

Chybové hlášky v PHP frameworku Laravel

Nyní máme plně fungující kalkulačku vytvořenou přes Laravel, na které jsme si ukázali naprosté základy tohoto PHP frameworku. Pokud vám není cokoliv jasné, stáhněte si projekt z přiloženého archivu a podívejte se na řešení. Můžete se též zeptat v diskuzi pod článkem, pokud-li čelíte nějakému problému. Každopádně s potřebnými znalostmi, které jsem uvedl v první lekci, by vše mělo být po chvilce jasné.

V příští lekci, Jednoduchý redakční systém v Laravel - Struktura projektu, se vrhneme na nový projekt, kde se podíváme na některé části frameworku více do hloubky.


 

Stáhnout

Staženo 115x (12.61 MB)
Aplikace je včetně zdrojových kódů v jazyce php

 

Předchozí článek
První aplikace v Laravel
Všechny články v sekci
Laravel framework pro PHP
Článek pro vás napsal Jan Lupčík
Avatar
Jak se ti líbí článek?
9 hlasů
Autor se primárně věnuje vývoji webových stránek a aplikacích v PHP (framework Laravel) a je jedním z herních vývojářů komunitní modifikace TruckersMP.
Aktivity (15)

 

 

Komentáře
Zobrazit starší komentáře (4)

Avatar
Josef Prause
Člen
Avatar
Josef Prause:4.6.2019 18:31

Nazdar,
omlouvám se, ale to už nebudeme zkoumat. Přeinstaloval jsem projekt first-application a vše funguje jak má. Možná jsem omylem zasáhl nesprávně do nějakého souboru.
Děkuji za odpovědi a za celý článek o vývoji aplikace, hodně jsem se dozvěděl. Také při tom zkouším PhpStorm, dosud používám Netbeans.

 
Odpovědět
4.6.2019 18:31
Avatar
Jan Štěch
Super redaktor
Avatar
Jan Štěch:8. června 20:18

Nevím proč, ale když do toho pohledu napíšu @csrf, tak se to normálně vypíše do stránky jako běžný text. Musel jsem použít ten starší zápis {{ csrf_field() }}. Někdo nějaký nápad, proč mi to nefunguje? :-?

 
Odpovědět
8. června 20:18
Avatar
Jan Lupčík
Super redaktor
Avatar
Odpovídá na Jan Štěch
Jan Lupčík:8. června 23:28

Co máš za verzi frameworku? Můžeš zjistit přes příkaz php artisan --version.
Taky záleží, jestli máš hned něco za tím zápisem. Pošli kus toho pohledu.

Odpovědět
8. června 23:28
TruckersMP vývojář
Avatar
Jan Štěch
Super redaktor
Avatar
Odpovídá na Jan Lupčík
Jan Štěch:9. června 9:42

Verzi mi to hlásí 5.4.36
V pohledu mám toto:

<form method="POST" action="/calculator">
        @csrf

        Operace:
 
Odpovědět
9. června 9:42
Avatar
Jan Lupčík
Super redaktor
Avatar
Odpovídá na Jan Štěch
Jan Lupčík:9. června 15:52

V dané verzi @csrf ještě neexistovalo. Daná direktiva byla zavedena snad až ve verzi 5.5.x.

Odpovědět
9. června 15:52
TruckersMP vývojář
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jan Štěch
Super redaktor
Avatar
Odpovídá na Jan Lupčík
Jan Štěch:9. června 16:05

Aha, jak to, že ale mám tuhle starší verzi? Laravel jsem instaloval před composer přesně podle návodu v druhém díle. Jak si to můžu aktualizovat?

 
Odpovědět
9. června 16:05
Avatar
Jan Lupčík
Super redaktor
Avatar
Odpovídá na Jan Štěch
Jan Lupčík:9. června 19:37

Nevím, co přesně jsi zadával do terminálu/konzolové řádky. Právě jsem si sám zkusil nainstalovat Laravel a hodilo mi to tu nejnovější verzi; 7.12.0. Můžeš to zkusit znova? Popřípadě můžeš vyzkoušet instalaci skrze PhpStorm. A nebo to lze jednoduše nainstalovat i přes klonování Github repositáře.

Odpovědět
9. června 19:37
TruckersMP vývojář
Avatar
Jan Štěch
Super redaktor
Avatar
Odpovídá na Jan Lupčík
Jan Štěch:10. června 18:01

Zvláštní, instaloval jsem to teď přes composer znova, mám i pocit že stejně jako poprvé (i když očividně ne :-D ) a teď už mám verzi 7.15.0. Díky za radu. :-)

 
Odpovědět
10. června 18:01
Avatar
Jiří Fanta
Člen
Avatar
Jiří Fanta:21. září 18:22

Ahoj, mam takový problém. Nejde mi spustit pohled té kalkulačky. Hází mi to vyjímku, že CalculatorCon­troller neexistuje. Posílám screen

 
Odpovědět
21. září 18:22
Avatar
Jan Lupčík
Super redaktor
Avatar
Odpovídá na Jiří Fanta
Jan Lupčík:22. září 10:01

Opět je tohle bohužel změna v nové verzi frameworku Laravel. Routování se trochu změnilo (soubor routes/web.php), mělo by vypadat následovně:

use App\Http\Controllers\CalculatorController;

Route::get('calculator', [CalculatorController::class, 'index']);
Route::post('calculator', [CalculatorController::class, 'calculate']);
Odpovědět
22. září 10:01
TruckersMP vývojář
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 14. Zobrazit vše