Office week BF - Easter
Tento týden až 80% sleva na e-learning MS Office!
80 % bodů zdarma díky naší Velikonoční akci!

Lekce 7 - Jednoduchý redakční systém v Laravel - Výpis článku

V minulé lekci, Jednoduchý redakční systém v Laravel - Migrace, jsme se věnovali migracím a vytvořili jsme si modelovou vrstvu pro články. Jak jsem slíbil, dnes budeme v PHP Laravel tutoriálu pokračovat v tvorbě kontroleru a zprovozníme si zobrazení článku.

Routování

Začneme nejdříve tím, že si definujeme routy pro články. Otevřeme si soubor routes/web.php a odstraníme výchozí routu pro hlavní stránku, jelikož ji zatím v našem projektu nebudeme potřebovat. Místo ní si definujeme, že námi vytvořený CRUD kontroler má zpracovávat požadavky na články:

use Illuminate\Support\Facades\Route;

Route::resource('article', 'ArticleController');

Metodou resource() jsme definovali routy pro všechny CRUD akce kontroleru. Již víme, že to jsou akce pro přidání, zobrazení, editaci a odstraněnín článku. O výsledku se můžeme přesvědčit příkazem php artisan route:list:

+--------+-----------+----------------------------+-----------------+------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
| Domain | Method    | URI                        | Name            | Action                                                     | Middleware                                                                                                                         |
+--------+-----------+----------------------------+-----------------+------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
|        | POST      | _ignition/execute-solution |                 | Facade\Ignition\Http\Controllers\ExecuteSolutionController | Facade\Ignition\Http\Middleware\IgnitionEnabled,Facade\Ignition\Http\Middleware\IgnitionConfigValueEnabled:enableRunnableSolutions |
|        | GET|HEAD  | _ignition/health-check     |                 | Facade\Ignition\Http\Controllers\HealthCheckController     | Facade\Ignition\Http\Middleware\IgnitionEnabled                                                                                    |
|        | GET|HEAD  | _ignition/scripts/{script} |                 | Facade\Ignition\Http\Controllers\ScriptController          | Facade\Ignition\Http\Middleware\IgnitionEnabled                                                                                    |
|        | POST      | _ignition/share-report     |                 | Facade\Ignition\Http\Controllers\ShareReportController     | Facade\Ignition\Http\Middleware\IgnitionEnabled,Facade\Ignition\Http\Middleware\IgnitionConfigValueEnabled:enableShareButton       |
|        | GET|HEAD  | _ignition/styles/{style}   |                 | Facade\Ignition\Http\Controllers\StyleController           | Facade\Ignition\Http\Middleware\IgnitionEnabled                                                                                    |
|        | GET|HEAD  | api/user                   |                 | Closure                                                    | api,auth:api                                                                                                                       |
|        | GET|HEAD  | article                    | article.index   | App\Http\Controllers\[email protected]               | web                                                                                                                                |
|        | POST      | article                    | article.store   | App\Http\Controllers\[email protected]               | web                                                                                                                                |
|        | GET|HEAD  | article/create             | article.create  | App\Http\Controllers\[email protected]              | web                                                                                                                                |
|        | GET|HEAD  | article/{article}          | article.show    | App\Http\Controllers\[email protected]                | web                                                                                                                                |
|        | PUT|PATCH | article/{article}          | article.update  | App\Http\Controllers\[email protected]              | web                                                                                                                                |
|        | DELETE    | article/{article}          | article.destroy | App\Http\Controllers\[email protected]             | web                                                                                                                                |
|        | GET|HEAD  | article/{article}/edit     | article.edit    | App\Http\Controllers\[email protected]                | web                                                                                                                                |
+--------+-----------+----------------------------+-----------------+------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+

Tabulka výše obsahuje kromě akcí s články i API akci, která je definovaná v souboru routes/api.php, a akce pro debugger. Pro nás se momentálně jedná o nepodstatné routy, proto je budeme ignorovat.

