Lekce 11 - Jednoduchý redakční systém v Laravel - Práce s datem
V minulé lekci, Jednoduchý redakční systém v Laravel - Laravel Mix, jsme se věnovali zejména front-end části
našeho projektu. Přidali jsme si také Font Awesome
Tentokrát si vysvětlíme práci s datem a následně se přesuneme na vyvíjení back-endu. Vytvoříme si totiž hlavní stránku.
Práce s datem
Určitě jste si už všimli, že data v naší aplikaci se vypisují ve
výchozí podobě z databáze a to ve formátu Y-m-d H:i:s
. Jedná
se však o něco, co opravdu mít nechceme, jelikož to není zrovna intuitivní
pro uživatele. Navíc se data ukládají v UTC, i když je celá naše aplikace
v češtině (až na výjimky, tj. chybové hlášky knihoven či frameworku a
URL adresy). Časové pásmo by tedy též mělo být nejlépe
lokalizované.
V čistém PHP bychom vždy museli volat funkci date()
a sami
nastavovat formát času. V lepším případě bychom na to použili knihovnu.
O to se však už postaral někdo za nás, jelikož Laravel ve výchozím
nastavení používá knihovnu Carbon. Tato knihovna obsahuje
mnoho užitečných metod a i překlady pro nespočet jazyků. Pokud vás
zajímá více, zavítejte na oficiální
stránky knihovny Carbon.
Nastavení lokalizace aplikace
Carbon si získává hodnoty pro nastavení z konfiguračního souboru
aplikace, který je, jak již zřejmě tušíte, ve složce
config/
, přesněji v souboru app.php
. Nás v tomto
případě zajímají tyto hodnoty:
timezone
- Definuje časové pásmo pro naší aplikaci. Výchozí hodnota jeUTC
. Pro střední Evropu bychom klidně mohli použítCET
(Central European Time), zde však bohužel nastává problém s letním časem. Proto využijeme možnosti definovat kontinent s městem, v našem případěEurope/Prague
, což vyřeší tento problém za nás.locale
- Zkratka pro jazyk, který má naše aplikace používat. Výchozí hodnota jeen
. My si však nastavímecs
, čímž změníme nejen konfiguraci jazyka pro samotný framework, ale i pro danou knihovnu. Pokud nelze najít frázi pro daný jazyk, použije se výchozí. Záložní jazyk je definovaný konfigurační hodnotoufallback_locale
. Tato hodnota je jako výchozí nastavená na angličtinu (en
).
Změny v souboru vypadají takto:
/* |-------------------------------------------------------------------------- | Application Timezone |-------------------------------------------------------------------------- | | Here you may specify the default timezone for your application, which | will be used by the PHP date and date-time functions. We have gone | ahead and set this to a sensible default for you out of the box. | */ 'timezone' => 'Europe/Prague', /* |-------------------------------------------------------------------------- | Application Locale Configuration |-------------------------------------------------------------------------- | | The application locale determines the default locale that will be used | by the translation service provider. You are free to set this value | to any of the locales which will be supported by the application. | */ 'locale' => 'cs',
Nyní se již změny aplikují na naší aplikaci. Pokud si totiž zkusíme editovat článek, uvidíme, že datum poslední změny sedí i s lokálním časem. Co ale zatím nesedí, je výpis data, jelikož stále využívá výchozí formát. Pojďme to napravit.
Pokud se tyto změny neprojevily na vaší aplikaci, spusťte
příkaz php artisan config:cache
v kořenové složce projektu.
Konfigurační hodnoty se totiž ukládají do mezipaměti a pomocí tohoto
příkazu se naplní novými hodnotami.
Výpis dat v pohledech
Začneme nejdříve pohledem pro článek, který najdeme ve složce
resources/views/article/
s názvem show.blade.php
. Tam
vypisujeme pouze jedno datum a to poslední změnu daného záznamu v patičce
článku. Vytvoříme si tedy nový objekt třídy knihovny Carbon
a následně vypíšeme časový rozdíl oproti poslední změně pomocí
lokalizované metody diffForHumans()
:
@php $updatedAt = new Carbon\Carbon($article->updated_at); @endphp <footer> <p class="small text-secondary border-top pt-2 mt-4"> <i class="fa fa-calendar"></i> {{ $updatedAt->diffForHumans() }} </p> </footer>
Mimo klasické PHP tagy lze použít Blade direktivu
@php ... @endphp
. Není mezi nimi žádný rozdíl, pouze (a snad
mi tuto připomínku ostatní vývojáři odpustí) se jedná o zkrášlení
kódu daného pohledu.
Pokud si nyní zobrazíme nějaký článek, uvidíme v patičce článku výstup podobný tomuto:

