Java týden Java týden
Pouze tento týden sleva až 80 % na celý Java e-learning!
Brno? Vypsali jsme pro vás nové termíny školení OOP v Brně!

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

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 minulé lekci, Jednoduchý redakční systém v Nette - Administrace, jsme rozpracovali administraci článků. Dnes ji spolu s kontaktním formulářem dokončíme.

Presentery

Začneme dokončením presenterů z minula.

app/CoreModule/pre­senters/Contac­tPresenter.php

Přidáme tak ještě jeden presenter pro kontaktní formulář:

<?php

namespace App\CoreModule\Presenters;

use App\Presenters\BasePresenter;
use Nette\Application\UI\Form;
use Nette\Mail\IMailer;
use Nette\Mail\Message;
use Nette\Mail\SendException;
use Nette\Utils\ArrayHash;

/**
 * Presenter pro kontaktní formulář.
 * @package App\CoreModule\Presenters
 */
class ContactPresenter extends BasePresenter
{
    /** @var string Kontaktní email, na který se budou posílat emaily z kontaktního formuláře. */
    private $contactEmail;

    /** @var IMailer Služba Nette pro odesílání emailů. */
    private $mailer;

    /**
     * Konstruktor s nastavením kontaktního emailu a injektovanou Nette službou pro odesílání emailů.
     * @param string  $contactEmail kontaktní email
     * @param IMailer $mailer       automaticky injektovaná Nette služba pro odesílání emailů
     */
    public function __construct($contactEmail, IMailer $mailer)
    {
        parent::__construct();
        $this->contactEmail = $contactEmail;
        $this->mailer = $mailer;
    }

    /**
     * Vytváří a vrací kontaktní formulář.
     * @return Form kontaktní formulář
     */
    protected function createComponentContactForm()
    {
        $form = new Form;
        $form->getElementPrototype()->setAttribute('novalidate', true);
        $form->addEmail('email', 'Vaše emailová adresa')->setRequired();
        $form->addText('y', 'Zadejte aktuální rok')->setOmitted()->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('send', 'Odeslat');

        // Funkce se vykonaná při úspěšném odeslání kontaktního formuláře a odešle email.
        $form->onSuccess[] = function (Form $form, ArrayHash $values) {
            try {
                $mail = new Message;
                $mail->setFrom($values->email)
                    ->addTo($this->contactEmail)
                    ->setSubject('Email z webu')
                    ->setBody($values->message);
                $this->mailer->send($mail);
                $this->flashMessage('Email byl úspěšně odeslán.');
                $this->redirect('this');
            } catch (SendException $e) {
                $this->flashMessage('Email se nepodařilo odeslat.');
            }
        };

        return $form;
    }
}

Zde si všimněte především použití Nette knihovny pro odesílání emailů z formuláře.

app/CoreModule/con­fig/config.ne­on

Dále nesmíme zapomenout předat konfiguraci kontaktního emailu do našeho nového presenteru:

#
# Konfigurační soubor pro CoreModule.
#
parameters:
    defaultArticleUrl: 'uvod'          # URL výhozího článku
    contactEmail: '[email protected]' # Kontaktní email


# Nastavení služeb pro CoreModule.
services:
    # Definice vlastních služeb dále přístupných pomocí DI.
    - App\CoreModule\Model\ArticleManager

    # Předání nastavení při vytváření služeb presenterů.
    - App\CoreModule\Presenters\ArticlePresenter(%defaultArticleUrl%)
    - App\CoreModule\Presenters\ContactPresenter(%contactEmail%)

app/config/con­fig.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 hlavním 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.'
        EMAIL: 'Neplatná emailová adresa.'
...

app/router/Rou­terFactory.php

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

<?php

namespace App;

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

/**
 * Továrna na routovací pravidla.
 * Řídí směrování a generovaní URL adres v celé aplikaci.
 * @package App
 */
class RouterFactory
{
    use StaticClass;

    /**
     * Vytváří a vrací seznam routovacích pravidel pro aplikaci.
     * @return IRouter 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>]', [
            'presenter' => 'Core:Article',
            'action' => [
                Route::FILTER_STRICT => true,
                Route::FILTER_TABLE => [
                    // řetězec v URL => akce presenteru
                    'seznam-clanku' => 'list',
                    'editor' => 'editor',
                    'odstranit' => 'remove'
                ]
            ]
        ]);
        $router[] = new Route('[<url>]', 'Core:Article:default');
        return $router;
    }
}

Pokud se divíte, proč mají některé presentery svojí vlastní 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ě tedy vždy dostane přednost název presenteru před vykreslením URL článku.

Šablony

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

app/templates/@la­yout.latte

Zde pouze doplníme odkazy na jednotlivé presentery a jejich akce pomocí Latte maker a přidáme odkaz na administrační rozhraní do patičky. Nebudu sem vypisovat již 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/tem­plates/Article/lis­t.latte

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

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

app/CoreModule/tem­plates/Article/e­ditor.latte

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

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

{block scripts}
    {include parent}
    <script type="text/javascript" src="//cdn.tinymce.com/4/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: 'raw'
        });
    </script>
{/block}

app/CoreModule/tem­plates/Adminis­tration/defau­lt.latte

Následuje šablona pro administrační rozhraní:

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

app/CoreModule/tem­plates/Contac­t/default.lat­te

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

{block title}Kontaktní formulář{/block}
{block description}Kontaktní formulář.{/block}
{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 kurzu budeme 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í lekci, Jednoduchý redakční systém v Nette - Model uživatelů, začneme rozšířením databáze a přidáním modelu uživatelů.


 

Stáhnout

Staženo 580x (1.17 MB)
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?
14 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. :-)
Předchozí článek
Jednoduchý redakční systém v Nette - Administrace
Všechny články v sekci
Základy Nette frameworku
Miniatura
Následující článek
Jednoduchý redakční systém v Nette - Model uživatelů
Aktivity (5)

 

 

Komentáře

Avatar
NouF
Člen
Avatar
NouF:10.7.2015 7:53

Super

Editováno 10.7.2015 7:53
 
Odpovědět  +1 10.7.2015 7:53
Avatar
Jan Suchánek:10.7.2015 9:25

Nastavení vychozích hodnot formulaře by melo být už Presenteru.

 
Odpovědět  +1 10.7.2015 9:25
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Suchánek
Jindřich Máca:10.7.2015 11:00

To je rozhodně dobrá připomínka. :) Samozřejmě může, ale tady je potřeba si uvědomit průběh vykreslení té stránky editoru. Je tam trochu problém s ověřením té URL.

Moje úvaha:

  • Z funkce renderEditor($ur­l) se volá getArticle($url) kvůli ověření existence článku a volat předání hodnot do fomuláře tady, je čisté asi stejně jako v té šabloně.
  • Ve funkci createComponen­tEditorForm() naopak zase není přístup k té URL a volat tady znovu getArticle($url) není úplně optimální i kdyby tady ta URL byla k dispozici.
  • Řešení je pak mít buď $url nebo $article jako field té třídy. Tohle zase není úplně čisté z hlediska OOP návrhu, protože je tu víc metod pro vykreslování a fieldy by neměli být tak specifické.

Moje řešení:
Určitě není čisté, ale rozhodl jsem se zachovat standardní průběh vykreslování a komunikace mezi MVP vrstvami. Z metody renderEditor($ur­l) předám vše potřebné do šablony, tak jak by se mělo a když se ze šablony volá zpětně vykreslení komponenty, tak jak by se mělo, můžu jí předat výchozí hodnoty nebo ne. Tady je pak ten kámen úrazu, protože v Latte není hezký standardní způsob, jak ty hodnoty předat.

Samozřejmě nejsem neomylný a pokud znáš 100% čistý způsob, jak by se tohle mělo v Nette řešit, tak sem s ním! Vždycky se rád poučím. ;)

Editováno 10.7.2015 11:01
 
Odpovědět  +1 10.7.2015 11:00
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Suchánek
Jindřich Máca:10.7.2015 11:48

Tak beru zpět, měl si pravdu. Koukal jsem ještě pro jistotu na http://doc.nette.org/…eating-posts a zde se volá předání hodnot do formuláře v action*, takže to asi bude nejčistší řešení. :) V tom případě opravím napříč články. ;)

 
Odpovědět  +1 10.7.2015 11:48
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Jindřich Máca:10.7.2015 12:59

!!!UPOZORNĚNÍ!!!

Na základě připomínek v komentářích jsem opět trochu poupravil kód i článek. Teoreticky by to nemělo mít vliv na funkčnost, spíše jde o vylepšení čistoty kódu podle Nette. Konkrétně se jedná o předávání výchozích hodnot do formuláře v metodě render/actionE­ditor a následného vykreslení formuláře v šabloně editor.latte.

Omlouvám se všem za komplikace a zároveň děkuji za pochopení! :)

 
Odpovědět  +1 10.7.2015 12:59
Avatar
Odpovídá na Jindřich Máca
Jan Suchánek:10.7.2015 13:02

Jj, přesně, jinak by se pak nedali dělat továrničky z neonu a předávat jim parametry a vyčistit si tak presentery od spousty kódu.

Jako je něco takového:

protected createComponentEditForm()
{
        return $this->editFormFactory->create($this->editItem);
}
Editováno 10.7.2015 13:03
 
Odpovědět  +1 10.7.2015 13:02
Avatar
Jan Suchánek:10.7.2015 13:06

Mrkni na Zlámalův blogísek: https://github.com/…w.zeminem.cz

 
Odpovědět 10.7.2015 13:06
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Suchánek
Jindřich Máca:10.7.2015 13:08

Ano, na továrničky taky samozřejmě dojde, ale tenhle tutoriál je určen i pro začátečníky, takže jsem to zatím nechtěl zbytečně komplikovat a navíc, ty Presentery, kde tvořím formuláře, nejsou ještě tak extra dlouhé, ty formuláře jsou pro ně unikátní a je tam vždy jen jeden. ;)

Editováno 10.7.2015 13:09
 
Odpovědět 10.7.2015 13:08
Avatar
Jan Suchánek:10.7.2015 13:10

Jasný

 
Odpovědět 10.7.2015 13:10
Avatar
pepapavlik
Člen
Avatar
Odpovídá na Jindřich Máca
pepapavlik:21.7.2015 12:47

Zdravím,

našel jsem menší chybku. A to v app/CoreModule/pre­senters/article­Presenter.php

na začátku v "use" chybí cesty na používané soubory. Bez nich to vyhazuje chybu, že není znám Form.

Možná by to chtělo již v tom šestém díle upravit, nebo v dalších ty cesty přidat.

Jsou to tyto:
use Nette\Applica­tion\UI\Form;
use Nette\Database\U­niqueConstrain­tViolationExcep­tion;
use Nette\Utils\A­rrayHash;

 
Odpovědět  +1 21.7.2015 12:47
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na pepapavlik
Jindřich Máca:21.7.2015 20:29

Ahoj,

to je způsobené tím, že v článku http://www.itnetwork.cz/…administrace je vypsané pouze rozšíření třídy ArticlePresenter tj. pouze přidané metody. Není tam tedy vidět kýžený začátek souboru, kde je samozřejmě třeba doplnit nově použité třídy. V přiloženém archivu už jsou ale pak uvedeny. :)

Uznávám, že je to matoucí a neúplné, takže to ve zmíněném článku napravím. ;)

 
Odpovědět 21.7.2015 20:29
Avatar
Supercaptain
Člen
Avatar
Supercaptain:22.8.2015 14:56

ahoj, setkal se nekdo u kontaktniho formulare s touto chybou?

Method Nette\Utils\Html::__toS­tring() must not throw an exception

Nevite cim by to mohlo byt? Kdyz necham jenom addText s emailem tak to funguje pokud pridam addTextArea zacne to blbnout.

 
Odpovědět  +1 22.8.2015 14:56
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Supercaptain
Jindřich Máca:6.9.2015 15:46

Ahoj, to bude pravděpodobně tím, že u addTextArea() potom nemůžeš volat setType('email'), protože TextArea žádný takový typ nemá. :-D Zkoušel jsi to i bez toho? :-)

 
Odpovědět 6.9.2015 15:46
Avatar
Supercaptain
Člen
Avatar
Odpovídá na Jindřich Máca
Supercaptain:6.9.2015 18:25

Kod jsem mel "zkopirovany z tutorialu z této stranky".

Opravdu jsem u addTextArea nepřidaval type email :-). Co jsem tim myslel ukazu na nasledujícím kodu....

Měl jsem nasledujici kod

$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"));

A prave kdyz jsem tohle pridal zacalo to blbnout.

$form->addTextArea('message', 'Zpráva')->setRequired()
                   ->addRule(Form::MIN_LENGTH, 'Zpráva musí být minimálně %d znaků dlouhá.', 10);

Nevim proc tomu tak je. Stahnul jsem si ten presenter ze zdrojaku a jede to v pořadku.

 
Odpovědět 6.9.2015 18:25
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Supercaptain
Jindřich Máca:6.9.2015 19:40

Aha, tak to jsem špatně pochopil. :-D Každopádně nevím, proč Ti to takhle blbne. Začal bych asi promazáním cache a případně potom zkusil od té výjimky dohledat její příčinu. Ovšem občas jsou ty výjimky nic neříkající... :-/

Editováno 6.9.2015 19:42
 
Odpovědět  +1 6.9.2015 19:40
Avatar
Milan Gallas
Redaktor
Avatar
Milan Gallas:5.10.2015 18:14

Ten řádek v routeFactory mě fakt potrápil

$router[] = new Route('[<action>/][<url>]', array(

Měl sem tam napsané

$router[] = new Route('[<action/>][<url>]', array(

a chybu jsem hledal asi hodinu :D :D
Ale spoň vím na co si dát příště pozor.

 
Odpovědět  +1 5.10.2015 18:14
Avatar
danhosek
Člen
Avatar
danhosek:26.3.2016 17:44

ahoj prosím o pomoc s RouteFactory.php přidal jsem do projektu Reference (-např.) ale nevím, jak tuto podstránku přidat do route tak, aby mi fungovala i administrace referencí i článků.
Děkuji za pomoc.

 
Odpovědět 26.3.2016 17:44
Avatar
danhosek
Člen
Avatar
danhosek:26.3.2016 22:42

upravil jsem RouterFactory takto dle specifikací:

<?php

/*  _____ _______         _                      _
*ANOTACE
*/

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('<action>/', array(
                        'presenter' => 'Core:Administration',
                        'action' => array(
                                // řetězec v URL => akce presenteru
                                Route::FILTER_TABLE => array(
                                        'administrace' => 'default',
                                        'prihlaseni' => 'login',
                                        'odhlasit' => 'logout',
                                        'registrace' => 'register'
                                ),
                                Route::FILTER_STRICT => true
                        )
                ));
        $router[] = new Route('reference/[<action>/][<url>]', array(
            'presenter' => 'Core:Reference',
            'action' => array(
                Route::VALUE => 'default',
                Route::FILTER_TABLE => array(
                    // řetězec v URL => akce presenteru
                    'reference' => 'list',
                    'editor' => 'editor',
                    'odstranit' => 'remove'
                ),
                Route::FILTER_STRICT => true
            ),
            'url' => null,
        ));
        $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;
    }
}