Tabulka rout nám popisuje tyto vlastnosti:

  • Domain - Pro kterou doménu je daná routa určená. Pokud je hodnota prázdná, platí výchozí doména.
  • Method - HTTP metoda akce. Jelikož HTML formuláře nepodporují metody PUT, PATCH ani DELETE, budeme je muset trochu modifikovat. To si ale ukážeme v další lekci.
  • URI - URI akce (v našem případě část v URL adrese za doménou).
  • Name - Název akce, který se používá v kódu pro vytvoření odkazu přes helper funkci route() (například route('article.index') vygeneruje http://localhost:8000/article).
  • Action - Metoda kontroleru zpracovávající danou akci.
  • Middleware - Výpis middlewarů, přes které požadavek projde.

Také si všimněte, že v akcích, jako je například zobrazení, je v URI definovaný parametr {article}. Pokud používáme stejný název parametru jako proměnné v metodě kontroleru, můžeme následně získat instanci článku pouze díky dependency injection, viz dále.

Předpřipravený článek

Do naší tabulky článků si ještě doplníme úvodní článek, abychom měli s čím pracovat, než cokoliv vytvoříme.

Podle oficiálního postupu bychom si měli připravit tzv. seedery. Toho vás chci ale prozatím ušetřit. Místo toho si ukážeme nový Artisan příkaz - tinker. Jedná se o PHP konzoli, přes kterou můžeme provést jakoukoliv operaci a to i s třídami frameworku. Do konzole poté vložíme následující kód, skrz který vytvoříme nový článek:

$article = new App\Article();
$article->title = 'Úvod';
$article->url = 'uvod';
$article->description = 'Úvodní článek na webu v Laravel frameworku.';
$article->content = '<p>Vítejte na našem webu!</p><p>Tento web je postaven na <strong>jednoduchém redakčním systému v Laravel frameworku</strong>. Toto je úvodní článek, načtený z databáze.</p>';
$article->save();
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Nakonec nám metoda save() vrátí boolean hodnotu úspěchu:

Použití PHP konzole v Laravel frameworku pro vytvoření článku

Kontroler

Nyní se přesuneme ke kontroleru. Tam pouze upravíme akci show(), aby nám vracela pohled spolu s daty článku:

/**
 * Načti článek a předej jeho data do šablony.
 *
 * @param  Article $article
 * @return Response
 */
public function show(Article $article)
{
    return view('article.show', ['article' => $article]);
}

Pohledy

Abychom si článek mohli zobrazit, budeme k tomu potřebovat pohled. Předtím, než však začneme nějaký vytvářet, si prosím odstraňte vygenerovaný pohled resources/views/welcome.blade.php, my ho totiž potřebovat nebudeme :)

Šablona webu

Začneme úpravou celkového vzhledu naší aplikace. Ten bude zajišťovat hlavní pohled base.blade.php:

<!DOCTYPE html>
<html lang="cs-CZ">
    <head>
        <meta charset="utf-8" />
        <meta name="csrf-token" content="{{ csrf_token() }}" />
        <meta name="description" content="@yield('description')" />
        <title>@yield('title', env('APP_NAME'))</title>

        <link href="{{ asset('css/app.css') }}" rel="stylesheet" />

        <script src="{{ asset('js/app.js') }}"></script>
    </head>
    <body>
        <div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
            <h5 class="my-0 mr-md-auto font-weight-normal">{{ env('APP_NAME') }}</h5>
            <nav class="my-2 my-md-0 mr-md-3">
                <a class="p-2 text-dark" href="#">Hlavní stránka</a>
                <a class="p-2 text-dark" href="#">Seznam článků</a>
                <a class="p-2 text-dark" href="#">Kontakt</a>
            </nav>
        </div>

        <div class="container">
            @if ($errors->any())
                <div class="alert alert-danger mb-4">
                    <ul class="mb-0">
                        @foreach ($errors->all() as $error)
                            <li>{{ $error }}</li>
                        @endforeach
                    </ul>
                </div>
            @endif

            @yield('content')

            <footer class="pt-4 my-md-5 border-top">
                <p>
                    Ukázkový tutoriál pro jednoduchý redakční systém v Laravel frameworku z programátorské sociální sítě
                    <a href="http://www.itnetwork.cz" target="_blank">itnetwork.cz</a>
                </p>
            </footer>
        </div>

        @stack('scripts')
    </body>
</html>

V lekci Jednoduchý redakční systém v Laravel - Struktura projektu jsme si do projektu naimportovali CSS framework Bootstrap. Toho jsem využil při tvorbě této šablony, kdy jsem si stáhl jeden z jejich příkladů a trochu ho upravil, aby naše stránka alespoň trochu vypadala k světu :)

