Lekce 9 - Jednoduchý redakční systém v Laravel - Správa článků
V minulé lekci, Jednoduchý redakční systém v Laravel - Tvorba článků, jsme začali s tvorbou administrace pro jednoduchý redakční systém v Laravel frameworku. Vytvořili jsme si seznam článků a editor pro jejich tvorbu.
V dnešním tutoriálu se podíváme na správu článků a povíme si něco o třídách HTTP požadavků.
HTTP požadavky
Předtím, než se vrhneme na vytváření nových částí aplikace, se
zpětně podíváme na naší metodu store()
v kontroleru
ArticleController.php
, kterou jsme definovali v minulé lekci. Jak
už název napovídá, tato metoda by měla sloužit pro vkládání nového
záznamu (v našem případě článku) do databáze. Mimo jiné ale obsahuje
také validaci přijatých dat, což v případě větších formulářů
nemusí být zrovna praktické. Proto si představíme tzv. Request
třídy.
Request třídy
Request
třídy kontrolují, zdali je uživatel oprávněný pro
odeslání daného požadavku, a validují odeslaná data. Můžeme tak
přesunout sadu pravidel daného HTTP požadavku právě do nich a metoda
kontroleru bude poté obsahovat pouze logiku akce. Pojďme si nyní takovou
třídu vytvořit.
Pro akci store()
si vygenerujeme třídu
StoreRequest
pomocí Artisan příkazu make:request
,
který nepotřebuje žádné speciální možnosti:
php artisan make:request Article/StoreRequest
Jelikož tříd požadavků můžeme mít pro jeden kontroler více, je dobrým zvykem vytvářet pro každý kontroler vlastní složku.
Vytvořila se nám automaticky nová složka app/Http/Requests/
následně s námi definovanou podsložkou Article/
. V ní najdeme
vygenerovaný soubor StoreRequest.php
, jehož obsah je
následující:
<?php namespace App\Http\Requests\Article; use Illuminate\Foundation\Http\FormRequest; class StoreRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return false; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ // ]; } }
Nově vygenerovaná třída StoreRequest
dědící třídu
frameworku FormRequest
obsahuje pouze tyto dvě metody:
authorize()
- Určuje, zdali je uživatel oprávněný pro odeslání požadavku. Jedná se o jedno z míst, kam můžeme toto ověření umístit. Dalším z nich může být například middleware, to si však ukážeme až v dalších lekcích.rules()
- Vrací pole s nastavenými validačními pravidly.
Jelikož se oprávněními (a uživateli) zatím nezabýváme, můžeme
metodu authorize()
kompletně odstranit. Pokud totiž není
definovaná, automaticky se toto ověření považuje za úspěšné. Co už
nás ale zajímá více, je právě metoda rules()
, kterou
naplníme pravidly z metody store()
našeho kontroleru. Bude tedy
vypadat následovně:
/** * Vrať validační pravidla pro formulář, který má na starosti tvorbu článků. * * @return array */ public function rules(): array { return [ 'title' => ['required', 'min:3', 'max:80'], 'url' => ['required', 'min:3', 'max:80', 'unique:articles,url'], 'description' => ['required', 'min:25', 'max:255'], 'content' => ['required', 'min:50'], ]; }
Následně můžeme validaci z metody store()
kompletně
odstranit. Upravíme však typ objektu proměnné $request
na
naší Request
třídu místo té obecné, aby se následně
aplikovala i definovaná pravidla:
/** * Zvaliduj odeslaná data přes formulář a vytvoř nový článek. * * @param StoreRequest $request * @return RedirectResponse */ public function store(StoreRequest $request): RedirectResponse { Article::create($request->all()); return redirect()->route('article.index'); }
Nezapomeneme samozřejmě importovat naší novou třídu:
use App\Http\Requests\Article\StoreRequest;
Z metody, která na začátku měla 26 řádků včetně dokumentace, jsme
následně vytvořili metodu s pouhými 12 řádky a to jsme zachovali naprosto
stejnou funkčnost! Jen si teď zkuste vytvořit nějaký článek a ignorovat
některé z validačních pravidel. Třída HTTP požadavku vás nepustí dále
Editace článků
Pojďme se nyní přesunout k editaci článku.
Akce edit() a update()
Pohled s formulářem pro jeho úpravu budeme vracet v metodě
edit()
:
/** * Zobraz formulář pro editaci článku a předej danému pohledu načtený článek. * * @param Article $article * @return View */ public function edit(Article $article): View { return view('article.edit', ['article' => $article]); }
Samotná úprava záznamu bude probíhat v metodě update()
:
/** * Zvaliduj odeslaná data přes formulář a uprav načtený článek. * * @param UpdateRequest $request * @param Article $article * @return RedirectResponse */ public function update(UpdateRequest $request, Article $article) { $article->update($request->all()); return redirect()->route('article.index'); }
Stejně jako u akce store()
, i zde předáme Eloquent metodě
pouze pole dat z formuláře, v tomto případě metodě update()
,
a následně přesměrujeme uživatele do administrace článků.
UpdateRequest
Pro validaci dat opět používáme vlastní Request
třídu s
názvem UpdateRequest
, kterou si nyní vygenerujeme ve složce
app/Http/Requests/Article/
pomocí již zmíněného Artisan
příkazu:
php artisan make:request Article/UpdateRequest
Tuto vygenerovanou třídu si ihned upravíme. Odstraníme metodu
authorize()
a definujeme si validační pravidla v metodě
rules()
:
<?php namespace App\Http\Requests\Article; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class UpdateRequest extends FormRequest { /** * Vrať validační pravidla pro formulář, který má na starosti editaci článků. * * @return array */ public function rules(): array { return [ 'title' => ['required', 'min:3', 'max:80'], 'url' => [ 'required', 'min:3', 'max:80', Rule::unique('articles', 'url')->ignore($this->route('article')->id), ], 'description' => ['required', 'min:25', 'max:255'], 'content' => ['required', 'min:50'], ]; } }
Pro editaci článku se validační pravidla stala trochu složitějšími.
Pro validační pravidlo unique
musíme definovat výjimku
aktuálního záznamu. Kdybychom ji totiž nedefinovali a chtěli pozměnit
článek bez modifikace jeho URL, validace by nám následně vyhodila chybu,
že v databázi již existuje článek s danou URL adresou, i když se jedná o
právě editovaný článek.
Tuto výjimku nastavujeme skrz metodu ignore()
builderu
Unique
, která přijímá ID záznamu. Také si povšimněte
další výhody parametrů fungujících přes dependency injection (tzv. route model
binding). Instanci modelu článku můžeme lehce získat pomocí metody
route()
třídy frameworku FormRequest
, kdy předáme
název parametru definovaného v routovacím souboru a nemusíme tento záznam
složitě vybírat z databáze pouze přes předaný identifikátor (v našem
případě URL článku).
Nakonec přidáme do našeho kontroleru ArticleController
import
této nové třídy:
use App\Http\Requests\Article\UpdateRequest;
Pohled
Nyní si vytvoříme pohled s názvem edit.blade.php
ve složce
resources/views/article/
, který je téměř totožný s pohledem
create.blade.php
:
@extends('base') @section('title', 'Editace článku ' . $article->title) @section('description', 'Editor pro editaci článků.') @section('content') <h1>Editace článku {{ $article->title }}</h1> <form action="{{ route('article.update', ['article' => $article]) }}" method="POST"> @csrf @method('PUT') <div class="form-group"> <label for="title">Nadpis</label> <input type="text" name="title" id="title" class="form-control" value="{{ old('title') ?: $article->title }}" required minlength="3" maxlength="80" /> </div> <div class="form-group"> <label for="url">URL</label> <input type="text" name="url" id="url" class="form-control" value="{{ old('url') ?: $article->url }}" required minlength="3" maxlength="80" /> </div> <div class="form-group"> <label for="description">Popisek článku</label> <textarea name="description" id="description" rows="4" class="form-control" required minlength="25" maxlength="255">{{ old('description') ?: $article->description }}</textarea> </div> <div class="form-group"> <label for="content">Obsah článku</label> <textarea name="content" id="content" class="form-control" rows="8">{{ old('content') ?: $article->content }}</textarea> </div> <button type="submit" class="btn btn-primary">Uložit článek</button> </form> @endsection @push('scripts') <script type="text/javascript" src="{{ asset('//cdn.tinymce.com/4/tinymce.min.js') }}"></script> <script type="text/javascript"> tinymce.init({ selector: '#content', plugins: [ 'advlist autolink lists link image charmap print preview anchor', 'searchreplace visualblocks code fullscreen', 'insertdatetime media table contextmenu paste' ], toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image', entities: '160,nbsp', entity_encoding: 'raw', }); </script> @endpush
Jelikož HTTP akce store()
je typu
PUT
, musíme ve formuláři opět použít Blade direktivu
@method
.
Pokud nyní vyzkoušíme upravit některý z existujících článků, vše
proběhne naprosto v pořádku. Za pozornost ještě stojí datum poslední
změny v seznamu článků, jenž se automaticky aktualizuje při jakékoliv
změně daného záznamu. Jen si to sami vyzkoušejte
Odstraňování článků
Poslední část administrace, která nám chybí, je odstraňování
článků. Jelikož formulář pro tuto akci už máme vytvořený v seznamu
článků a věnovali jsme se mu minulou lekci, stačí nám teď pouze upravit
akci destroy()
v našem kontroleru:
/** * Odstraň článek z databáze. * * @param Article $article * @return RedirectResponse */ public function destroy(Article $article): RedirectResponse { try { $article->delete(); } catch (\Exception $exception) { return redirect()->back()->withErrors(['Při procesu odstranění článku došlo k chybě.']); } return redirect()->route('article.index'); }
K odstranění záznamu používáme Eloquent metodu delete()
,
ve které však může dojít k výjimce. Tu musíme ošetřit, aby se
uživateli nezobrazila stránka s chybou 500. Přesměrujeme ho tedy zpátky (na
to používáme metodu back()
builder funkce
redirect()
) a dáme mu vědět, že proces odstranění se
nepodařil.
Tímto jsme dokončili vzhlednou a plně fungující administraci. Pokud se vám něco nepodařilo, můžete si stáhnout projekt z přiloženého archivu níže. V opačném případě výsledek našeho snažení můžeme shrnout tímto obrázkem:

V následujícím cvičení, Řešené úlohy k 5.-9. lekci frameworku Laravel pro PHP, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 180x (46.79 MB)
Aplikace je včetně zdrojových kódů v jazyce PHP