nyní je funkční přesměrování na výpis referencí i článků, ale reference se mi nevypisují
Ani administrace nefunguje. po pokusu uložit referenci s form action: /reference/editor/
jsem přesměrován na /chyba
Je vůbec možné upravit tento projekt tak, že jsem upravit article na reference a aby mi fungovala administrace k obojímu? Já si myslím, že je už problém pouze v RouterFactory, ale 100% si jistý nejsem. a lépe upravit router factory sám nedokážu.
Děkuji.

 
Odpovědět 26.3.2016 22:42
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na danhosek
Jindřich Máca:28.3.2016 22:30

Ahoj,
vezmu tvůj komentář asi od konce. Co se týče psaní routování v Nette, není to úplně snadné. Doporučoval bych poctivě pročíst dokumentaci - https://doc.nette.org/cs/2.3/routing a potom se třeba ještě podívat na nějaké příklady např. http://zlml.cz/…te-prakticky. Obecný postup je pak následující:

  • Sepsat si všechny URL adresy, které má / může můj web obsahovat.
  • Seřadit adresy od nejkonkrétnějších po nejobecnější a to kvůli pořadí jejich zpracování.
  • Zkontrolovat, jestli se někde částečně nepřekrývají a pokud ano, je potřeba to napravit. Zkrátka každá URL adresa na webu musí být unikátní.
  • Vymyslet jak svůj seznam URL adres nejoptimálněji zapsat do routeru. K tomu je potřeba dobrá znalost všech jeho vlastností viz. odkazy výše uvedené.

Další Tvoje otázka byla, jestli je routování v projektu možné upravit Tvým specifickým způsobem. Určitě ano, ale budeš k tomu muset využít postup uvedený výše.

Abych Ti pomohl, dal jsem si tu práci a analyzoval jsem kód, který jsi uvedl, plus jsem v něm udělal pár úprav. ;) Vyložená chyba tam není, otázka zní, jestli to dělá to, co by jsi od toho očekával. Onu analýzu můžeš najít zde - http://www.itnetwork.cz/dev-lighter/703. Zkrátka zadaná adresa prochází seznam, přesně tak, jak jsem to očísloval a pokud se najde shoda, je zavolána akce presenteru s danými parametry.

Pokud je vše, jak má být, ještě bych ověřil pomocí laděnky (Tracy), že dané URL se opravdu mapují správně. Laděnka Ti při jejich zadání vypíše všechny podrobnosti. :)

Pokud vše souhlasí, chyba bude opravdu s největší pravděpodobností někde jinde, obzvlášť např. u toho odesílání formuláře bych ji nehledal v routeru. Bohužel, bez dalších zdrojových kódů projektu Ti nedokážu říct více.

Na závěr Ti popřeji hodně štěstí a pevné nervy! :D

 
Odpovědět  +1 28.3.2016 22:30
Avatar
danhosek
Člen
Avatar
Odpovídá na Jindřich Máca
danhosek:29.3.2016 22:17

sepsal jsem si ty odkazy na webu a zjistil jsem problem u editoru článků a editoru referencí. Podle Url nelze zjistit, zda jde o referenci nebo článek:
/editor/ //Editor článku

/editor/ //uložení nového článku
editor/clanek1 //odkaz na editaci čánku + uložení změn článku
/odstranit/clanek1 //smazání článku
u reference ty odkazy vypadají stejně.
Mydlim, že tento problem by vyřešily změny v routovacím poly:
$router[] = new Route('[<acti­on>/][<url>]', array(
'presenter' => 'Core:Reference',
'action' => array(
Route::VALUE => 'default',
Route::FILTER_TABLE => array(
// řetězec v URL => akce presenteru
'reference' => 'list',
'editor_ref' => 'editor',
'odstranit_ref' => 'remove'
),
Route::FILTER_STRICT => true
),
'url' => null,
));
Stačilo by to? nebo by to nerozeznalo, zda jde o referenci nebo článek?

 
Odpovědět 29.3.2016 22:17
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na danhosek
Jindřich Máca:29.3.2016 22:35

Ahoj,
díky tomu, že tam máš Route::FILTER_STRICT => true, což znamená, že to bere pouze explicitně uvedené routy a nic jiného (pak to pokračuje dál), by tohle mělo stačit. :) Ostatně, proč to nevyzkoušíš sám? ;)

 
Odpovědět 29.3.2016 22:35
Avatar
danhosek
Člen
Avatar
danhosek:18.10.2016 17:51

Ahoj, jak mohu v ContactPresenter nastavit formuláři id nebo class? abych docílil tohodle? <form id="formular" class="formular">?? nebo lze definovat v latte element div? Abych mohl mít něco podobného?

<div class="formular">
    {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}
</div>

hledal jsem v dokumentacích a forech ale nic jsem nenašel. Všede se řeší pouze set atrubute u inputů.
Děkuji.

 
Odpovědět 18.10.2016 17:51
Avatar
danhosek
Člen
Avatar
Odpovídá na danhosek
danhosek:18.10.2016 17:58

nebo v latte {define title}Kontaktní formulář{/define} -> h1.. můžu tomu naspisu nastavit id nebo class?

 
Odpovědět 18.10.2016 17:58
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na danhosek
Jindřich Máca:19.10.2016 23:26

No nazdar! :D

Pokud chceš v HTML přiřadit elementu, jako např. div, id nebo class, je to v pohodě. Ale to samotné použití div v uvedeném příkladu Latte šablony je špatné ve všech směrech. Ta šablona definuje 3 nezávislé bloky, konkrétně title, description a content, jejichž obsah se dosadí do celkové šablony layoutu. Pokud to takhle obalíš tím div, tak jeho první část se vůbec nepoužije a ta druhá </div> se vloží do bloku content a ve výsledné HTML struktuře nadělá kompletní paseku.

Tohle bylo spíš varování s vysvětlením, aby jsi Ty, ani nikdo jiný, tohle v kódu nedělal a teď k odpovědi na otázku. Formuláři se class dá nastavit poměrně jednoduše pomocí parametru:

{control contactForm, class => 'formular'}

Zato id mu automaticky generuje Nette a to bys nejlépe měnit vůbec neměl. Naopak by ses tomu měl podřídit, jelikož se podle toho provádí např. i mapování odeslaných hodnot. Zkrátka Nette formuláře mají vždy vlastní generované id a neměl by jsi to měnit, pokud přesně nevíš, co děláš. ;)

A k té druhé otázce ohledně nastavení id nebo class u definice bloku. Ne, tady se to přímo nijak nastavit nedá, jak už jsem psal, ten obsah toho bloku se celý vezme a vloží na příslušné místo do celkového layoutu. Ten blok samotný ale není reprezentovaný žádným HTML elementem, takže mu logicky nejdou přiřadit žádné HTML vlastnosti. :)

Obecně, pokud by jsi chtěl měnit třídu u nadřazeného elementu daného bloku, musel by jsi to udělat jedině nějakou volitelnou hodnotou, mimo ten blok, která by se dosazovala na správné místo v šabloně nadřazené.

Doufám, že to takhle vysvětlené dává smysl a že v tom najdeš odpovědi, které jsi hledal, když tak se hold budeš muset ptát dále.

 
Odpovědět  +1 19.10.2016 23:26
Avatar
danhosek
Člen
Avatar
Odpovídá na Jindřich Máca
danhosek:20.10.2016 0:46

děkuji za odpověď, je to přesně to co jsem potřeboval..
jinak, když jsem čekal na odpověď, zkoušel jsem různá řešení a zkusil toto:

<div class="kontaktni_formular">
    {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. *}
      <div id="form-main">
        <div id="form-div">
            <div class="container">

                {control contactForm}
            </div>
        </div>
    </div>
</div>

<div class="kontak­tni_formular"> se opravdu nevipisoval, ale <div id="form-main">, <div id="form-div">, <div class="container"> , které jsou už v bloku {block content}, tak jsem na toto přišel metodou pokus omyl sám.(ten pokus/omyl slyšíš nerad co?):-D

 
Odpovědět  +1 20.10.2016 0:46
Avatar
CZkiniCZ
Člen
Avatar
CZkiniCZ:5.1.2017 10:22

Ahoj. Jak by se dal mail odeslat více lidem když chci zadat adresáty přez formulář?

Odpovědět 5.1.2017 10:22
Age of the geek.
Avatar
Jan Říha
Člen
Avatar
Jan Říha:2.2.2017 20:30

Ahoj,
přes formulář ukládám článek do tabulky article:
INSERT INTO article (article_id, title, url, description, content)
VALUES ('', 'aaa', 'aaa', 'aaa', '<p>aaaaaa</p>')
vypíše se chyba:
General error: 1366 Incorrect integer value: '' for column 'article_id' at row 1.
Chápu, kde je chyba. Nevím, jak ji odstranit.

 
Odpovědět 2.2.2017 20:30
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Říha
Jindřich Máca:2.2.2017 20:50

Ahoj,

tahle chyba spíš souvisí s SQL než s Nette jako takovým. Tvůj SQL kód:

INSERT INTO article (article_id, title, url, description, content)
VALUES ('', 'aaa', 'aaa', 'aaa', '<p>aaaaaa</p>');

Proč posíláš do hodnoty article_id, která je očividně celé číslo, prázdný textový řetězec? :D A pak ještě hned pod tím napíšeš toto:

Chápu, kde je chyba. Nevím, jak ji odstranit.

Tak to prostě nedělám a to SQL bude vypadat takto:

INSERT INTO article (title, url, description, content)
VALUES ('aaa', 'aaa', 'aaa', '<p>aaaaaa</p>');

Chyba odstraněna. ;)

Každopádně, pokud Ti tenhle kód nebude fungovat, tak máš špatně navrženou tu samotnou databázovou tabulku. Standardní postup při tvorbě SQL tabulek s indexem je, že se tento index nechává přiřazovat automaticky, tudíž se mu nastaví AUTO_INCREMENT a v INSERT dotazech se pak může právě úplně vynechat. :)

 
Odpovědět 2.2.2017 20:50
Avatar
Jan Říha
Člen
Avatar
Jan Říha:3.2.2017 18:12

Ahoj,
postupuji podle návodu Jednoduchý redakční systém v Nette. Dodělal jsem 8. díl - Dokončení administrace.
Na úvodní stránce vyberu Administrace, Editor článků, vyplním pole Titulek, URL, Popisek, Obsah a dám Uložit článek. Vyskočí mnou víše popisovaná chyba.

Předpokládám, že problém souvisí s metodou createComponen­tEditorForm(), skrytým polem article_id, které se metoda editorFormSucceeded snaží uložit do tabulky article jako prázdný text.
Doplnil jsem:
$form->addHidden('ar­ticle_id')->addRule(Form::IN­TEGER);
Opět nejde uložit. Nad formulářem vyskočí: Please enter a valid integer.
Tabulku article jsem zakládal podle create_article.sql.
Hostuji na wedos.
Honza

 
Odpovědět 3.2.2017 18:12
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Říha
Jindřich Máca:3.2.2017 21:15

Chápu, takže to je chyba v kontextu toho formuláře. Každopádně to přidání pravidla k tomu skrytému poli není ve směs špatná myšlenka, ale v tomhle kontextu je to dost nepoužitelné, protože ten prázdný formulář tam to article_id nikdy nemá nastavené, tudíž to nemůže být číslo. :)

Takže, pokud se vrátíme k té původní chybě, tak já jsem teď stáhl místní archiv, rozchodil znovu lokálně, zopakoval Tebou uvedený postup a vše prošlo bez chyby. :D Takže jakou máš verzi PHP, popřípadě verzi databáze? A opravdu jsi v tom projektu vůbec nic neměnil?

 
Odpovědět 3.2.2017 21:15
Avatar
Jan Říha
Člen
Avatar
Jan Říha:3.2.2017 22:33

PHP Version 5.6.29-0+deb8u1,
innodb_version 5.7.17,
Snažil jsem se nic neměnit.
Google pro výše uvedenou chybu doporučuje: sql_mode nemá být strict.
Nevím, zda-li to s tím souvisí, ale phpinfo() říká: session.use_stric­t_mode Off Off.
Když v ArticlePresen­ter.php odstraním řádek
$form->addHidden('ar­ticle_id')->addRule(Form::IN­TEGER);
chyba: Undefined property: Nette\Utils\A­rrayHash::$ar­ticle_id, která ukazuje také do ArticleManager.php metody public function saveArticle($ar­ticle) na řádek if (!$article[sel­f::COLUMN_ID])
Když do metody saveArticle($ar­ticle) vložím pouze:
$this->database->table(self::TAB­LE_NAME)->insert($article);
pak se článek uloží.

 
Odpovědět 3.2.2017 22:33
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Jan Říha
Jindřich Máca:4.2.2017 18:16

To, co popisuješ, se všechno chová tak, jak by mělo. Pro tu chybu je asi tady opravdu nutné vypnout striktní mód databáze tak, jak napovídá Google. Ovšem session.use_stric­t_mode s tím nemá nic společného, to je nastavení módu pro PHP Sessions. ;)

 
Odpovědět 4.2.2017 18:16
Avatar
Jan Říha
Člen
Avatar
Jan Říha:4.2.2017 21:02
  1. odstranil jsem: ->addRule(Form::IN­TEGER),
  2. na serveru jsem vytvořil soubor: /etc/mysql/con­f.d/disable_stric­t_mode.cnf
  3. do souboru jsem zapsal:

[mysqld]
sql_mode=IGNO­RE_SPACE,NO_ZE­RO_IN_DATE,NO_ZE­RO_DATE,ERROR_FOR_DI­VISION_BY_ZERO,NO_A­UTO_CREATE_USER,NO_EN­GINE_SUBSTITU­TION

  1. restartoval jsem mysql: service mysql restart

a funguje to.
Dík za odpovědi.

 
Odpovědět  +1 4.2.2017 21:02
Avatar
Karl
Člen
Avatar
Karl:15.2.2017 10:55

Jindro a jak Ty máš nastavené my.ini ?

mám WAMP s PHP 7.0.10 a MySQL 5.7.14
když nastavím v my.ini sql-mode="" tak to funguje
když to nechám default, tedy zakomentuji v my.ini ;sql-mode="" (zakomentován) tak to nefunguje

jinak toto mi nepomohlo sql-mode=„NO_AUTO_VA­LUE_ON_ZERO“ – chybu to házelo dále

Kárl

 
Odpovědět 15.2.2017 10:55
Avatar
Karl
Člen
Avatar
Odpovídá na Karl
Karl:15.2.2017 11:13

a pokud to udělám jako p.Říha, (tedy sql_mode=IGNO­RE_SPACE,NO_ZE­RO_IN_DATE,NO_ZE­RO_DATE,ERROR_FOR_DI­VISION_BY_ZERO,NO_A­UTO_CREATE_USER,NO_EN­GINE_SUBSTITU­TION)

tak mi to vyhodí chybu:

Integrity constraint violation: 1048 Column 'product_id' cannot be null

 
Odpovědět 15.2.2017 11:13
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Karl
Jindřich Máca:15.2.2017 19:39

Já to mám obecně trochu jinak, protože používám Linux. Každopádně mám klasické php.ini a zde jednoduše nastavené:

sql.safe_mode = Off

Více informací - http://php.net/…ini.core.php#… ;)

Nicméně, když jsi použil řešení od Jan Říha, tak to pravděpodobně fungovalo, ale máš tam potom ještě jinou chybu a to nejspíše v chybějícím ID. :)

 
Odpovědět 15.2.2017 19:39
Avatar
Karl
Člen
Avatar
Karl:15.2.2017 20:49

Nicméně mě tuto chybu háže každý insert v celém projektu Nette Eshop - stažen zip z posledního dílu s nahrazením Nette za 2.4

háže mi to jak localhost tak i na hostingu (Savana)
a jelikož to druhým funguje, musí to být někde v nastavení, aby MySQL nevadilo, že zadávám ´´ a místo toho zafungoval autoincrement

snad kvůli tomu nebudu přepisovat všechny inserty, navíc nevím jestli to pak neudělá paseku při editaci záznamu, tam se přeci id zase musí předávat

respektive nastavení v my.ini (překvapuje mě že ho nemáš) mě to s tímto nastavením
sql-mode="" funguje, jenom nevím, co jsem tím ještě ovlivnil