Na pohledu výše si také všimněte těchto Blade direktiv:

  • @yield('hodnota') - Očekává se předání jedné hodnoty z pohledu, který dědí tento pohled. Do hlavní šablony se nám tak např. předá titulek z šablony aktuální podstránky. Můžeme definovat i výchozí hodnotu, toho využíváme zrovna u titulku stránky. Hodnota bloku se přiřazuje Blade direktivami @section (popř. @endsection).
  • @stack - Jedná se o kolekci zásobník na rozdíl od @yield. To se nám hodí pro přidávání skriptů, jelikož je můžeme předávat ve více pohledech pro jednu stránku. Do zásobníku se přidávají hodnoty pomocí Blade direktiv @push (popř. @endpush)

Zobrazení článku

V pohledu pro zobrazení článku, který si vytvoříme ve složce resources/views/article s názvem show.blade.php, budeme dědit naší hlavní šablonu a následně využijeme bloků, které jsme si definovali:

@extends('base')

@section('title', $article->title)
@section('description', $article->description)

@section('content')
    <h1>{{ $article->title }}</h1>
    {!! $article->content !!}
@endsection

Jelikož framework nás chrání před XSS útokem pomocí escapování vypsaného textu, musíme pro výpis obsahu článku použít {!! !!} namísto {{ }}. Obsahuje totiž i HTML kód.

Pokud si však nyní zkusíme zobrazit náš úvodní článek přes stránku webu /article/uvod, dostaneme chybu 404 i přes to, že vše vypadá funkčně. Kde je tedy chyba?

Definování atributu pro parametr routy

Laravel ve výchozím nastavení získává data z databáze pomocí jejich ID. Pro zobrazení úvodního článku bychom museli použít adresu /article/1. Jedná se však o nechtěné chování aplikace, jelikož každý náš článek má svojí unikátní slovní URL a toho chceme využít.

Aby se aplikovala hodnota url článku v routách používající model Article (parametr {article}), budeme muset v našem modelu přepsat obsah metody getRouteKeyName(), která se dědí z třídy Model:

/**
 * Vrať název atributu, podle kterého se získává článek z parametru routy.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'url';
}

Nyní při navštívení stránky /article/uvod uvidíme náš úvodní článek:

Zobrazení úvodního článku v PHP frameworku Laravel

Úplný základ článků máme zprovozněný. V příští lekci, Jednoduchý redakční systém v Laravel - Tvorba článků, půjdeme zase o něco hlouběji. Podíváme se totiž na vytváření článků a zobrazení jejich seznamu v administraci.


 

Stáhnout

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

 

 

Článek pro vás napsal Jan Lupčík
Avatar
Jak se ti líbí článek?
5 hlasů
Autor se primárně věnuje vývoji webových stránek a aplikacích v PHP (speciálně ve frameworku Laravel) a je jedním z vývojářů komunitního módu TruckersMP.
Předchozí článek
Jednoduchý redakční systém v Laravel - Migrace
Všechny články v sekci
Laravel framework pro PHP
Miniatura
Následující článek
Jednoduchý redakční systém v Laravel - Tvorba článků
Aktivity (10)

 

 

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

Avatar
Jiří Hruška:13.6.2019 16:41

Děkuji, konečně jsem pochopil, jak v laravelu do sebe zapadá celá MVC architektura. Skvělé články!

 
Odpovědět
13.6.2019 16:41
Avatar
Ladislav Sviták:21.11.2019 21:06

Můj projekt i stažený " Stáhnout lekce-7.zip" mi ve webovém prohlížeči vyhazují chybu 404.
Projekt vytvořený pomocí
https://laravel.com/docs/6.x#…
funguje v pořádku.
Kde mám hledat chybu?

 
Odpovědět
21.11.2019 21:06
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na Ladislav Sviták
Jan Lupčík:22.11.2019 9:59

Hlavní stránka ještě není vyřešená, jak můžeš vidět v routovací tabulce na začátku této lekce. Hlavní stránka jako celkem se řeší až později v seriálu, přesněji v lekci Jednoduchý redakční systém v Laravel - Práce s datem.

Odpovědět
22.11.2019 9:59
TruckersMP vývojář
Avatar
Ondra
Člen
Avatar
Ondra:18. ledna 22:36

všechno mě funguje krom stylu. Kontroloval jsem to s originálem v vše je stejné ale styly se nenačtou kde je chyba?

 
Odpovědět
18. ledna 22:36
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na Ondra
Jan Lupčík:19. ledna 19:54

Ahoj, v návodu (i v přiložených souborech) vše funguje. Nezapomněl jsi zkompilovat assety? Pokud ne, použij příkaz npm run dev v kořenové složce projektu.
Více informací můžeš najít v 5. lekci.

Editováno 19. ledna 19:55
Odpovědět
19. ledna 19:54
TruckersMP vývojář
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Ondra
Člen
Avatar
Odpovídá na Jan Lupčík
Ondra:19. ledna 20:27

Dobrý už to funguje chyba byla že jsem neměl v projektu nainstalováno npm install a poté npm run dev díky za radu

 
Odpovědět
19. ledna 20:27
Avatar
bhm81
Člen
Avatar
bhm81:30. března 19:18

Ahoj, měl bych takový zvláštní dotaz. Vzhledem k tomu, že přes artisan vytvořím "Article" model, "ArticleController" kontroler, tak mám i v routu/url řádku "/article/uvod", který se generuje automaticky. Ale co když bych tam chtěl mít "/clanky/uvod". Lze to nějakou funkcí přejmenovat? Nechci vytvářet třídy v češtině jako "ClankyController", to mi přijde trochu úchylný... Díky za radu...

 
Odpovědět
30. března 19:18
Avatar
Odpovídá na bhm81
Martin Kašpar:31. března 9:33

Ahoj, vyzkoušej následující úpravu routy:

Route::resource('clanek', 'ArticleController', ['names' => 'article', 'parameters' => ['clanek' => 'article']]);

Výpis originálních a upravených rout.

# artisan route:list před úpravou
GET|HEAD  | article                | article.index   | App\Http\Controllers\[email protected]
POST      | article                | article.store   | App\Http\Controllers\[email protected]
GET|HEAD  | article/create         | article.create  | App\Http\Controllers\[email protected]
GET|HEAD  | article/{article}      | article.show    | App\Http\Controllers\[email protected]
PUT|PATCH | article/{article}      | article.update  | App\Http\Controllers\[email protected]
DELETE    | article/{article}      | article.destroy | App\Http\Controllers\[email protected]
GET|HEAD  | article/{article}/edit | article.edit    | App\Http\Controllers\[email protected]

# artisan route:list po úpravě
GET|HEAD  | clanek                 | article.index   | App\Http\Controllers\[email protected]
POST      | clanek                 | article.store   | App\Http\Controllers\[email protected]
GET|HEAD  | clanek/create          | article.create  | App\Http\Controllers\[email protected]
GET|HEAD  | clanek/{article}       | article.show    | App\Http\Controllers\[email protected]
PUT|PATCH | clanek/{article}       | article.update  | App\Http\Controllers\[email protected]
DELETE    | clanek/{article}       | article.destroy | App\Http\Controllers\[email protected]
GET|HEAD  | clanek/{article}/edit  | article.edit    | App\Http\Controllers\[email protected]

Dál za nastavení rout jsem to nezkoušel, tak nemusí jít na sto procent o všechny potřebné úpravy.

 
Odpovědět
31. března 9:33
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na bhm81
Jan Lupčík:31. března 18:33

Omlouvám se, ale včera už jsem se k odpovědi nedostal.
Úprava od Martin Kašpar je správná a děkuji mu za odpověď. Každopádně rád bych jeho úpravy trochu okomentoval.

Metoda resource() třídy Route přijímá tři parametry. První parametr určuje název v URI akci, název samotné routy a i pojmenování parametru. V druhém parametru specifikuješ kontroler, který má dané routy obsluhovat. Musí obsahovat všechny CRUD metody zmíněné v předchozí lekci :)
Třetí parametr přijímá pole nastavení, kde můžeš přepsat jak název routy (klíč names), tak i jméno parametru (klíč parameters). U parametru musíme převést clanek na article, jelikož clanek je vygenerovaný právě podle prvního parametru a náš kód kontroleru využívá proměnnou s názvem article - ty se musí shodovat, aby dependency injection správně fungovalo.

Odpovědět
31. března 18:33
TruckersMP vývojář
Avatar
bhm81
Člen
Avatar
bhm81:1. dubna 18:09

Díky moc za odpovědi... funguje to skvěle...

 
Odpovědět
1. dubna 18:09
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 15. Zobrazit vše