Válí se ti projekty v šuplíku? Dostaň je mezi lidi a získej cool tričko a body na profi IT kurzy v soutěži ITnetwork summer 2017!
Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

8. díl - Jednoduchý redakční systém v Nette - Dokončení administrace

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

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

V minulém tutoriálu o tvorbě jednoduchého redakčního systému v Nette frameworku jsme rozpracovali administraci článků. Dnes ji spolu s kontaktním formulářem dokončíme.

app/CoreModule/presenters/ContactPresenter.php

Nejprve přidáme ještě presenter pro kontaktní formulář:

<?php

namespace App\CoreModule\Presenters;

use App\Presenters\BasePresenter;
use Nette\Application\UI\Form;
use Nette\InvalidStateException;
use Nette\Mail\Message;
use Nette\Mail\SendmailMailer;
use Nette\Utils\ArrayHash;

/**
 * Zpracovává kontaktní formulář.
 * @package App\CoreModule\Presenters
 */
class ContactPresenter extends BasePresenter
{
        /** Email administrátora, na který se budou posílat emaily z kontaktního formuláře. */
        const EMAIL = [email protected]';

        /**
         * Vytváří a vrací komponentu kontaktního formuláře.
         * @return Form kontaktní formulář
         */
        protected function createComponentContactForm()
        {
                $form = new Form;
                $form->addText('email', 'Vaše emailová adresa')->setType('email')->setRequired();
                $form->addText('y', 'Zadejte aktuální rok')->setRequired()
                        ->addRule(Form::EQUAL, 'Chybně vyplněný antispam.', date("Y"));
                $form->addTextArea('message', 'Zpráva')->setRequired()
                        ->addRule(Form::MIN_LENGTH, 'Zpráva musí být minimálně %d znaků dlouhá.', 10);
                $form->addSubmit('submit', 'Odeslat');
                $form->onSuccess[] = [$this, 'contactFormSucceeded'];
                return $form;
        }

        /**
         * Funkce se vykonaná při úspěsném odeslání kontaktního formuláře a odešle email.
         * @param Form $form kontaktní formulář
         * @param ArrayHash $values odeslané hodnoty formuláře
         */
        public function contactFormSucceeded($form, $values)
        {
                try {
                        $mail = new Message;
                        $mail->setFrom($values->email)
                                ->addTo(self::EMAIL)
                                ->setSubject('Email z webu')
                                ->setBody($values->message);
                        $mailer = new SendmailMailer;
                        $mailer->send($mail);
                        $this->flashMessage('Email byl úspěšně odeslán.');
                        $this->redirect('this');
                } catch (InvalidStateException $ex) {
                        $this->flashMessage('Email se nepodařilo odeslat.');
                }
        }
}

Zde si povšimněte především použití Nette rozhraní pro odesílání e-mailů z formuláře.

app/config/config.neon

Pokud jste pozorně četli kód, všimli jste si, že u tvorby formulářů v metodě ->setRequired() není vyplněna chybová hláška. To je z toho důvodu, že nám bude stačit všude stejná a tu si globálně nastavíme v konfiguračním souboru připsáním následujících řádků:

# Nastavení výchozích chybových hlášek pro formuláře.
forms:
        messages:
                REQUIRED: 'Povinné pole.'

app/router/RouterFactory.php

Nakonec musíme ještě opět upravit routování, aby naše aplikace brala v potaz nové presentery a jejich akce. Také si zde ukáže příklad překladu českých URL adres na anglické názvy akcí.

<?php

namespace App;

use Nette\Application\Routers\Route;
use Nette\Application\Routers\RouteList;

/**
 * Routovací továrnička.
 * Řídí routování v celé aplikaci.
 * @package App
 */
class RouterFactory
{
        /**
         * Vytváří router pro aplikaci.
         * @return RouteList výsledný router pro aplikaci
         */
        public static function createRouter()
        {
                $router = new RouteList();
                $router[] = new Route('kontakt/', 'Core:Contact:default');
                $router[] = new Route('administrace/', 'Core:Administration:default');
                $router[] = new Route('[<action>/][<url>]', array(
                        'presenter' => 'Core:Article',
                        'action' => array(
                                Route::VALUE => 'default',
                                Route::FILTER_TABLE => array(
                                        // řetězec v URL => akce presenteru
                                        'seznam-clanku' => 'list',
                                        'editor' => 'editor',
                                        'odstranit' => 'remove'
                                ),
                                Route::FILTER_STRICT => true
                        ),
                        'url' => null,
                ));
                $router[] = new Route('[<url>]', 'Core:Article:default');
                return $router;
        }
}

Pokud se divíte, proč musí mít každý presenter svojí routu, tak je to z toho důvodu, že potřebujeme rozlišit mezi URL článku a názvem presenteru, protože obě mají stejný tvar - /presenter vs. /url. V tomto případě pak vždy dostane přednost presenter před vykreslením článku.

Šablony

Nyní se můžeme podívat zase na šablony (templates).

[email protected]

Zde pouze upravíme odkazy na jednotlivé presentery a jejich akce pomocí Latte maker a přidáme odkaz na administrační rozhraní. Nebudu sem vypisovat znovu celou šablonu, pouze provedené změny:

...
<ul>
        <li><a n:href=":Core:Article:">Úvod</a></li>
        <li><a n:href=":Core:Article:list">Seznam článků</a></li>
        <li><a n:href=":Core:Contact:">Kontakt</a></li>
</ul>
...
<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>. <a n:href=":Core:Administration:">Administrace</a></p>
</footer>
...

app/CoreModule/templates/Article/list.latte

Přidáme šablonu pro výpis článků:

{define title}Výpis článků{/define}
{define description}Výpis všech článků.{/define}
{block content}
<table>
        <tr n:foreach="$articles as $article">
                <td>
                        <h2><a n:href=":Core:Article: $article->url">{$article->title}</a></h2>
                        {$article->description}
                        <br />
                        <a n:href=":Core:Article:editor $article->url">Editovat</a>
                        <a n:href=":Core:Article:remove $article->url">Odstranit</a>
                </td>
        </tr>
</table>

app/CoreModule/templates/Article/editor.latte

Nyní šablonu pro editor článků. Zde si povšimněte jak jednoduše jsme zařídili renderování formuláře a dále způsobu přidávání dalších JavaScript knihoven:

{define title}Editor{/define}
{define description}Editor článků.{/define}
{block content}
{* Formulář pro editaci. *}
{control editorForm}
{/block}

{block scripts}
{include parent}
<script type="text/javascript" src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
<script type="text/javascript">
    tinymce.init({
        selector: "textarea[name=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: "named",
        entity_encoding: "raw"
});
</script>
{/block}

app/CoreModule/templates/Administration/default.latte

Dále následuje šablona pro administrační rozhraní:

{define title}Administrace webu{/define}
{define description}Administrace webu.{/define}
{block content}
<p>Vítejte v administraci!</p>
<h2><a n:href=":Core:Article:editor">Editor článků</a></h2>
<h2><a n:href=":Core:Article:list">Seznam článků</a></h2>

app/CoreModule/templates/Contact/default.latte

A na závěr šablona pro stránku s kontaktním formulářem:

{define title}Kontaktní formulář{/define}
{define description}Kontaktní formulář.{/define}
{block content}
<p>Kontaktujte nás odesláním formuláře níže.</p>
{* Formulář pro kontakt. *}
{control contactForm}
Stránka s kontaktním formulářem

Gratuluji, právě vám běží jednoduché administrační rozhraní pro články v Nette s kontaktním formulářem jako bonus. ;)

Nyní, v rámci seriálu, budeme dále pokračovat v rozšiřování administrace a začneme se věnovat zabezpečení našeho webu, což by mělo vyústit v plně funkční přihlašování a registraci uživatelů s definicí jejich práv, takže se určitě máte na co těšit. :) Konkrétně v příštím díle začneme rozšířením databáze a přidáním modelu uživatelů. ;)


 

Stáhnout

Staženo 339x (657.03 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?
7 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 (37)

Avatar
Vakos
Redaktor
Avatar
Vakos:21. února 18:38

Chci se zeptat. Jména latte šablonů mohou být pojmenovány jakkoli? Vše mám dělané podle článků a to nastává, problém nastává, když si chci přidat další latte šablonu, začne to ihned zlobit. Když si vytvořím novou šablonu, tak nastavím práva v config a pak už jej začínám používat, bohužel to vyhodí chybu.

V čem může být problém?

Odpovědět 21. února 18: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:21. února 19:45

Nějak nechápu, jak to myslíš. :( Jména Latte šablon mají nějaké konvence vůči akcím jednotlivých presenterů. Práva v konfiguračním souboru, pokud tedy myslíš statické ACL, vůbec nesouvisí se šablonami, ale právě s presentery. A vůbec, vhodné by bylo sem poslat tu konkrétní chybu, kterou Ti to píše. Takhle z toho nikdo nemůže být moc moudrý. :)

 
Odpovědět 21. února 19:45
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:21. února 19:55

Chápu tedy že mají nějaké konvence, jak si tedy mohu vytvořit druhý soubor, kde například budu taktéž vypisovat články?

Odpovědět 21. února 19: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...
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Vakos
Jindřich Máca:21. února 20:18

Myslím, že to jsou trochu popletené pojmy. Za výpis článků přeci vůbec není zodpovědný soubor Latte šablony, ale samotná akce presenteru. Šablona pak pouze slouží k reprezentaci výstupu dané akce do HTML podoby. Konvence jsou pak v tom, jaká šablona se mapuje na kterou příslušnou akci presenteru. :)

Pro pochopení problematiky doporučuji kouknout hned na první díl seriálu (http://www.itnetwork.cz/…eworku-nette), kde je vysvětlen životní cyklus stránky v Nette, včetně obrázku. ;)

 
Odpovědět 21. února 20:18
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:21. února 20:31

Prošel jsem si to a snad už vím. Nyní ale nevím jak to změnit v Presenteru. Aktuálně je tam takovýto řádek

$this->template->articles = $this->articleManager->getArticles();

Jak napsat tedy nový řádek například pro šablonu page.latte? Díval jsem se i na nette.org, ale moudrý z toho moc nejsem ...

Odpovědět 21. února 20:31
"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:21. února 20:46

Tohle je kód, co právě předává příslušná data článků do automaticky (podle konvencí) namapované Latte šablony. Vůbec to nesouvisí s tím, jaká šablona se použije, jde pouze o to předávání dat.

Pokud Ti to moc nedává smysl, tak hned na začátku seriálu je napsané, že je potřeba umět dobře OOP v PHP a vědět něco o třívrstvé MVP (MVC) architektuře. Možná bych tedy začal tam. ;)

 
Odpovědět 21. února 20:46
Avatar
Karl
Člen
Avatar
Odpovídá na Jindřich Máca
Karl:22. února 9:42

Jindro, prosím mohl bys juknout na můj poslední dotaz z 15. února? Díky

 
Odpovědět 22. února 9:42
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Karl
Jindřich Máca:22. února 22:39

Promiň, já jsem Tvůj příspěvek četl, ale považoval jsem ho spíše za konstatování, protože v něm nevidím žádnou otázku a před tím jsi ještě uváděl, že Ti to při nějakém nastavení funguje. :D

Shrnul bych to asi takhle, pokud to nefunguje na hostingu, kde vlastně nemáš možnost si nic přenastavit, tak asi bude opravdu potřeba předělat příslušné inserty. :(

Jak to udělat "dobře" můžeš najít třeba tady - http://stackoverflow.com/…-primary-key

 
Odpovědět 22. února 22:39
Avatar
SolusLupusUmbra
Redaktor
Avatar
SolusLupusUmbra:11. července 23:13

v routeru máš new Route("[<acti­on>/][url]",.­....)
nebylo by výhodnější použít new Route( "[<module>/] [<presenter>/<ac­tion>] [<url>]",... )?
neposkytlo by to uživateli příliš informací o struktuře?
pokud bych to použil, stačilo by routovat jen výchozí stránku?
Díky,

 
Odpovědět 11. července 23:13
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na SolusLupusUmbra
Jindřich Máca:11. července 23:25

Můžeš to klidně upravit podle sebe, pokud chceš. Potencionálně může nastat pouze rozdíl v URL adresách, což vlastně stejně záleží čistě na Tobě. ;)

P.S.: Za případné chyby ale neručím. :D

Editováno 11. července 23:26
 
Odpovědět 11. července 23:25
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 47. Zobrazit vše