Životní cyklus aplikace

Seznámíme se s tím, jak se vlastně v Nette Framework tvoří aplikace. Po přečtení budete znát:

  • MVC, adresářovou strukturu a soubor bootstrap.php
  • co jsou to presentery a akce

Model-View-Controller (MVC)

Model-View-Controller je softwarová architektura, která vznikla z potřeby oddělit u aplikací s grafickým rozhraním kód obsluhy (controller) od kódu aplikační logiky (model) a od kódu zobrazujícího data (view). Tím jednak aplikaci zpřehledňuje, usnadňuje budoucí vývoj a umožňuje testování jednotlivých části zvlášť.

Model

Model je datový a zejména funkční základ celé aplikace. Je v něm obsažena aplikační logika. Jakákoliv akce uživatele (přihlášení, vložení zboží do košíku, změna hodnoty v databázi) představuje akci modelu. Model si spravuje svůj vnitřní stav a ven nabízí pevně dané rozhraní. Voláním funkcí tohoto rozhraní můžeme zjišťovat či měnit jeho stav. Model o existenci view nebo kontroleru neví.

View

View, tedy pohled, je vrstva aplikace, která má na starost zobrazení výsledku požadavku. Obvykle používá šablonovací systém a ví, jak se má zobrazit ta která komponenta nebo výsledek získaný z modelu.

Controller

Řadič, který zpracovává požadavky uživatele a na jejich základě pak volá patřičnou aplikační logiku (tj. model) a poté požádá view o vykreslení dat. Obdobou kontrolerů v Nette Framework jsou presentery.

Zpracování akce presenteru

Všechny požadavky posílá prohlížeč přes jediný PHP soubor, který se nachází ve veřejném adresáři www/, a tím je soubor index.php. Ten předává řízení do aplikace (tj. do adresáře app/) zaváděcímu souboru bootstrap.php, kde se konfiguruje prostředí a DI kontejner.

DI kontejner vytvoří tzv. front controller, což objekt třídy Nette\Application\Application. Ten ale HTTP požadavkům nerozumí, proto požádá router, aby mu ho přeložil do řeči, které už rozumí. Tedy aby mu řekl, pro který presenter je požadavek určen a kterou akci s ním chce vykonat. Router kupříkladu odpoví, že uživatel chce akci show presenteru Product (je dobrý zvykem to zapisovat jako Product:show) a dále předává parametr id = 123. Česky by se řeklo: uživatele chce zobrazit produkt s id=123.

Tomu už Application rozumí a přistoupí k plnění přání. Vyrobí objekt třídy ProductPresenter, která reprezentuje presenter Product. (Abychom byli zcela přesní, o výrobu objektu presenteru požádá službu presenterFactory). A pak bude presenter požádán o provedení akce (show s parametrem id).

Presenter je objekt, který vezme požadavek přeložený routerem a vymyslí odpověď. Odpovědí může být HTML stránka, obrázek, XML dokument, soubor na disku, JSON, přesměrování nebo cokoliv potřebujete. Konkrétně ProductPresenter požádá model o data a ty poté předá do šablony k vykreslení. Tohle se zpravidla odehraje v metodě renderShow, kde slovo Show odpovídá názvu akce a parametr požadavku id bude předán jako parametr této metodě:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function renderShow($id)
	{
		// získáme data z modelu a předáme do šablony
		$this->template->product = $this->productRepository->getProduct($id);
	}
}

Pole všech parametrů odeslaných aplikaci požadavkem GET najdete v $this->request->getParameters(). V běžných případech byste je ale neměli potřebovat, využívejte routování a parametrů akce.

Obdobně pole všech hodnot přijatých přes POST naleznete v $this->request->getPost(). Ani to byste neměli potřebovat, pokud nezpracováváte požadavek z jiné aplikace. Nejčastěji zpracováváte totiž formuláře vlastní aplikace a na ty máme formulářovou komponentu.

Následně přistoupí presenter k vykreslení šablony.

Cestu k souboru se šablonou odvodí presenter podle jednoduché logiky. Pro presenter Product a akci show zkusí, zda existuje jeden z těchto souborů:

- templates/Product/show.latte
- templates/Product.show.latte

Taktéž se pokusí dohledat layout (ten je nepovinný):

- templates/Product/@layout.latte
- templates/Product.@layout.latte
- templates/@layout.latte layout společný pro více presenterů

O šablonovacím jazyku Latte více v samostatné kapitole.

Ono to vlastně není nic těžkého! Pokud požaduji akci například Homepage:default, tak se

  1. vytvoří objekt třídy HomepagePresenter
  2. zavolá se metoda renderDefault() (existuje-li, ale nemusí)
  3. vykreslí se šablona např. templates/Homepage/default.latte s layoutem např. templates/@layout.latte

a v šabloně pak můžeme vytvořit odkaz na zmíněný Product:show($id), zhruba takto:

<a n:href="Product:show $productId">detail produktu</a>

Nechci to zakřiknout, ale tvorba aplikací v Nette bude pohodička.

Adresářová struktura

Když se po stažení distribuce Nette Framework podíváte do adresáře sandbox, uvidíte doporučovanou adresářovou strukturu. Tato uvedená adresářová struktura je jen doporučená, protože ji můžeme snadno jakkoliv změnit nebo složky přejmenovat a bude stačit pouze přenastavit cesty v souboru bootstrap.php.

sandbox/
├── app/                  ← adresář s aplikací
│   ├── config/           ← konfigurační soubory
│   │   ├── config.neon   ← konfigurační soubor
│   │   └── config.local.neon
│   │
│   ├── forms/            ← třídy formulářů
│   ├── model/            ← modelová vrstva a její třídy
│   ├── presenters/       ← třídy presenterů
│   │   ├── HomepagePresenter.php  ← třída presenteru Homepage
│   │   └── templates/    ← adresář se šablonami
│   │       ├── @layout.latte ← šablona společného layoutu
│   │       └── Homepage/     ← šablony presenteru Homepage
│   │           └── default.latte  ← šablona akce default
│   ├── router/           ← třídy routerů
│   │
│   └── bootstrap.php     ← zaváděcí soubor aplikace
│
├── log/                  ← obsahuje logy, error logy atd.
├── temp/                 ← pro dočasné soubory, cache, ...
│
├── vendor/               ← adresář na knihovny (např. třetích stran)
│   ├── nette/            ← všechny knihovny Nette Frameworku
│   │   └── nette/Nette   ← oblíbený framework nainstalovaný Composerem
│   ├── ...
│   │
│   └── autoload.php      ← soubor který se stará o načítání tříd nainstalovaných balíčků
│
└── www/                  ← veřejný adresář, document root projektu
    ├── .htaccess         ← pravidla pro mod_rewrite
    ├── index.php         ← který spouští aplikaci
    └── images/           ← další adresáře, třeba pro obrázky

Krom toho se v některých složkách nacházejí soubory .htaccess resp. web.config, které zakazují přístup z prohlížeče (pro Apache resp. IIS). Ujistěte se, že to funguje a že se skutečně z prohlížeče do složky app/ nebo libs/ nedostanete.

Adresářům log/ a temp/ nezapomeňte nastavit práva pro zápis (chmod 0777).

Moduly

U složitějších aplikací můžeme složky s presentery a šablonami rozčlenit do podadresářů, kterým říkáme moduly. Pokud by naše aplikace obsahovala například moduly Front a Admin, její struktura by mohla vypadat takto:

sandbox/
	app/                ← adresář s aplikací
		AdminModule/    ← modul Admin
			presenters/ ← a jeho presentery
			templates/  ← a šablony

		FrontModule/    ← modul Front
			presenters/ ← a jeho presentery
			templates/  ← a šablony

		...

Moduly nemusí tvořit jen plochou strukturu, lze vytvářet i submoduly atd.

Pokud by součástí modulu Front byl presenter Product. Akce show se pak zapíše jako Front:Product:show a třída ProductPresenter se umístí do jmenného prostoru FrontModule:

namespace FrontModule;

class ProductPresenter extends \Nette\Application\UI\Presenter
{
	// ...
}

Související články na blogu