Naše aplikace opět vypadá trochu profesionálněji. Bohužel naše řešení už na tom není tak dobře. Daný postup je samozřejmě bezchybný a funguje přesně tak, jak bychom si přáli. Představte si však, že byste na jedné stránce měli například 10 různých dat a pro všechna tato data byste museli vždy vytvořit nový objekt třídy knihovny Carbon. To by bylo poněkud zdlouhavé a zároveň by se kód stal nepřehledným.
Data záznamu jako instance knihovny Carbon
Jak jste si již určitě všimli v předchozích lekcích, vždy se dá vše
zjednodušit. To samé platí pro data záznamů, jež jsou v instanci modelu
vždy reprezentovaná jako objekt třídy Carbon
dědící PHP
třídu DateTime
. My se tedy vytvářením nového objektu
zatěžovat nemusíme a ihned můžeme přistupovat k metodám této
knihovny.
Další datumy, které mají fungovat na stejném principu v
daném modelu, se definují v proměnné $dates
.
Atributy created_at
a updated_at
už jsou automaticky
zahrnuté. Pokud byste tedy chtěli definovat další data, je zbytečné je
znovu specifikovat.
Část pohledu s patičkou si tedy můžeme upravit do následující podoby:
<footer> <p class="small text-secondary border-top pt-2 mt-4"> <i class="fa fa-calendar"></i> {{ $article->updated_at->diffForHumans() }} </p> </footer>
Lokalizované datum
Nejspíše se shodneme na tom, že v článku by se uživateli mělo
zobrazovat přesné datum. Na to můžeme použít jednu z mnoha dostupných
metod a to isoFormat()
, jelikož jedna z výhod je lokalizovaný
výstup (což neplatí například pro metodu format()
):
<footer> <p class="small text-secondary border-top pt-2 mt-4"> <i class="fa fa-calendar"></i> {{ $article->updated_at->isoFormat('LLL') }} </p> </footer>
Výstup může vypadat podobně tomuto:

Více možností pro lokalizovaný výstup lze nalézt v oficiální dokumentaci knihovny Carbon.
Následně si také upravíme zobrazení dat v administraci článků,
abychom tyto výstupy měli sjednocené. Otevřeme si tedy pohled
resources/views/article/index.blade.php
a upravíme následující
část tabulky:
<td>{{ $article->description }}</td> <td>{{ $article->created_at->isoFormat('LLL') }}</td> <td>{{ $article->updated_at->isoFormat('LLL') }}</td> <td>
Hlavní stránka
Zlepšování naší aplikace zakončíme vytvořením hlavní stránky (homepage) pro náš web. Nám zatím postačí, když bude obsahovat pouze výpis nejnovějších článků.
Začneme nejdříve od kontroleru.
Kontroler o jediné akci
Jak jsme si již řekli, kontroler pro zobrazení hlavní stránky bude
definovat pouze jednu akci. Pozastavíme se však u názvu metody pro danou akci
kontroleru. Jak bychom ji totiž měli pojmenovat? Názvy jako
show()
nebo index()
se moc nehodí, jelikož se
nejedná o CRUD kontroler pracující s jednou instancí modelu (na hlavní
stránce nemusíme zobrazovat pouze výpis článků a navíc již jeden CRUD
kontroler pro daný model máme). Možná vás ještě napadne něco jako
getHome()
, ani to však není ten nejlepší přístup.
Pro takovéto případy Laravel definuje tzv. kontrolery jediné
akce (Single
Action Controllers). Tyto kontrolery se vyznačují tím, že definují
pouze jedinou metodu __invoke()
, která může přijímat parametry
stejně jako jakákoliv jiná akce.
Pojďme si nyní takový kontroler vytvořit přes Artisan příkaz
make:controller
. Předtím se však podíváme na jeho
možnosti:
php artisan help make:controller

