Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

7. díl - Jednoduchý redakční systém v Nette - Administrace

PHP Nette Framework Základy Jednoduchý redakční systém v Nette - Administrace

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Vítám vás všechny u pokračování seriálu tutoriálů o tvorbě webových aplikací v PHP frameworku Nette. V minulém díle jsme již vytvořili základní strukturu pro výpis článků kromě šablon, které dnes přidáme. 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 již můžeme smazat složku app/templates/Homepage/, protože stejně jako 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 cesta k webovému obsahu např. CSS souborům
 * @param array    $flashes  pole zpráv
 *}

<!DOCTYPE html>
<html lang="cs-cz">
        <head>
                <meta charset="UTF-8" />
                <title>{include title|striptags}</title>
                <meta name="description" content="{include description|striptags}" />

                {block css}
                <link rel="stylesheet" href="{$basePath}/css/style.css" type="text/css"/>
                {/block}

                {block head}{/block}
        </head>

        <body>
                <header>
                        <h1>Jednoduchý redakční systém v Nette</h1>
                </header>

                {* Výpis zpráv. *}
                <p n:foreach="$flashes as $flash" class="message">{$flash->message}</p>

                <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 clear="both" />

                <article>
                        <header>
                                <h1>{include title}</h1>
                        </header>
                        <section>
                                {include content} {* Vložení obsahu do šablony. *}
                        </section>
                </article>

                <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}{/block}
        </body>
</html>

app/CoreModule/templates/Article/default.latte

Nakonec přidáme šablonou pro výchozí akci (renderDefault) našeho ArticlePresenter, která je relativně jednoduchá:

{define title}{$article->title}{/define}
{define description}{$article->description}{/define}
{block content}
{$article->content|noescape}

Nyní si již můžete zkusit web spustit a vidět úvodní stránku. Je to jistě příjemný pocit po tom, co jsme změnili tolik kódu, že? :)

Úvodní stránka redakčního systému v Nette frameworku

Ú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

Jelikož model máme již nachystaný z minula, 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

namespace App\CoreModule\Presenters;

use App\CoreModule\Model\ArticleManager;
use App\Presenters\BasePresenter;
use Nette\Application\BadRequestException;
use Nette\Application\UI\Form;
use Nette\Database\UniqueConstraintViolationException;
use Nette\Utils\ArrayHash;

/**
 * Zpracovává práci s články.
 * @package App\CoreModule\Presenters
 */
class ArticlePresenter extends BasePresenter
{
        /** Konstanta s hodnotou URL výchozího článku. */
        const DEFAULT_ARTICLE_URL = 'uvod';

        /** @var ArticleManager Instance třídy modelu pro práci s články. */
        protected $articleManager;

        /**
         * Konstruktor s injektovaným modelem pro práci s články.
         * @param ArticleManager $articleManager automaticky injektovaná třída modelu pro práci s články
         */
        public function __construct(ArticleManager $articleManager)
        {
                parent::__construct();
                $this->articleManager = $articleManager;
        }

        /** Načte a vykreslí článek článek do šablony podle jeho URL.
         * @param string $url URL článku
         * @throws BadRequestException Jestliže článek s danou URL nebyl nalezen.
         */
        public function renderDefault($url)
        {
                if (!$url) $url = self::DEFAULT_ARTICLE_URL; // Pokud není zadaná URL, vykreslí se výchozí článek.
                // Pokusí se načíst článek s danou URL a pokud nebude nalezen, vyhodí chybu 404.
                if (!($article = $this->articleManager->getArticle($url))) throw new BadRequestException();
                $this->template->article = $article; // Předá článek do šablony.
        }

        /** Vykreslí seznam článků do šablony. */
        public function renderList()
        {
                $this->template->articles = $this->articleManager->getArticles();
        }

        /**
         * Odstraní článek.
         * @param string $url
         */
        public function actionRemove($url)
        {
                $this->articleManager->removeArticle($url);
                $this->flashMessage('Článek byl úspěšně odstraněn.');
                $this->redirect(':Core:Article:list');
        }

        /**
         * Vykresluje editaci článku podle jeho URL.
         * @param string $url URL adresa článku, který editujeme, pokud není zadána, vytvoří se nový
         */
        public function actionEditor($url)
        {
                // Pokud byla zadána URL, pokusí se článek načíst a předat jeho hodnoty do editačního formuláře, jinak vypíše chybovou hlášku.
                if ($url) ($article = $this->articleManager->getArticle($url)) ? $this['editorForm']->setDefaults($article) : $this->flashMessage('Článek nebyl nalezen.');
        }

        /**
         * Vrátí formulář pro editor článků.
         * @return Form formulář pro editor článků
         */
        protected function createComponentEditorForm()
        {
                $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('submit', 'Uložit článek');
                $form->onSuccess[] = [$this, 'editorFormSucceeded'];
                return $form;
        }

        /**
         * Funkce se vykonaná při úspěsném odeslání formuláře; zpracuje hodnoty formuláře.
         * @param Form $form formulář editoru
         * @param ArrayHash $values odeslané hodnoty formuláře
         */
        public function editorFormSucceeded($form, $values)
        {
                try {
                        $this->articleManager->saveArticle($values);
                        $this->flashMessage('Článek byl úspěšně uložen.');
                        $this->redirect(':Core:Article:', $values->url);
                } catch (UniqueConstraintViolationException $ex) {
                        $this->flashMessage('Článek s touto URL adresou již existuje.');
                }
        }
}

Zde bych upozornil především na způsob předávání výchozích hodnost do editačního formuláře a to, že se to provádí v actionEditor, nikoliv v renderEditor metodě a také si všimněte použití Nette forms pro vytvoření editačního formuláře, což nám v šabloně ušetří spoustu kódu.

app/CoreModule/presenters/AdministrationPresenter.php

Vytvoříme si prázdný presenter pro administrační rozhraní, protože v tuto chvíli mu v podstatě nepotřebujeme do šablony nic předávat:

<?php

namespace App\CoreModule\Presenters;

use App\Presenters\BasePresenter;

/**
 * Zpracovává vykreslování administrační sekce.
 * @package App\CoreModule\Presenters
 */
class AdministrationPresenter extends BasePresenter
{

}

Příště si přidáme ještě ContactPresenter a poté šablony, kterými administraci článků v našem redakčním systému dokončíme :)


 

Stáhnout

Staženo 296x (651.49 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

 

Článek pro vás napsal Jindřich Máca
Avatar
Jak se ti líbí článek?
6 hlasů
Autor se věnuje převážně webovým technologiím, ale má velkou zálibu ve všem vědeckém, nejen ze světa IT. :-)
Aktivity (1)

 

 

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

Avatar
Petr Linhart
Člen
Avatar
Petr Linhart:14.9.2016 15:10

UniqueConstra­intViolationEx­ception je výjimka, kterou ti vyhodí db driver právě při té duplicitě klíčů

 
Odpovědět  +2 14.9.2016 15:10
Avatar
danhosek
Člen
Avatar
danhosek:5.11.2016 0:23

AHoj.Co mám udělat, když chci předat do editor.latte hodnoty editovaného článku?
Zkusil jsem do public function actionEditor($url) přidal:

($article = $this->articleManager->getArticle($url));
$this->template->article = $article; // Předá článek do šablony.

Ale nefunguje mi to. Sem patří přiřazení proměnných do šablony ne? Proměnné pak v šabloně vypisuju standartně: $article->$article_id
Chci je tam posílat z důvodu další práce ve snippetu s proměnýma.
Děkuji.

Editováno 5.11.2016 0:24
 
Odpovědět 5.11.2016 0:23
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na danhosek
Jindřich Máca:5.11.2016 23:35

Nezlob se na mě, ale tenhle dotaz na mě opět působí tak, že vlastně moc nevíš, co děláš. Opravdu se mě ptáš na to, jak předat proměnou do šablony?

Sem patří přiřazení proměnných do šablony ne?

NE, je to v těch článcích dokonce popsané! Pokud to lze, měl by jsi předávat proměnné do šablony v metodách render*(). Každopádně, pokud na to dojde, můžeš to udělat i v metodě action*() a bude to fungovat...

V uvedeném kódu pak máš úplně zbytečně závorky kolem přiřazení proměnné, proč?! A potom nemáš vůbec ošetřené, co se stane, pokud článek s danou URL neexistuje. :(

A poslední věc, která mě opravdu dorazila:

Proměnné pak v šabloně vypisuju standartně: $article->$article_id

Vážně, odkdy se to takhle zapisuje? Nemá to být náhodou takhle:

$article->article_id

Tohle je úplně začátečnická chyba, kterou každý, kdo alespoň trochu umí PHP, hned vidí. Což značí opět buď Tvoji nepozornost nebo neznalost PHP, a jak už jsem jednou psal, umět PHP je nutně potřeba než se pustíš vlastně do jakéhokoliv PHP frameworku.

Upřímně mě to už nebaví. Můj čas je drahý a rád bych ho strávil odpovídáním na dotazy, které nevyplývají z neznalosti základních věcí. Rozhodně neříkám, že všechny Tvoje dotazy byly takové, ale tenhle... škoda mluvit. Takže příště až uvidím něco podobného, tak prostě už asi nebudu reagovat. Doufám, že si rozumíme. :)

 
Odpovědět  +1 5.11.2016 23:35
Avatar
danhosek
Člen
Avatar
Odpovídá na Jindřich Máca
danhosek:6.11.2016 1:52

Ahoj, rozumíme. Chtěl jsem jen dodělat ten snipped, který poslední chyběl. Byla tam nepozornost... umím spoustu věcí, ale bohužel pouze teoreticky a v praxi pak přehlédnu hloupé chyby. Ale děkuji ti za tvůj čas, který pro mě nebyl promarněný a dal mi spoustu cenných zkušeností.
Nyní mi to už funguje. Tak myslím, že bude odemne snad i na delší dobu klid.:o)
Už je to snad i klišé, ale moc děkuji za trpělivost s mémi dotazy. Tvé odpovědi byli pro mě plodné, cenné a získal jsem spoustu zkušeností.
Děkuji.

Editováno 6.11.2016 1:54
 
Odpovědět  +2 6.11.2016 1:52
Avatar
Jan Bezdíček
Redaktor
Avatar
Odpovídá na danhosek
Jan Bezdíček:6.11.2016 1:58

Vice zkusenosti bys asi ziskal, kdybys ty teoreticke znalosti uplatnil v praxi na nejakem projektu bez pouziti nette, at to PHP dostanes poradne do krve ... protoze ocividne z predchoziho komentare ani nevis, jak poradne funguje syntaxe jazyka

 
Odpovědět 6.11.2016 1:58
Avatar
Vakos
Redaktor
Avatar
Vakos:8. února 23:09

Chtěl bych se zeptat. Zkoušel jsem využít ArticleManager a ArticlePresenter a vytvořil jsem jejich kopie s názvy DateManager a DatePresenter a celý obsah překopíroval a názvy tříd, proměnné, konstanty atd. jsem upravil a pořád mi to hází Error 500.

V Router by problém být neměl, zkopíroval jsem si zde také tu část z Article a dal jsem nakonec i 'url' => null, takže v tomto by problém být neměl.

Nevíte, v čem by mohla být tedy chyba?

Odpovědět 8. února 23:09
"Jediný způsob, jak dělat skvělou práci, je milovat to, co děláte. Pokud jste to ještě nenašli, hledejte dál. Ne...
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Vakos
Jindřich Máca:8. února 23:29

Jestliže to hází pouze čistou chybu 500, tak konkrétní chybová zpráva bude uvedená v logu (složka log/). ;)

P.S.: Pokud si ani s ní nebudeš vědět rady, tak ji sem pošli. :)

 
Odpovědět 8. února 23:29
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:8. února 23:38

V log mi to hází toto:

Nette\InvalidStateException: Resource 'Core:Date' does not exist. in C:\xampp\htdocs\vendor\nette\security\src\Security\Permission.php:300  @  http://localhost/dates/  @@  exception-2017-02-08-22-01-55-ab963012bf52ae2b84dd39a63a6b0823.html

Nevím ale kde to upravit. V konfig.neon mám přidáno date: Core:Date

Odpovědět 8. února 23:38
"Jediný způsob, jak dělat skvělou práci, je milovat to, co děláte. Pokud jste to ještě nenašli, hledejte dál. Ne...
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Vakos
Jindřich Máca:8. února 23:49

To vypadá na to, že používáš finální verzi projektu a zapomněl jsi přidat zdroj pro oprávnění. Podívej se do 11. dílu, kde se řeší právě konfigurace oprávnění u statického ACL - http://www.itnetwork.cz/…ka-opravneni

Co potřebuješ přidat je toto:

# Nastavení vlastních služeb dále přístupných pomocí DI v rámci CoreModule.
services:
        security.authorizator: # Nastavení zdrojů a pravidel přístupu k nim v rámci CoreModule pomocí statického ACL.
                setup:
                        ...
                        - addResource(%date%)
                        ...

A dále samozřejmě nastavení konkrétních přístupových práv k danému presenteru. ;)

 
Odpovědět  +1 8. února 23:49
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:9. února 9:55

Jj, to je ono, děkuji.

Odpovědět 9. února 9:55
"Jediný způsob, jak dělat skvělou práci, je milovat to, co děláte. Pokud jste to ještě nenašli, hledejte dál. Ne...
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 24. Zobrazit vše