Úvodní stránka blogu

Nyní si vytvoříme úvodní stránku zobrazující poslední příspěvky.

Než začneme, je zapotřebí znát alespoň základy návrhového vzoru Model-View-Presenter (podobné jako MVC):

  • Model – vrstva pracující s daty. Je kompletně oddělena od zbytku aplikace. Komunikuje pouze s presenterem.
  • View – front-end vrstva. Vykresluje požadovaná data pomocí šablon a zobrazuje je uživateli.
  • Presenter (nebo Controller) – propojovací vrstva. Presenter propojuje Model a View. Zpracovává požadavky, dotazuje se Modelu na data a vrací je zpět do View.

V případě jednoduchých aplikací, jako bude náš blog, budou celou modelovou vrstvu tvořit jenom dotazy do databáze – na to zatím žádný extra kód nepotřebujeme. Pro začátek si tedy vytvoříme jenom presentery a šablony. V Nette má každý presenter své vlastní šablony, takže je budeme vytvářet zároveň.

Vytvoření databáze pomocí Admineru

Pro ukládání dat použijeme MySQL databázi, protože je nejvíce rozšířená mezi programátory webových aplikací. Pokud ji však použít nechcete, klidně si zvolte databázi dle vlastního uvážení.

Nyní si připravíme databázovou strukturu, kde budou uloženy články našeho blogu. Začneme velmi jednoduše – vytvoříme si pouze jednu tabulku pro příspěvky.

Pro vytvoření databáze si můžeme stáhnout Adminer, nebo jiný váš oblíbený nástroj pro správu databází.

Otevřeme si Adminer a vytvoříme novou databázi s názvem quickstart.

Vytvoříme novou tabulku s názvem posts a s těmito sloupci:

  • id int, zaškrtneme na autoincrement (AI)
  • title varchar, length 255
  • content text
  • created_at timestamp

Výsledná struktura by měla vypadat takto:

CREATE TABLE `posts` (
    `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `title` varchar(255) NOT NULL,
    `content` text NOT NULL,
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;

Je opravdu důležité použít úložiště InnoDB. Za chvilku si ukážeme proč. Prozatím ji jednoduše vyberte a klikněte na uložit.

Než vytvoříme možnost přidávat články do databáze pomocí aplikace, přidejte několik vzorových článků na blogu ručně.

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1, 'Article One',  'Lorem ipusm dolor one',    CURRENT_TIMESTAMP),
(2, 'Article Two',  'Lorem ipsum dolor two',    CURRENT_TIMESTAMP),
(3, 'Article Three',    'Lorem ipsum dolor three',  CURRENT_TIMESTAMP);

Připojení k databázi

Nyní, když je již databáze vytvořena a máme v ní uloženo pár článků, je ten správný čas zobrazit je na naší krásné nové stránce.

Prvně musíme aplikaci říct, jakou databázi má použít. Připojení k databázi nastavíme v souboru app/config/config.neon pomocí DSN a přihlašovacích údajů. Mělo by to vypadat nějak takto:

database:
    dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
    user: root
    password: *zde vložte heslo k databázi*

Při editování tohoto souboru dávejte pozor na odsazení řádků. NEON formát akceptuje jak odsazení pomocí mezer, tak odsazení pomocí tabulátorů, ale ne obojí zároveň. Výchozí konfigurační soubor ve Web Projectu využívá tabulátory.

Veškerá konfigurace včetně konfigurace databáze je uložena v adresáři /app/config/ v souborech config.neon a config.local.neon. Soubor config.neon obsahuje globální nastavení aplikace a config.local.neon pouze ty parametry, které jsou specifické pro aktuální prostředí (rozdíl mezi vývojovým a produkčním serverem apod.).

Předání databázového spojení

Presenter (soubor app/presenters/HomepagePresenter.php), který se bude starat o výpis článků, potřebuje připojení k databázi. Pro jeho získání využijeme konstruktor, který bude vypadat takto:

namespace App\Presenters;

use Nette;


class HomepagePresenter extends Nette\Application\UI\Presenter
{
    /** @var Nette\Database\Context */
    private $database;

    public function __construct(Nette\Database\Context $database)
    {
        $this->database = $database;
    }

    // ...
}

Načítání příspěvků z databáze

Nyní načteme příspěvky z databáze a pošleme je do šablony, která je následně vykreslí jako HTML kód. Pro tohle je určena takzvaná render metoda:

public function renderDefault()
{
    $this->template->posts = $this->database->table('posts')
        ->order('created_at DESC')
        ->limit(5);
}

Presenter nyní obsahuje jednu renderovací metodu renderDefault(), která předává data z databáze do šablony (View). Šablony jsou umístěny v app/presenters/templates/{PresenterName}/{viewName}.latte, takže v tomto případě je šablona umístěna v app/presenters/templates/Homepage/default.latte. V šabloně nyní bude k dispozici proměnná $posts, ve které jsou příspěvky získané z databáze.

Šablona

Pro celou webovou stránku máme k dispozici hlavní šablonu (která se jmenuje layout, obsahuje hlavičku, styly, patičku,…) a dále konkrétní šablony pro každý pohled (View) (např. pro zobrazení příspěvků na blogu), které mohou přepsat některé části hlavní šablony.

Ve výchozím stavu je layout šablona umístěna v app/presenters/templates/@layout.latte a obsahuje:

...
{include content}
...

Zápis {include content} vkládá do hlavní šablony blok s názvem content. Ten budeme definovat v šablonách jednotlivých pohledů (View). V našem případě soubor app/presenters/templates/Homepage/default.latte upravíme následovně:

{block content}
    Hello World
{/block}

Tímto jsme nadefinovali blok content, který bude vložen do hlavního layoutu. Pokud opět obnovíme prohlížeč, uvidíme stránku s textem „Hello World“ (ve zdrojovém kódu i s HTML hlavičkou a patičkou definovanou v @layout.latte).

Pojďme zobrazit příspěvky z blogu – šablonu upravíme následovně:

{block content}
    <h1 n:block="title">Můj blog</h1>

    {foreach $posts as $post}
    <div class="post">
        <div class="date">{$post->created_at|date:'F j, Y'}</div>

        <h2>{$post->title}</h2>

        <div>{$post->content}</div>
    </div>
    {/foreach}
{/block}

Pokud obnovíme prohlížeč, uvidíme výpis všech příspěvků. Výpis zatím není moc hezký, ani barevný, proto můžeme do souboru www/css/style.css přidat pár CSS stylů a zalinkovat jej v layoutu (soubor @layout.latte):

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

Makro {foreach} iteruje přes všechny příspěvky, které jsme předali šabloně v proměnné $posts, a pro každý vykreslí daný kus HTML. Chová se přesně jako PHP kód.

Zápisu |date: říkáme filtr. Filtry jsou určeny k formátování výstupu. Tento konkrétní filtr převádí datum (např. 2013-04-12) na jeho čitelnější podobu (April 12, 2013). Další výchozí filtry najdeme v dokumentaci a nebo si můžeme vytvořit vlastní, když je to potřeba.

Ještě jedna věc. Předchozí kód můžeme zkrátit a zjednodušit. Toho docílíme záměnou Latte maker za n:makra:

<div n:foreach="$posts as $post" class="post">
    <div class="date">{$post->created_at|date:'F j, Y'}</div>

    <h2>{$post->title}</h2>

    <div>{$post->content}</div>
</div>

Atribut n:foreach obaluje div blokem foreach (funguje naprosto stejně jako předchozí kód).

Shrnutí

Nyní máme velmi jednoduchou MySQL databázi s pár příspěvky. Aplikace se připojuje k této databázi a vypisuje jednoduchý seznam těchto příspěvků do šablony.