Možnost --model[=MODEL]
již známe z předchozích lekcí.
Nás však tentokrát bude zajímat možnost --invokable
, která
vytvoří kontroler jediné akce. Ten si pojmenujeme jako
WelcomeController
:
php artisan make:controller --invokable WelcomeController
Nově vygenerovaný kontroler najdeme ve složce s kontrolery
app/Http/Controllers/
a obsahuje pouze zmíněnou metodu
__invoke()
:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Http\Response; class WelcomeController extends Controller { /** * Handle the incoming request. * * @param Request $request * @return Response */ public function __invoke(Request $request) { // } }
My si přes tuto metodu zobrazíme hlavní stránku. Bude nám tedy stačit,
aby vracela pohled, kterému předáme kolekci nejnovějších článků pomocí
Eloquent metody latest()
:
/** * Zobraz hlavní stránku webu. * * @param Request $request * @return View */ public function __invoke(Request $request): View { return view('welcome', ['articles' => Article::latest()->get()]); }
Nesmíme zapomenout importovat náš model a třídy zmíněné v dokumentaci:
use App\Models\Article; use Illuminate\Contracts\View\View;
Routování
Routování kontrolerů jediné akce je trochu rozdílné - nedefinujeme
totiž metodu daného kontroleru, ale pouze jeho název. Pro zobrazení hlavní
stránky využívající tento kontroler si musíme do routovacího souboru
routes/web.php
přidat následující volání metody
get()
routovací třídy Route
:
Route::get('', WelcomeController::class);
Opět musíme přidat import třídy kontroleru:
use App\Http\Controllers\WelcomeController;
Jak si můžete povšimnout, jako URI akci definujeme pouze prázdný
řetězec. Tím dosáhneme toho, že při zobrazení webu bez jakýchkoliv
jiných parametrů v URL adrese se vykoná metoda __invoke()
kontroleru pro hlavní stránku WelcomeController
.
Nesmíme také zapomenout odkázat na hlavní stránku v menu naší hlavní
šablony resources/views/base.blade.php
. Na to použijeme helper
funkci url()
:
<nav class="my-2 my-md-0 mr-md-3"> <a class="p-2 text-dark" href="{{ url('') }}">Hlavní stránka</a> <a class="p-2 text-dark" href="{{ route('article.index') }}">Seznam článků</a> <a class="p-2 text-dark" href="#">Kontakt</a> </nav>
Pohled
Hlavní stránku zakončíme vytvořením pohledu s názvem
welcome.blade.php
ve složce s pohledy
resources/views/
. Momentálně nebude mít na starosti nic jiného
než pouhé vypsání všech článků z naší databáze, které jsme předali
v metodě kontroleru akce:
@extends('base') @section('title', 'Jednoduchý redakční systém v Laravel') @section('description', 'Ukázkový tutoriál pro jednoduchý redakční systém v Laravel frameworku z programátorské sociální sítě itnetwork.cz') @section('content') <h1 class="text-center mb-4">Jednoduchý redakční systém v Laravel</h1> @forelse ($articles as $article) <article class="article mb-5"> <header> <h2> <a href="{{ route('article.show', ['article' => $article]) }}">{{ $article->title }}</a> </h2> </header> <p class="article-content mb-1">{{ $article->description }}</p> <footer> <p class="small text-secondary"> <i class="fa fa-calendar"></i> Naposledy upraveno {{ $article->updated_at->diffForHumans() }} </p> </footer> </article> @empty <p>Zatím se zde nenachází žádné články.</p> @endforelse @endsection
Pokud si nyní otevřeme hlavní stránku přes odkaz v menu nebo při
zadání URL adresy naší aplikace (v případě vestavěného web serveru
http://127.0.0.1:8000/
), uvidíme výpis nejnovějších článků
spolu s odkázáním na ně a jejich datem poslední úpravy:

Tímto jsme dokončili vylepšování našeho projektu. Pokud se vám něco nepodařilo, můžete si stáhnout projekt z přiloženého archivu níže nebo se zeptat v komentářích pod článkem.
V následujícím kvízu, Kvíz - Mix, práce s datem a Blade direktivy v Laravel, si vyzkouší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 93x (52.33 MB)
Aplikace je včetně zdrojových kódů v jazyce PHP