Lekce 7 - Jednoduchý redakční systém v Nette - Administrace
V minulé lekci, Jednoduchý redakční systém v Nette - Výpis článku, jsme vytvořili základní strukturu pro výpis článků.
Dnes se vrhneme do šablon. Tím výpis zprovozníme a budeme pokračovat s tvorbou jejich administrace.
Šablony
Nyní je tedy čas podívat se na zoubek šablonám (templates). Opět zde
můžeme smazat celou složku app/templates/Homepage/
, protože
stejně jako třídu HomepagePresenter
ji už nebudeme dále
potřebovat.
app/templates/@layout.latte
Samozřejmě nezačneme ničím jiným než úpravou celkového vzhledu
naší aplikace, který v tomto případě zajišťuje Latte šablona @layout.latte
,
opět předpřipravená v sandboxu, ze kterého vycházíme:
{** * @param string $basePath web base path * @param array $flashes flash messages *} {import 'components/form.latte'} <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{ifset title}{include title|stripHtml} | {/ifset}Nette Sandbox</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="{$basePath}/css/style.css"> {block head}{/block} </head> <body> <header> <h1>Jednoduchý redakční systém v Nette</h1> </header> <div class=container> {* Výpis flash zpráv. *} <div n:foreach="$flashes as $flash" n:class="alert, 'alert-' . $flash->type">{$flash->message}</div> <nav> <ul> <li><a n:href=:Core:Article:>Úvod</a></li> <li><a href="#">Seznam článků</a></li> <li><a href="#">Kontakt</a></li> </ul> </nav> <br style="clear: both;"> <article> <header> <h1>{include title}</h1> </header> <section> {include content} {* Vložení obsahu do šablony. *} </section> </article> </div> <footer> <p> Ukázkový tutoriál pro jednoduchý redakční systém v Nette z programátorské sociální sítě <a href="http://www.itnetwork.cz" target="_blank">itnetwork.cz</a> </p> </footer> {block scripts} <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <script src="https://nette.github.io/resources/js/3/netteForms.min.js"></script> <script src="{$basePath}/js/main.js"></script> {/block} </body> </html>
app/CoreModule/templates/Article/default.latte
Nakonec vytvoříme složku Article/
pro šablony našeho
ArticlePresenter
v CoreModule a do ní přidáme soubor
default.latte
jako šablonou pro jeho výchozí akci
renderDefault()
. Samotná šablona je relativně jednoduchá:
{block title}{$article->title}{/block} {block description}{$article->description}{/block} {block content} {$article->content|noescape}
Nyní si již můžeme zkusit web spustit a měli bychom vidět úvodní stránku. Je to jistě příjemný pocit po tom, co jsme změnili tolik kódu, že?
Úplný základ máme zprovozněný, nyní se podíváme hlouběji do CoreModule a to konkrétně na administraci článků
Presentery
Model máme již nachystaný z minula, takže začneme rovnou od presenterů.
app/CoreModule/Presenters/ArticlePresenter.php
Jelikož v Nette můžeme mít více akcí v jednom presenteru, budeme
pokračovat v rozšiřování naší třídy ArticlePresenter
a
přidáme do ní následující metody dalších akcí:
<?php declare(strict_types=1); namespace App\CoreModule\Presenters; use App\CoreModule\Model\ArticleManager; use App\Presenters\BasePresenter; use Nette\Application\AbortException; use Nette\Application\BadRequestException; use Nette\Application\UI\Form; use Nette\Database\UniqueConstraintViolationException; use Nette\Utils\ArrayHash; /** * Presenter pro vykreslování článků. * @package App\CoreModule\Presenters */ class ArticlePresenter extends BasePresenter { /** @var string URL výchozího článku. */ private string $defaultArticleUrl; /** @var ArticleManager Model pro správu s článků. */ private ArticleManager $articleManager; /** * Konstruktor s nastavením URL výchozího článku a injektovaným modelem pro správu článků. * @param string $defaultArticleUrl URL výchozího článku * @param ArticleManager $articleManager automaticky injektovaný model pro správu článků */ public function __construct(string $defaultArticleUrl, ArticleManager $articleManager) { parent::__construct(); $this->defaultArticleUrl = $defaultArticleUrl; $this->articleManager = $articleManager; } /** * Načte a předá článek do šablony podle jeho URL. * @param string|null $url URL článku * @throws BadRequestException Jestliže článek s danou URL nebyl nalezen. */ public function renderDefault(string $url = null) { if (!$url) $url = $this->defaultArticleUrl; // Pokud není zadaná URL, vezme se URL výchozího článku. // Pokusí se načíst článek s danou URL a pokud nebude nalezen vyhodí chybu 404. if (!($article = $this->articleManager->getArticle($url))) $this->error(); // Vyhazuje výjimku BadRequestException. $this->template->article = $article; // Předá článek do šablony. } /** Načte a předá seznam článků do šablony. */ public function renderList() { $this->template->articles = $this->articleManager->getArticles(); } /** * Odstraní článek. * @param string|null $url URL článku * @throws AbortException */ public function actionRemove(string $url = null) { $this->articleManager->removeArticle($url); $this->flashMessage('Článek byl úspěšně odstraněn.'); $this->redirect('Article:list'); } /** * Vykresluje formulář pro editaci článku podle zadané URL. * Pokud URL není zadána, nebo článek s danou URL neexistuje, vytvoří se nový. * @param string|null $url URL adresa článku */ public function actionEditor(string $url = null) { if ($url) { if (!($article = $this->articleManager->getArticle($url))) $this->flashMessage('Článek nebyl nalezen.'); // Výpis chybové hlášky. else $this['editorForm']->setDefaults($article); // Předání hodnot článku do editačního formuláře. } } /** * Vytváří a vrací formulář pro editaci článků. * @return Form formulář pro editaci článků */ protected function createComponentEditorForm() { // Vytvoření formuláře a definice jeho polí. $form = new Form; $form->addHidden('article_id'); $form->addText('title', 'Titulek')->setRequired(); $form->addText('url', 'URL')->setRequired(); $form->addText('description', 'Popisek')->setRequired(); $form->addTextArea('content', 'Obsah'); $form->addSubmit('save', 'Uložit článek'); // Funkce se vykonaná při úspěšném odeslání formuláře a zpracuje zadané hodnoty. $form->onSuccess[] = function (Form $form, ArrayHash $values) { try { $this->articleManager->saveArticle($values); $this->flashMessage('Článek byl úspěšně uložen.'); $this->redirect('Article:', $values->url); } catch (UniqueConstraintViolationException $e) { $this->flashMessage('Článek s touto URL adresou již existuje.'); } }; return $form; } }
Zde bych upozornil především na způsob předávání výchozích hodnot
do editačního formuláře a hlavně na to, že se úkon provádí v metodě
actionEditor()
, nikoliv v renderEditor()
. Vyplývá to
z životního cyklu akce Nette presenteru.
Dále si všimněte použití Nette knihovny pro vytvoření editačního formuláře, což nám, mimo např. bezpečnosti, v šabloně následně ušetří spoustu kódu při jeho vykreslování
app/CoreModule/Presenters/AdministrationPresenter.php
Ještě než dnes skončíme s presentery, vytvoříme si jeden prázdný pro administrační sekci. Bude prázdný, protože, že v tuto chvíli v podstatě nepotřebujeme do jeho šablony nic předávat:
<?php declare(strict_types=1); namespace App\CoreModule\Presenters; use App\Presenters\BasePresenter; /** * Presenter pro vykreslování administrační sekce. * @package App\CoreModule\Presenters */ class AdministrationPresenter extends BasePresenter { }
Pro dnešní lekci to bude vše.
V další lekci, Jednoduchý redakční systém v Nette - Dokončení administrace, si přidáme presenter pro kontaktní formulář a poté také všechny chybějící šablony. Tak administraci článků v našem redakčním systému dokončíme