Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij podzimní akce 30% výuky zdarma!
Pouze tento týden sleva až 80 % na e-learning týkající se JavaScript
JavaScript týden

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/@la­yout.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
 *}
<!DOCTYPE html>
<html lang="cs">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="{include description|striptags}">

        <title>{include title|striptags}</title>

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

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

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

        {* Výpis flash 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}
            <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
            <script src="{$basePath}/js/main.js"></script>
        {/block}
    </body>
</html>

app/CoreModule/tem­plates/Article/de­fault.latte

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

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ůžete zkusit web spustit a měli byste 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

Model máme již nachystaný z minula, takže začneme rovnou od presenterů.

app/CoreModule/pre­senters/Article­Presenter.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\AbortException;
use Nette\Application\BadRequestException;
use Nette\Application\UI\Form;
use Nette\Database\UniqueConstraintViolationException;
use Nette\Utils\ArrayHash;

/**
 * Presenter pro akce s články.
 * @package App\CoreModule\Presenters
 */
class ArticlePresenter extends BasePresenter
{
    /** @var string URL výchozího článku. */
    private $defaultArticleUrl;

    /** @var ArticleManager Model pro správu s článků. */
    private $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($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($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($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($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/pre­senters/Adminis­trationPresen­ter.php

Ještě než dnes skončíme s presentery, vytvoříme si jeden prázdný pro administrační sekci. Prázdný bude proto, že v tuto chvíli v podstatě nepotřebujeme do jeho šablony nic předávat:

<?php

namespace App\CoreModule\Presenters;

use App\Presenters\BasePresenter;

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

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 :)


 

Předchozí článek
Jednoduchý redakční systém v Nette - Výpis článku
Všechny články v sekci
Základy Nette frameworku
Článek pro vás napsal Jindřich Máca
Avatar
Jak se ti líbí článek?
13 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 (6)

 

 

Komentáře

Avatar
Raiper34
Redaktor
Avatar
Raiper34:17.8.2015 12:53

Jednu vec nechapem, tie actionRemove, ako sa vykonavaju, kde? Alebo to je len zatial nachystane do buducna?

Odpovědět
17.8.2015 12:53
Posledná vydaná hra: http://www.islandsoft.cz/index.php?art=hra-akcna-space-resistance
Avatar
Odpovídá na Raiper34
Martin Konečný (pavelco1998):17.8.2015 13:21

Metody action() se volají automaticky.
Tady o tom máš článek

http://doc.nette.org/…3/presenters

Přesněji si všimni tohoto obrázku:
http://files.nette.org/…fecycle2.gif

Tzn. když navštívíš stránku, prvně se zavolá metoda startup(), pak action<name>(), handle<signal>() atd.
V tomto případě by actionRemove() spíš mělo být handleRemove(), ale udělá to to stejné.

Odpovědět
17.8.2015 13:21
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Raiper34
Redaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Raiper34:17.8.2015 15:44

Ah uz chapem, ono to tam nerobi nic len odstrani a redirectuje, ono to action a render je to iste skoro vsak, akurat jendo sa pouziva na to a jedno na to kvoli prehladnosti

Odpovědět
17.8.2015 15:44
Posledná vydaná hra: http://www.islandsoft.cz/index.php?art=hra-akcna-space-resistance
Avatar
Odpovídá na Raiper34
Martin Konečný (pavelco1998):17.8.2015 15:51

Přesně tak. Na úpravu dat by se měly používat signály, ne akce, ty jsou spíš třeba pro naplnění defaultních hodnot formuláře atd., ale z technického hlediska je jedno, kam to dáš, bude to fungovat tak jako tak.

Odpovědět
17.8.2015 15:51
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Tomáš Smolka:25.8.2015 8:45

Ahoj,
zkoušel jsem postupovat podle tutoriálu. Ale když přes Chrome spustím k testu web, chybí mi tam vzhled CSS (viz příloha). Nevíte kde je chyba. Díky za info.

 
Odpovědět
25.8.2015 8:45
Avatar
Jindřich Máca
Redaktor
Avatar
Odpovídá na Tomáš Smolka
Jindřich Máca:6.9.2015 15:41

Ahoj, podobný problém už jsme tady řešili. Zkus si promazat cache, případně si pohrát s linky na styly v souboru @layout.latte. ;-)

 
Odpovědět
6.9.2015 15:41
Avatar
saavikam
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
saavikam:23.2.2016 14:06

Mám trošku zmatek ve funkcích prezenteru

  • render* jsou použité pro zobrazení dat
  • action* pro editaci, mazání apod?

Je to tak?

A v ArticlePresenter je ve funkci actionEditor použito $this['editor­Form']... kde se prosím bere editorForm? Nemůžu to najít.

Děkuji

Andrea

 
Odpovědět
23.2.2016 14:06
Avatar
Odpovídá na saavikam
Dominik Gavrecký:23.2.2016 14:11

Ahoj Andrea,

presne ako hovoríš render sa používa v prípade že chceš vykresliť nejaké údaje napríklad cez foreach. Action používaš v prípade že daná funkcia vykoná nejakú akciu (zmazanie, editovanie atď.)

A k druhej časti tvojej otázky, tuník vytvoril komponentu ktorá sa sa stará o vytvorenie formulára. Formulár si nazval editorForm. A potom si už len použil údaje z pola formulára ktoré vytvoril.

Kľudne sa môžem mýliť ak áno opravte ma niekto.

Odpovědět
23.2.2016 14:11
Hlupák nie je ten kto niečo nevie, hlupákom sa stávaš v momente keď sa na to bojíš opýtať.
Avatar
saavikam
Člen
Avatar
saavikam:23.2.2016 14:24

proto se následující funkce jmenuje createComponen­tEditorForm?

 
Odpovědět
23.2.2016 14:24
Avatar
Odpovídá na saavikam
Dominik Gavrecký:23.2.2016 15:00

createComponent ti vytvorí komponentu a EditorForm už je názov tej komponenty. Ak by ťa zaujímalo niečo viac tak https://doc.nette.org/cs/2.3/forms

Odpovědět
23.2.2016 15:00
Hlupák nie je ten kto niečo nevie, hlupákom sa stávaš v momente keď sa na to bojíš opýtať.
Avatar
Jindřich Máca
Redaktor
Avatar
Odpovídá na saavikam
Jindřich Máca:23.2.2016 15:13

Ahoj,

je to přesně tak, jak říká Dominik Gavrecký.

  • Mezi action*() a render*() je jediný technický rozdíl a to, že action*() se pro danou akci (to co se dosadí za *) presenteru vykonává dřív než render*(). Potom je tady nějaká konvence (ne pravidlo), že v render*() by se měli předávat data do šablony a obecně řešit operace ohledně vykreslování stránky, zato v action*() by se mělo řešit například plnění komponent (formuláře) výchozími daty nebo přesměrování (logicky dřív, než se začne stránka vykreslovat). Dále nic nezabraňuje tomu, aby existovala např. actionDefault() a renderDefault() najednou v tom samém presenteru. Poté se akorát vykonávají v daném pořadí a měli by (nemusí) dodržovat výše popsané rozdělení zodpovědností.
  • K úplnému pochopení odpovědi na ten druhý dotay, bude možná lepší nejdříve objasnit, jak funguje vztah prezenterů a komponent. Každý presenter může obsahovat libovolné množství různých komponent. Jejich instance poté uchovává ve svém "vnitřním poli" (implementuje totiž interface ArrayAccess). A jak dané instance získává? Při jeho životním cyklu (viz. https://doc.nette.org/…3/presenters#…), konkrétně po metodě startup(), je vytváří podle všech metod z předpisem createComponen­t*() a pojmenovává je podle jejich názvu, tedy to co je v tomto případě * (pozor, mění se tady počáteční písmeno názvu na malé a důrazně se to rozlišuje). Poté, tedy už v libovolné action*() případně i render*(), je tedy k dispozici instance dané komponenty přes ono "vnitřní pole" presenteru a to právě pomocí $this[*] (kde * je právě název komponenty, pouze s počátečním malým písmenem). Ale znalost práce s třídami implementujícími ArrayAccess se již předpokládá ze standardního OOP v PHP. :)

Tak to bylo docela vyčerpávající, ale pokud by byli další dotazy, neváhej se zeptat. ;)

 
Odpovědět
23.2.2016 15:13
Avatar
saavikam
Člen
Avatar
saavikam:25.2.2016 18:08

Děkuju, už je mi to jasné. Andrea

 
Odpovědět
25.2.2016 18:08
Avatar
rosatislav
Člen
Avatar
rosatislav:14.9.2016 10:23

Zdravím, celkem by mně zajímalo tohle:

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.');
                }

přesněji článek s touto URL adresou již existuje.
Nedokážu moc pochopit, jak může k takové chybě dojít. Chápu, že je to asi myšleno, že pokud by při editaci někdo změnil kolonku URL adresy za stejnou, která v databázi už je, tak by to nemělo projít. Nikde jsem ovšem nenašel ošetření, kde by se ověřovalo, zda-li jsme nezadali takovou url, která by již byla použita (pokud se to teda neřeší až v dalších článcích)

 
Odpovědět
14.9.2016 10:23
Avatar
rosatislav
Člen
Avatar
Odpovídá na rosatislav
rosatislav:14.9.2016 11:17

Aha, tak už jsem na to přišel... taková ostuda :D je to dáno už z definice v předchozím článku

ADD UNIQUE KEY `url` (`url`);

každopádně, pokud bych se mohl zeptat, tak co dělá přesně třída UniqueConstra­intViolationEx­ception?

Editováno 14.9.2016 11:18
 
Odpovědět
14.9.2016 11:17
Avatar
Petr Linhart
Člen
Avatar
Odpovídá na rosatislav
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
14.9.2016 15:10
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
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
Redaktor
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
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
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.2.2017 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.2.2017 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
Redaktor
Avatar
Odpovídá na Vakos
Jindřich Máca:8.2.2017 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.2.2017 23:29
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:8.2.2017 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.2.2017 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
Redaktor
Avatar
Odpovídá na Vakos
Jindřich Máca:8.2.2017 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
8.2.2017 23:49
Avatar
Vakos
Redaktor
Avatar
Odpovídá na Jindřich Máca
Vakos:9.2.2017 9:55

Jj, to je ono, děkuji.

Odpovědět
9.2.2017 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...
Avatar
Miroslav Mucha:11.4.2018 15:46

Ahoj, už několik dní si lámu hlavu s jedním problémem. Při vkládání nového řádku do DB se data uloží a následně se přesměruje se na šablonu show, kde se nově uložený záznam zobrazí. Vše je v pořádku jak ve vykreslené šabloně, tak v databázi.
Pokud ale edituji již dříve uložený záznam, změny se správně uloží do databáze, ale přesměrování se nepodaří. Laděnka vypisuje chybu: Trying to get property of non-object.
Pro nový záznam i editaci je stejný formulář, načítání a zobrazování záznamů je v pořádku.

Presenter (část):

public function projektFormSucceeded($form, $values)
        {
                $projektId = $this->getParameter('projektId');
                $values['datum_odevzdani'] = DateTime::from($values['datum_odevzdani']);
                $projekt = $this->projektManager->saveProjekt($values, $projektId);
                $this->flashMessage("Projekt byl úspěšně uložen.", 'success');
                $this->redirect('show', $projekt->projekt_id);
        }

        public function actionEdit($projektId)
        {
                $projekt = $this->projektManager->getProjekt($projektId);
                if (!$projekt) {
                        $this->error('Projekt nebyl nalezen');
                }else{
                        $this['projektForm']->setDefaults($projekt);
                }
        }

Model:

public function saveProjekt($values, $projektId)
        {
                if(!$projektId) {
                        $projekt = $this->data->insert($values);
                }else{
                        $projekt = $this->data->where('projekt_id', $projektId)->update($values);
                }
                return $projekt;
        }
 
Odpovědět
11.4.2018 15:46
Avatar
Jindřich Máca
Redaktor
Avatar
Odpovídá na Miroslav Mucha
Jindřich Máca:11.4.2018 18:28

Ahoj, pokud se nepletu, tak problém vzniká tady:

public function saveProjekt($values, $projektId) {
        if (!$projektId) {
                // Metoda insert vrací nový vložený řádek.
                $projekt = $this->data->insert($values);
        } else {
                // Metoda update nevrací upravený řádek, ale číslo, reprezentující počet upravených řádek.
                $projekt = $this->data->where('projekt_id', $projektId)->update($values);
        }
        return $projekt;
}

A následně to vede k chybě, neboť při editaci dostaneš z metody saveProjekt() pouze číslo a ne objekt jako u vkládání. Následně na tomto číslu voláš přístup k atributu $projekt->projekt_id v rámci toho přesměrovaní, což samozřejmě vede k oné chybě, kterou Ti to píše... :)

Pokud bych do toho mohl mluvit, celkově bych předělal tu práci s ID. Už to, že ho při odeslání formuláře bereš z parametru, zavání potenciálním průšvihem. :-`

 
Odpovědět
11.4.2018 18:28
Avatar
Jindřich Máca
Redaktor
Avatar
Jindřich Máca:11.4.2018 18:31

Jinak informace o tom, jak se chovají ty metody insert(), update() apod. lze najít v oficiální programátorské dokumentaci Nette (API) - https://api.nette.org/…lection.html ;)

 
Odpovědět
11.4.2018 18:31
Avatar
Odpovídá na Jindřich Máca
Miroslav Mucha:11.4.2018 19:11

Vřelé díky za odpověď, bude to ono, protože když jsem si v Laděnce ukázal na proměnnou $projekt, ukázalo mi to jedničku a nedošlo mi proč. Dokumentaci jsem procházel, ale asi jsem se nechal zmást příklady, kde je rovněž použita metoda update, ale přeci jen trochu jinak.
Ještě jednou díky :-)

 
Odpovědět
11.4.2018 19:11
Avatar
Marty
Člen
Avatar
Marty:30.10.2018 16:01

Pochopil jsem správně, že

public function renderDefault($url = null)

znamená, že do $url se nepřiřazuje null, ale pouze se tím říká, že parametr může být null?

 
Odpovědět
30.10.2018 16:01
Avatar
Jindřich Máca
Redaktor
Avatar
Odpovídá na Marty
Jindřich Máca:30.10.2018 16:18

Ne tak docela. Znamená to, že pokud nebude tento argument metody zadán, nastaví se místo toho na null. Z toho pak logicky plyne, že může být null, ale teoreticky i cokoliv jiného, neboť PHP je dynamicky typovaný jazyk. Ale tohle by jsi už měl vědět, protože to patří do základů PHP viz. http://php.net/…rguments.php#… :-`

 
Odpovědět
30.10.2018 16:18
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 30 zpráv z 30.