ještě podotknu, že to nastavení, kdy mi to vyhazuje chybu je default nastavení nejnovějšího WAMPu

 
Odpovědět 15.2.2017 20:49
Avatar
Vakos
Redaktor
Avatar
Vakos:21.2.2017 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.2.2017 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.2.2017 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.2.2017 19:45
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:21.2.2017 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.2.2017 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.2.2017 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.2.2017 20:18
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:21.2.2017 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.2.2017 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.2.2017 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.2.2017 20:46
Avatar
Karl
Člen
Avatar
Odpovídá na Jindřich Máca
Karl:22.2.2017 9:42

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

 
Odpovědět 22.2.2017 9:42
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Karl
Jindřich Máca:22.2.2017 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.2.2017 22:39
Avatar
SolusLupusUmbra
Redaktor
Avatar
SolusLupusUmbra:11.7.2017 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.7.2017 23:13
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na SolusLupusUmbra
Jindřich Máca:11.7.2017 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.7.2017 23:26
 
Odpovědět 11.7.2017 23:25
Avatar
Vaclav Hrouda
Redaktor
Avatar
Vaclav Hrouda:4.8.2018 18:18

Tak jsem si stáhl přiložený soubor a:

Fatal error: Cannot use 'Object' as class name as it is reserved in /mnt/drive/www/net­te/rs-nette/vendor/net­te/utils/src/U­tils/Object.php on line 54

Myslím že takhle by to vypadat nemělo...

 
Odpovědět 4.8.2018 18:18
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Vaclav Hrouda
David Čápka:4.8.2018 18:48

Ahoj, autor Nette se rozhodl použít slovo object a proto verze 2.3 přestala od PHP 7 fungovat. Jsme v tom tedy tak trochu nevinně. Na aktualizaci kurzu pro opravené Nette se pracuje. Řešením je buď downgrade PHP na verzi 5 nebo proklikat diskuze lekcí, kde se řeší jak to opravit.

Editováno 4.8.2018 18:49
Odpovědět  +1 4.8.2018 18:48
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:6.8.2018 13:25

Aktualizováno pro Nette 2.4.

Odpovědět 6.8.2018 13:25
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Marty
Člen
Avatar
Marty:26.10.2018 23:22

Je normální, že načtení na localhostu je kolem 500 ms?

 
Odpovědět 26.10.2018 23:22
Avatar
AlenaZ
Člen
Avatar
AlenaZ:3. dubna 13:03

Service 'application.2' (type of App\CoreModule\Pre­senters\Article­Presenter): Parameter $defaultArticleUrl in App\CoreModule\Pre­senters\Article­Presenter::__con­struct() has no class type hint or default value, so its value must be specified.
Děkuji za pomoc.

 
Odpovědět 3. dubna 13:03
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na AlenaZ
patrik.valkovic:3. dubna 13:22

Ahoj, nastavila jsi službu správně v konfiguračním souboru? Tj. defaultArticleUrl: 'uvod' do parametrů a - App\CoreModule\Presenters\ArticlePresenter(%defaultArticleUrl%) při vytváření služby? Viz. článek.

Editováno 3. dubna 13:23
Odpovědět 3. dubna 13:22
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
AlenaZ
Člen
Avatar
AlenaZ:3. dubna 14:27

Dokonce jsem si stáhla zip a chyba byla pořád:
app/CoreModule/con­fig/config.ne­on
parameters:
defaultArticleUrl: 'uvod' # URL výhozího článku
# Nastavení služeb pro CoreModule.
services:
# Definice vlastních služeb dále přístupných pomocí DI.
- App\CoreModule\Mo­del\ArticleMa­nager

# Předání nastavení při vytváření služeb presenterů.
- App\CoreModule\Pre­senters\Article­Presenter(%de­faultArticleUr­l%)

Bere to jedině tady
public function __construct($de­faultArticleUr­l='uvod',Arti­cleManager $articleManager)

V configu to nevidí.

 
Odpovědět 3. dubna 14:27
Avatar
AlenaZ
Člen
Avatar
Odpovídá na AlenaZ
AlenaZ:3. dubna 17:57

bootstrap.php

$configurator->addConfig(__DIR__ . '/CoreModule/config/config.neon');
 
Odpovědět 3. dubna 17:57
Avatar
Jaroslav Patrný:30. června 3:58

Ahoj, nemůžu najít chybu. Soubory mám všechny, včetně ContactPresenteru. Poradí mi prosím někdo?

 
Odpovědět 30. června 3:58
Avatar
Odpovídá na Jaroslav Patrný
Jaroslav Patrný:30. června 18:58

Vyřešeno - už jsem se s tím vypořádal.

 
Odpovědět 30. června 18:58
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 57 zpráv z 57.