Lekce 6 - Jednoduchý redakční systém v Nette - Výpis článku
V minulé lekci, Jednoduchý redakční systém v Nette - Struktura projektu, jsme si připravili projektovou strukturu pro jednoduchý redakční systém.
Dnes se rovnou bez zbytečných řečí vrhneme do programování
CoreModule. Takže jdeme na to! 
Databáze
Prvně se podíváme na nastavení a obsah databáze. Vytvoříme si novou
databázi pro náš projekt (např. nette-rs) a v ní spustíme
následující SQL:
-- ---------------------------- -- Table structure for `article` -- ---------------------------- DROP TABLE IF EXISTS `article`; CREATE TABLE `article` ( `article_id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) COLLATE utf8_czech_ci DEFAULT NULL, `content` text COLLATE utf8_czech_ci, `url` varchar(255) COLLATE utf8_czech_ci DEFAULT NULL, `description` varchar(255) COLLATE utf8_czech_ci DEFAULT NULL, PRIMARY KEY (`article_id`), UNIQUE KEY `url` (`url`) ) ENGINE = InnoDB AUTO_INCREMENT = 3 DEFAULT CHARSET = utf8 COLLATE = utf8_czech_ci; -- ---------------------------- -- Records of article -- ---------------------------- INSERT INTO `article` VALUES ('1', 'Úvod', '<p>Vítejte na našem webu!</p><p>Tento web je postaven na <strong>jednoduchém redakčním systému v Nette frameworku</strong>. Toto je úvodní článek, načtený z databáze.</p>', 'uvod', 'Úvodní článek na webu v Nette v PHP'); INSERT INTO `article` VALUES ('2', 'Stránka nebyla nalezena', '<p>Litujeme, ale požadovaná stránka nebyla nalezena. Zkontrolujte prosím URL adresu.</p>', 'chyba', 'Stránka nebyla nalezena.');
To nám vytvoří a naplní tabulku s články, kterou budeme dále potřebovat.
SQL skript naleznete i v archivu ve složce sql/
pod názvem create_script.sql.
app/config/common.neon
Nakonec je ještě potřeba nastavit v Nette připojení do naší databáze. To uděláme v hlavním konfiguračním souboru tak, že upravíme již přednastavené parametry, tj. název naší databáze i uživatelské jméno a heslo. Výsledek by měl vypadat přibližně takto:
...
# Konfigurace databázového připojení v rámci celé aplikace.
database:
dsn: 'mysql:host=127.0.0.1;dbname=nette-rs' # Typ, adresa a název databáze
user: root # uživatelské jméno
password: kokos # heslo
options:
lazy: yes
...
Pokud máte jinou konfiguraci databáze v různých
prostředích (localhost vs. hosting), používá se ještě lokální
konfigurační soubor app/config/local.neon, jehož nastavení
přepíše to globální specificky pro dané prostředí.
Model
Stejně jako v minulé aplikaci začneme hezky od modelu.
app/Model/DatabaseManager.php
Protože jsme všichni znalí OOP a nechceme mít zbytečné duplicity v kódu, připravíme si základní abstraktní modelovou třídu pro práci s databází, která bude pomocí Dependency Injection (zkráceně DI) získávat přístup k Nette rozhraní pro práci s databází a všechny další modelové třídy z ní budou následně dědit, aby automaticky tento přístup získaly. Třída je poměrně jednoduchá a vypadá takto:
<?php declare(strict_types=1); namespace App\Model; use Nette\Database\Explorer; use Nette\SmartObject; /** * Základní model pro všechny ostatní databázové modely aplikace. * Poskytuje přístup k práci s databází. * @package App\Model */ class DatabaseManager { use SmartObject; /** @var Explorer Služba pro práci s databází. */ protected Explorer $database; /** * Konstruktor s injektovanou službou pro práci s databází. * @param Explorer $database Automaticky injektovaná Nette služba pro práci s databází */ public function __construct(Explorer $database) { $this->database = $database; } }
app/CoreModule/Model/ArticleManager.php
Další na řadě je model pro správu článků, který tedy podědí ze
třídy DatabaseManager. Bude již součástí našeho CoreModulu a
jeho cílem je definovat metody, které pomocí Nette rozhraní pro práci s
databází umožní manipulaci s tabulkou článků, kterou jsme si vytvořili
výše.
<?php declare(strict_types=1); namespace App\CoreModule\Model; use App\Model\DatabaseManager; use Nette\Database\Table\ActiveRow; use Nette\Database\Table\Selection; use Nette\Utils\ArrayHash; /** * Model pro správu článků v redakčním systému. * @package App\CoreModule\Model */ class ArticleManager extends DatabaseManager { /** Konstanty pro práci s databází. */ const TABLE_NAME = 'article', COLUMN_ID = 'article_id', COLUMN_URL = 'url'; /** * Vrátí seznam všech článků v databázi seřazený sestupně od naposledy přidaného. * @return Selection seznam všech článků */ public function getArticles() { return $this->database->table(self::TABLE_NAME)->order(self::COLUMN_ID . ' DESC'); } /** * Vrátí článek z databáze podle jeho URL. * @param string $url URl článku * @return false|ActiveRow první článek, který odpovídá URL nebo false pokud článek s danou URL neexistuje */ public function getArticle($url) { return $this->database->table(self::TABLE_NAME)->where(self::COLUMN_URL, $url)->fetch(); } /** * Uloží článek do systému. * Pokud není nastaveno ID vloží nový článek, jinak provede editaci článku s daným ID. * @param array|ArrayHash $article článek */ public function saveArticle(ArrayHash $article) { if (empty($article[self::COLUMN_ID])) { unset($article[self::COLUMN_ID]); $this->database->table(self::TABLE_NAME)->insert($article); } else $this->database->table(self::TABLE_NAME)->where(self::COLUMN_ID, $article[self::COLUMN_ID])->update($article); } /** * Odstraní článek s danou URL. * @param string $url URL článku */ public function removeArticle(string $url) { $this->database->table(self::TABLE_NAME)->where(self::COLUMN_URL, $url)->delete(); } }
Všimněte si, že Nette rozhraní pro práci s databází kopíruje
pokládání klasických SQL dotazů, ovšem v rámci PHP kódu v trochu
zjednodušeném formátu. A také obsahuje např. ochranu proti SQL
injection. 
Presentery
Dále budeme pokračovat s presentery. Začneme tím, že smažeme základní
presenter app/presenters/HomepagePresenter.php, protože už ho
nebudeme potřebovat. Na konci této lekce už totiž budeme mít základ zcela
nové aplikace.
app/Presenters/BasePresenter.php
Stejně jako ve většině projektů v Nette a podobně jako v našem modelu,
začneme od základní abstraktní třídy, ze které dědí všechny ostatní
presentery a tou je BasePresenter. V sandboxu, ze kterého
vycházíme, už je vytvořen, takže ho jen trošku upravíme:
<?php declare(strict_types=1); namespace App\Presenters; use Nette\Application\UI\Presenter; /** * Základní presenter pro všechny ostatní presentery aplikace. * @package App\Presenters */ abstract class BasePresenter extends Presenter { }
app/CoreModule/Presenters/ArticlePresenter.php
Nyní se dostáváme k presenteru, který nám pomocí
ArticleManager bude předávat data článků do šablony. Tento
presenter tvoří hlavní část našeho CoreModule a vypadá následovně:
<?php declare(strict_types=1); namespace App\CoreModule\Presenters; use App\CoreModule\Model\ArticleManager; use App\Presenters\BasePresenter; use Nette\Application\BadRequestException; /** * Presenter pro vykreslování článků. * @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(string $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(string $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. } }
app/CoreModule/config/common.neon
Aby fungovalo automatické předávání závislostí pomocí DI, musíme
ještě zaregistrovat ArticleManager jako službu v naší
aplikaci. Konkrétně to provedeme v konfiguračním souboru našeho modulu, kde
i předáme konfiguraci URL výchozího článku do našeho nového
presenteru:
#
# Konfigurační soubor pro CoreModule.
#
parameters:
defaultArticleUrl: 'uvod' # URL výhozího článku
# Nastavení služeb pro CoreModule.
services:
- App\CoreModule\Model\ArticleManager # Vlastní služba dále přístupná pomocí DI.
- App\CoreModule\Presenters\ArticlePresenter(%defaultArticleUrl%) # Předání nastavení při vytváření služby presenteru.
Routování
app/router/RouterFactory.php
Abychom se opravdu dostali k daným článkům podle jejich URL, je nutné
ještě upravit routování naší aplikace. To zařídíme úpravou již
existující třídy ze sandboxu RouterFactory, kde nastavíme
směrování na náš nový presenter:
<?php declare(strict_types=1); namespace App\Router; use Nette; use Nette\Application\Routers\RouteList; final class RouterFactory { use Nette\StaticClass; public static function createRouter(): RouteList { $router = new RouteList; $router->addRoute('[<url>]', 'Core:Article:default'); return $router; } }
To je zatím vše.
V příští lekci, Jednoduchý redakční systém v Nette - Administrace, se budeme věnovat šablonám a projekt zprovozníme.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 667x (3.65 MB)
Aplikace je včetně zdrojových kódů v jazyce PHP

