3. diel - Cms v Nette a Doctrine 2 - Modely a Layout
V minulej lekcii, Cms v Nette a Doctrine 2 - Kostra aplikácie , sme si založili projekt so všetkými potrebnými knižnicami a úpravami. V dnešnom Nette tutoriálu začneme tvoriť modelovou vrstvu a pridáme layout s úvodnou stránkou.
Model
Kľúčom k práci s Doctrine sú anotácie. Pomocou nich si uloží do cache informácie o entitách, ako sú názvy stĺpcov, ich dátové typy, väzby medzi entitami atď. Ak teda napríklad pomocou anotácie určíme, že premenná bude typu boolean, pri výbere dát z databázy sa hodnota automaticky přetypuje na TRUE alebo FALSE (v databáze hodnota bude uložená ako 1/0). Informácie je možné zapisovať aj pomocou formátu XML alebo Yamli, ale anotácie sú najpoužívanejšie.
Entity
App / model / entities / User.php
Vytvoríme si našu prvú jednoduchú entitu, ktorá bude reprezentovať
užívateľa. Nezabúdajte na to, že Nette obsahuje triedu
Nette\Security\User
, ktorej objekt je vo všetkých Presenter a
šablónach v premennej $user
. Nemali by sme túto premennú
prepísať, preto sa premenná našej entity bude v šablónach menovať
$userEntity
.
Pre začiatok bude naša entita veľmi jednoduchá. Obsahuje definíciu
atribútov, ktoré zodpovedajú stĺpcom v databázovej tabuľke
user
. Názov je odvodený od názvu entity, preto ak by sme mali
iný názov tabuľky, pridáme anotácii
@ORM\Table(name="nazev_tabulky")
.
Rovnako to platí aj u názvov stĺpcov, tam pridáme do zátvorky parameter
name
(@ORM\Column(name="nazev_sloupce")
).
<?php namespace App\Model\Entities; use Doctrine\ORM\Mapping as ORM; use Kdyby\Doctrine\Entities\BaseEntity; /** * Doctrine entita pro tabulku user. * @package App\Model\Entities * @ORM\Entity */ class User extends BaseEntity { // Pomocné konstanty pro náš model. /** Konstanty pro uživatelské role. */ const ROLE_USER = 1, ROLE_ADMIN = 2; /** Konstanty pro uživatelské jméno. */ const MAX_NAME_LENGTH = 15, NAME_FORMAT = "^[a-zA-Z0-9]*$"; // Proměné reprezentující jednotlivé sloupce tabulky. /** * Sloupec pro ID uživatele. * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue */ protected $id; /** * Sloupec pro jméno. * @ORM\Column(type="string") */ protected $name; /** * Sloupec pro heslo. * @ORM\Column(type="string") */ protected $password; /** * Sloupec pro email. * @ORM\Column(type="string") */ protected $email; /** * Sloupec pro IP adresu. * @ORM\Column(type="string") */ protected $ip; /** * Sloupec pro datum registrace. * @ORM\Column(name="`registration_date`", type="datetime") */ protected $registrationDate; /** * Sloupec role uživatele. Význam hodnot viz. konstanty pro uživatelské role. * @ORM\Column(type="integer") */ protected $role; /** * Ověřuje, zda je uživatel v roli administrátora. * @return bool vrací true, pokud je uživatel administrátor; jinak vrací false */ public function isAdmin() { return $this->role === self::ROLE_ADMIN; } }
Pre ID je potreba zapísať anotácií viac, Doctrine ho potom automaticky použije ako primárny kľúč.
Ďalej si všimnite metódy isAdmin()
- entita nie je len
prepravkou na dáta, ale môže vedieť aj jednoduché operácie.
Všetky naše entity budú dediť od základnej entity, vytvorené
rozšírením Keby. Získa vďaka tomu niektoré príjemné funkcie, napr.
Nebudeme musieť písať setter a Getter a namiesto toho budeme môcť
používať priamo $user->name
.
Poznámka: Ak atribútu určíme typ údajov date
alebo
datetime
, Doctrine automaticky pri ťahaní dáta z databázy
vytvorí objekt triedy DateTime
.
Fasády
Fasády budú služby (tzn. Že v celej aplikácii bude len jedna inštancia danej triedy), ktoré budú sprostredkovávať všetky operácie.
App / model / Facades / UserFacade.php
Pre začiatok bude opäť naša trieda veľmi jednoduchá. Konštruktor
automaticky dostane objekt triedy Kdyby\Doctrine\EntityManager
(opäť malé vylepšenia EntityManager
od Doctrine) a pridáme
metódu na vyhľadanie užívateľa podľa ID.
<?php namespace App\Model\Facades; use App\Model\Entities\User; use Kdyby\Doctrine\EntityManager; use Nette\Object; /** * Fasáda pro manipulaci s uživateli. * @package App\Model\Facades */ class UserFacade extends Object { /** @var EntityManager Manager pro práci s entitami. */ private $em; /** * Konstruktor s injektovanou třídou pro práci s entitami. * @param EntityManager $em automaticky injektovaná třída pro práci s entitami */ public function __construct(EntityManager $em) { $this->em = $em; } /** * Najde a vrátí uživatele podle jeho ID. * @param int|NULL $id ID uživatele * @return User|NULL vrátí entitu uživatele nebo NULL pokud uživatel nebyl nalezen */ public function getUser($id) { return isset($id) ? $this->em->find(User::class, $id) : NULL; } }
Metóda EntityManager::find()
vyhľadá entitu User podľa
daného ID. Normálne by sme ako prvý parameter mali napísať celý názov
triedy App\Model\Entities\User
, ale magická konštanta
class
(zabudovaná priamo v PHP) tento názov vrátane menného
priestoru obsahuje, je preto náš zápis o niečo kratšia.
V našom prípade sa buď vrátia načítané entita User (ako načítané
chápte objekt naplnený dátami z databázy) alebo NULL (čo vracia metóda
EntityManager::find()
, ak takú entitu nenájde).
App / config / config.neon
Keďže je UserFacade
automaticky injectovaná služba, musíme
ju zaregistrovať v našom konfiguračnom súbore:
... services: - App\Model\Facades\UserFacade router: App\RouterFactory::createRouter ...
Presenter
App / presenters / BasePresenter.php
Entitu User
aj UserFacade
budeme využívať v
podstate všetkých Presenter, preto ich uložíme do nášho
BasePresenteru:
<?php namespace App\Presenters; use App\Model\Entities\User as UserEntity; use App\Model\Facades\UserFacade; use Kdyby\Translation\Translator; use Nette\Application\UI\Presenter; use Nette\Bridges\ApplicationLatte\Template; /** * Základní presenter pro všechny ostatní presentery aplikace. * @package App\Presenters */ abstract class BasePresenter extends Presenter { /** @persistent null|string Určuje jazykovou verzi webu. */ public $locale; /** * @var Translator Obstarává jazykový překlad na úrovni presenteru. * @inject */ public $translator; /** * @var UserFacade Fasáda pro manipulaci s uživateli. * @inject */ public $userFacade; /** @var UserEntity Entita pro aktuálního uživatele. */ protected $userEntity; …
Ďalej si tu preťažíme metódu startup()
, kde si vytvoríme
entitu User
. Ak je používateľ prihlásený, nájdeme informácie
z databázy a uložíme ich do entity. Ak nie je, potom vytvoríme entitu s
jedinou informácií, a to že používateľ nie je v úlohe administrátora
(aby sme nemuseli všade pripisovať podmienku
$user->isLoggedIn()
, ale stačilo len
$userEntity->isAdmin()
).
/** * Volá se na začátku každé akce, každého presenteru a zajišťuje inicializaci entity uživatele. */ public function startup() { parent::startup(); if ($this->getUser()->isLoggedIn()) { $this->userEntity = $this->userFacade->getUser($this->getUser()->getId()); } else { // Abychom mohli použít "$userEntity->isAdmin()", když uživatel není přihlášen. $entity = new UserEntity(); $entity->role = UserEntity::ROLE_USER; $this->userEntity = $entity; } }
Nezabudnite do use
uviesť
use App\Model\Entities\User as UserEntity
Ďalšie metóda beforeRender()
odovzdáva premenné šablóne
ešte pred jej vykreslením - je jedno, o ktorú šablónu sa jedná - odovzdá
je teda každej šablóne, ktorá sa bude vykresľovať. Keďže sa naša entita
hodí vo všetkých šablónach, odovzdáme ju opäť v
BasePresenter
.
/** * Volá se před vykreslením každého presenteru a předává společné proměnné do celkového layoutu webu. */ public function beforeRender() { parent::beforeRender(); $this->template->userEntity = $this->userEntity; }
Šablóny
App/presenters/templates/@layout.latte
Layout je hlavná šablóna, ktorá sa vykresľuje vždy. Šablóny pre
jednotlivé stránky sa potom vloží makrom {include}
do
obsahu.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Nette Doctrine 2 blog</title> <link rel="stylesheet" href="{$basePath}/css/style.css"> <link rel="shortcut icon" href="{$basePath}/favicon.ico"> <meta name="viewport" content="width=device-width"> {block head}{/block} </head> <body> <div id="container"> {if count($flashes) > 0} <div id="flashes"> <div class="text"> <div n:foreach="$flashes as $flash" n:class="flash, $flash->type"> {$flash->message} </div> </div> </div> {/if} <div id="header"> <div id="logo"> <h1>Blog system</h1> </div> <div id="userInfo"> {if $user->isLoggedIn()} {_common.loggedAs}: {$userEntity->name} {/if} </div> <div id="menu"> <a n:href="Homepage:default">{_menu.homepage}</a> </div> </div> <div id="content"> {include content} </div> <div id="footer"> <div class="text"> © Konesoft Corporation </div> </div> </div> {block scripts} <script src="//code.jquery.com/jquery-1.11.2.min.js"></script> <script src="//nette.github.io/resources/js/netteForms.min.js"></script> <script src="{$basePath}/js/main.js"></script> {/block} </body> </html>
Nette okrem premennej $user
odovzdáva šablónam automaticky aj
premenné $flashes
, ktorá obsahuje polia flash správ (tie sa
vytvoria metódou
Nette\Application\UI\Control::flashMessage($message, $type)
), a
$basePath
- tá obsahuje názov koreňovej zložky projektu.
Všimnite si, že texty v našej šablóne sú pripravené pre preklad. K tomuto článku priložím všetky súbory pre preklad, nech to nemusíme v každom článku dopisovať. Je tu podpora pre český a anglický jazyk.
Tiež bude priložený CSS súbor. Príde mi bezdôvodné ho tu ukazovať a vysvetľovať (je k stiahnutiu v projekte), dizajn nie je cieľom tejto série. Rovnako si ho upravíte podľa vlastného vkusu.
Poznámka: Pri preklade znamená prvé slovo názov súboru, ostatné sú názvy kľúčov. Preto makro {_menu.homepage} použije kľúč homepage zo súboru menu (presný súbor sa ešte určí podľa jazyka). Súbory sú vo formáte NEON.
App / presenters / templates / Homepage / default.latte
Na úvodnej stránke bude zobrazené niekoľko najnovších článkov. To si vytvoríme až neskôr, teraz pridáme len stránku s nadpisom, aby Nette nevyhadzovali chybu 404.
{block content} <h2>{_homepage.header}</h2>
To je z dnešnej lekcie všetko. Nabudúce, v lekcii Cms v Nette a Doctrine 2 - Registrácia užívateľa , pridáme možnosť registrácie užívateľa.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 274x (3.43 MB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP