Statický web v Nette
Tento tutorial vám předvede, jak v Nette udělat jednoduchý web o 3 stránkách s jednoduchým menu pro jeho ovládání.
Dovolil jsem si tutoriál aktualizovat pro Nette 2.0, přiložené zdrojové kódy v archivu ale zůstaly neaktuální (HosipLan)
Doplněny úpravy reflektující Nette 2 beta pro PHP 5.3
(d2c39f5 released on 2011–07–02) Pro PHP 5.2 by mělo stačit zakomentovat
use (22)
Co budete potřebovat?
sandboxz aktuální distribuce Nette Frameworku
Co se naučíte?
- pracovat se sandboxem(adresářovou strukturou aplikace)
- seznámíte se s obsahem životně důležitých souborů index.php a bootstrap.php
- vytvořit Presentery a šablony aplikace
- vytvořit jednoduché menu a přiřadit k němu odkazy
- připojit CSS styly k aplikaci
- vytvořit jednoduchou statickou prezentaci
Adresářová struktura
Je dobré si předem připravit adresářovou strukturu, kde bude Vaše
aplikace sídlit. Tu je vhodné logicky rozčlenit podle modelu Model-View-Presenter
(MVP). S tím si nemusíte lámat hlavu, protože v distribučním
balíčku najdete adresář sandbox, kde je již připravená adresářová
struktura pro naši budoucí aplikaci.
Více o doporučené adresářové struktuře najdete v 2. kapitole QuickStartu. Doporučuji si ji prostudovat, protože my tento sandbox použijeme jako výchozí bod našeho tutorialu
Překopírujte tedy obsah adresáře sandbox do připravené
složky, nebo zkopírujte celou složku sandbox do vašeho
webového prostoru a přejmenujte ji, jak uznáte za vhodné. My si adresář
pojmenujeme třeba netteweb.
Pojďme se podívat blíže do struktury sandboxu, nyní adresáře
netteweb (ke stažení na konci stránky), na adresáře, které
nás budou zajímat:
+-- app/ (výkonné soubory aplikace, např.: bootstrap.php, config.ini)
+-- presenters/ (definice aplikačního layeru)
+-- templates/ (aplikační šablony)
+-- libs/ (knihovny aplikace, např.: loader.php, dibi.min.php)
+-- Nette/
+-- loader.php (minimalizovaný Nette Framework)
+-- log/ (errorlogy)
+-- temp/ (bude sloužit k ukládání dočasných souborů)
+-- www/ (kořen aplikace, např.: index.php)
Adresář temp a log musí mít
správně nastavena práva pro zápis (0777)
index.php
Nyní se podíváme na index.php, kde definujeme pouze cesty
k aplikačním adresářům a to formou konstant. Po jejich definici si
vyžádáme „starter“ aplikace – bootstrap.php
cesta k souboru: www/index.php
<?php
// absolute filesystem path to this web root
$params['wwwDir'] = __DIR__;
// absolute filesystem path to the application root
$params['appDir'] = realpath(__DIR__ . '/../app');
// load bootstrap file
require $params['appDir'] . '/bootstrap.php';
Při používání Nette Frameworku se doporučuje používat pouze úvodní tag pro php script. Uzavírací tag „?>“ může působit problémy
bootstrap.php
Aktuální bootstrap.php se může v poslední ditribuci lišit, neberte ho jako dogma. Vždy použijte ten z aktuální distribuce, předinstalovaný v sandboxu. Není do něj potřeba zasahovat.
Starter aplikace zavolá Nette Framework a spustí důležitého pomocníka – Laděnku. Ta nám bude neustále nablízku a bude nám pomáhat řešit případné chyby při psaní kódu.
cesta k souboru: app/bootstrap.php
<?php
use Nette\Diagnostics\Debugger,
Nette\Application\Routers\Route;
// Load Nette Framework
$params['libsDir'] = realpath(__DIR__ . '/../libs');
require $params['libsDir'] . '/Nette/loader.php';
// Enable Nette Debugger for error visualisation & logging
Debugger::$logDirectory = realpath(__DIR__ . '/../log');
Debugger::$strictMode = TRUE;
Debugger::enable();
// Load configuration from config.neon file
$configurator = new Nette\Configurator;
$configurator->container->params += $params;
$configurator->container->params['tempDir'] = realpath(__DIR__ . '/../temp');
$container = $configurator->loadConfig(__DIR__ . '/config.neon');
// Setup router
$router = $container->router;
$router[] = new Route('index.php', 'Homepage:default', Route::ONE_WAY);
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
// Configure and run the application!
$application = $container->application;
//$application->catchExceptions = TRUE;
$application->errorPresenter = 'Error';
$application->run();
Pro zajímavost si také prohlédněte soubor config.neon
umístěný v adresáři app a mrkněte, k čemu je
dobrý. Pro budoucnost bude rovněž dobré seznámit se s routováním, které jsou
rovněž ve starteru aplikace – v souboru bootstrap.php. Soubor najdeme v adresáři
app. Nyní si můžete zkusit spustit aplikaci index.php.
Pokud vás prohlížeč zobrazil uvítací obrazovku frameworku, je vše v pořádku a můžeme se pustit do našeho webu.
V opačném případě zkuste FAQ nebo forum
Vytvoření základního Presenteru (Controlleru)
V první řade je potřeba seznámit se s procesem návrhu Presenter/View(Action)
a životním cyklem Presenteru
v Nette aplikaci. My se budeme držet modelu, kdy si pro každou stránku
vytvoříme vlastní Presenter, protože tušíme, že naše webová prezentace
se bude v budoucnu rozšiřovat. Tomu však předchází vytvoření
abstraktního Presenteru. Pokud je vše jasné, vytvoříme ho –
BasePresenter.php. Je to základní stavební kámen pro ostatní
Presentery. Normálně se v něm nachází metody startup(),
beforeRender() atd. My pro náš jednoduchý web nebudeme nic
z toho potřebovat, takže bude vypadat takto:
cesta k souboru: app/presenters/BasePresenter.php
<?php
use Nette\Application\UI\Presenter;
abstract class BasePresenter extends Presenter
{
}
Náš web bude mít 3 stránky s menu: Domů | Nabídka |
Kontakt. Budeme tedy potřebovat 3 Presentery a to:
HomepagePresenter.php, ProductPresenter.php,
ContactPresenter.php. My si ukážeme, jak udělat
HomepagePresenter.php. Další 2 už zvládnete sami.
HomepagePresenter bude vypadat takto:
cesta k souboru: app/presenters/HomepagePresenter.php
<?php
class HomepagePresenter extends BasePresenter
{
}
Co je zde důležité? Třida HomepagePresenter, tím, že je definována,
automaticky hledá šablony @layout.latte
a /Homepage/default.latte
Při tvorbě názvu je třeba dodržovat tzv. velbloudí notaci, tzn. název třídy musí začínat velkým písmenem
Vytvoření základní šablony (@layout.latte)
Nette Framework hledá vždy základní šablonu v umístění
app/templates/ pod názvem @layout.latte. Je to
výchozí šablona, do které se pak nahrávají další podšablony/bloky.
Takže pokud máme vytvořenou nějakou obecnou/grafickou šablonu, stačí ji
přejmenovat, správně umístit a Nette se postará o její zobrazení.
Aby tato šablona měla praktický význam a mohla spolupracovat s ostatními, musíme jí vyznačit místa, kde se bude vykreslovat a kam se vloží obsah jiné šablony, případně šablon. V šablonách lze používat i různé filtry a teď právě nastala vhodná chvíle pro využití filtru Latte, díky němuž se nám zjednoduší a zpřehlední zápis PHP kódu. Následující script Vám ukáže, jak označit místa, kam se bude vkládat obsah jiných šablon a jak vypadá zápis s využitím filtru Latte:
cesta k souboru: app/templates/@layout.latte
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="description" content="Nette Framework Static Web">
<meta name="robots" content="{$robots}" n:ifset="$robots">
<title>{include #title}</title>
<link rel="stylesheet" media="screen,projection,tv" href="{$basePath}/css/screen.css" type="text/css">
<link rel="stylesheet" media="print" href="{$basePath}/css/print.css" type="text/css">
<link rel="shortcut icon" href="{$basePath}/favicon.ico" type="image/x-icon">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="{$basePath}/js/netteForms.js"></script>
{block head}{/block}
</head>
<body>
<div id="header">
<h1>Nette Fabrika, s.r.o.</h1>
<h2>Otevřeli jsme továrnu na sny...</h2>
</div>
<!--vložení bloku content-->
{include #content}
</body>
</html>
Nyní musíme ještě vytvořit šablonu pro HomepagePresenter a další
2 presentery, které jste vytvořili již samostatně. Pro tento Presenter
Nette očekává šablonu v adresáři app/templates/Homepage pod
názvem default.latte. Tady je její podoba:
cesta k souboru: app/templates/Homepage/default.latte
{block title}
<title>Nette Fabrika, s.r.o. - Úvod</title>
{/block}
{block content}
<div>
<p>Vítejte v Nette Fabrice!</p>
</div>
{/block}
To je důležité, protože název adresáře Homepage nám
vlastně páruje tuto šablonu s HomepagePresenterem, který jsme
si před malou chvílí vytvořili. V případě jiného pojmenování a
nedodržení párování by došlo k chybě. Stejný problém vznikne, pokud
pojmenujeme šablonu jinak, než default.latte.
V Nette se pro názvy šablon používá přípona *.latte
Vytvoření menu
K vytvoření menu upravíme šablonu @layout.latte v místě,
kde menu chceme mít zobrazené:
cesta k souboru: app/templates/@layout.latte
<ul n:inner-foreach="$menuItems as $item => $link">
<li>{$item}</li>
</ul>
Tím je úprava základní šablony hotová. Teď stačí v BasePresenteru
nachystat data pro proměnnou $menuItems.
cesta k souboru: app/presenters/BasePresenter.php
<?php
abstract class BasePresenter extends Presenter
{
public function beforeRender()
{
$this->template->menuItems = array(
'Domů' => 'Homepage:',
'Produkty' => 'Products:',
'Kontakty' => 'Contacts:',
);
}
}
Definici proměnné je třeba umístit do metody beforeRender(), aby byla dostupná pro všechny view.
Doplnění odkazů z menu
Nette Framework vnímá linky/odkazy jako pokyny k nějaké akci, přesněji řečeno kliknutím na odkaz spustíte nějakou funkci/metodu. V praxi to znamená, že se vůbec nestaráte o URL odkazu, link totiž volá metodu a je tak na URL nezávislý
My jednoduše upravíme šablonu @layout.latte s použitím
filtru Latte:
cesta k souboru: app/templates/@layout.latte
<ul n:inner-foreach="$menuItems as $item => $link">
<li><a n:href="$link">{$item}</a></li>
</ul>
Připojení CSS stylu k šabloně
Na chvilku si oddechneme a budeme se trochu věnovat grafice. Tzn.
nastylujeme si již vytvořené položky v šabloně pomocí CSS. Můžete
použít připravený styl v zazipované aplikaci (dole na stránce) a umístit
je do www/css/screen.css Nyní připojíme tento styl k naší
šabloně. Využijeme k tomu zabudované Nette proměnné
$basePath. Provedeme následující zápis v základní šabloně,
který netřeba komentovat.
cesta k souboru: app/templates/@layout.latte
<head>
...
<link href="{$basePath}/css/screen.css" rel="stylesheet" type="text/css" />
...
</head>
Dokončení webu
Tímto je web téměř hotový… Na závěr ještě zvýrazníme položku menu pro stránku, na které se právě nacházíme:
cesta k souboru: app/templates/@layout.latte
<li {ifCurrent $link}class="current"{/ifCurrent}><a n:href="$link">{$item}</a></li>
Pro vytvoření stránek Produkty a Kontakty je třeba vytvořit
ve složce app příslušné presentery
ProductsPresenter, ContactsPresenter, obdobně jako
tomu bylo u HomepagePresenter a ve složce templates vytvořit
odpovídající adresáře Products a Contacts.
Obsahem těchto složek bude šablona presenteru s názvem
default.latte. Její obsah musí obsahovat bloky title
a content, stejně jako u šablony pro
HomepagePresenter.
Komentáře 
_Martin_ | 27. 1. 2010, 9:42 | comment
2 Jan Tvrdík: Já myslím, že by se ta metoda nemusela přepisovat (se správně nastaveným routováním). A je to zajímavý nápad – ubylo by prostoru, kde se „zbytečně“ mluví o presenterech a naopak by zbylo více místa pro fičurky šablon.
Semik | 31. 1. 2010, 16:10 | question
Jak zařadím do menu odkaz na cizí web ?
{foreach $menuItems as $id ⇒ $item} {$item} {/foreach}V poli $menuItems jsou jako klíče jednotlivé presentery, ale zadat normální odkaz nejde, má poté href=„error: No route for Homepage:www.seznam.cz/()“
Jan Tvrdík | 31. 1. 2010, 20:14 | comment
Nejsem si jist, ale 'http://seznam.cz' => 'Seznam.cz', by
snad mělo fungovat.
amik | 31. 1. 2010, 21:51 | comment
chtěl bych upozornit na drobnou chybku v článku (sekce „vytvoření základního presenteru“): camelCase je notace s prvním písmenem vždy malým (viz http://cs.wikipedia.org/wiki/CamelCase ), notace s prvním písmenem velkým se označuje jako PascalCase.
Semik | 2. 2. 2010, 22:13 | comment
Re: Nejsem si jist, ale ‚http://seznam.cz‘ ⇒ ‚Seznam.cz‘, by snad mělo fungovat.
Ne, vyskočí laděnka:
Nette\Application\BadRequestException #404
Action name ‚seznam.cz‘ is not alphanumeric string.
magerio | 13. 2. 2010, 14:33 | comment
Sice je to uz starsi diskuze, ale pokud tvorim „staticky web“ v PHP, byl by snad problem do sablony napsat <a href=„http://www.seznam.cz“>Seznam</a> ? ;-) Vzdycky je mozne kolem toho nasypat nejake Latte ify apod…
petricekh | 22. 2. 2010, 13:34 | question
Mám problém. Úplně začínám s Nette. Zkoušel jsem si vytvořit podle tohoto tutoriálu statický web. Zasekl jsem se na jednom problému. Vytvořil jsem BasePresenter a HomePagePresenter (extends BasePresenter). Při spuštění hlavní stránky mi laděnka volá, že v HomePagePresenteru je chyba – „BasePresenter not found“. Přitom tam je, všechny velikosti písmen jsou správně. Prosím poraďte, kde je chyba. Díky
petricekh | 22. 2. 2010, 14:09 | question
Zjistil jsem jednu zajímavou věc, která by mohla souviset s před chvilkou uvedeným problémem. Na rozdíl od tohoto tutoriálu používám jinou adresářovou strukturu. Jediný rozdíl je v tom, že pro document root nepoužívám adresář root/document_root ale přímo root. Nicméně pořád nevím, jak problém vyřešit.
Jan Tvrdík | 1. 3. 2010, 0:21 | comment
Používáš RobotLoader? Pokud ano, tak obvykle pomůže
smazání temp. Pokud ne, tak je nutné načíst
BasePresenter ručně (require_once '...').
Jonnyb | 14. 3. 2010, 16:07 | comment
Ahoj jsem začátečník s nette. Tvořím si statický web, asi hodinu jsem si lámal hlavu, proč mi nejde přidat stránka v BasePresenteru do pole odkazu,když jsem si stáhl netteweb.zip, pokud jsem ji tam přidal skončilo to v Laděnce, že je chyba v HomePagePresenter.php… pak jsem smazal obsah složky Temp a už mi to fungovalo bez problému.....
trollnet | 21. 11. 2010, 12:52 | comment
zdravim nettaci, sem taky zacatecnik jako spamkolega vyse :), ale mam jiny dotaz: daji se nastavit ruzne nazvy sablon (*.phtml) pro stranky, pokud ano, jak? Napr. default.phtml pro HomePage a contact.phtml pro Contact , Diky moc
baki | 3. 1. 2011, 8:50 | comment
jasně že dá :). Prostě to pojmenuješ tak, jak jsi napsal a pak to
voláš klasicky pomocí {link default} nebo {link
contact} ;)
jik | 14. 2. 2011, 21:35 | question
Jsem taky zelenáč. Nějak nechápu (verze 2.0 alfa):
{ifCurrent $id}class="current"{/if}
Trochu jsem ho upravil, abych viděl, co tam padá – „Domů“, Produkty" a „Kontakty“, ale „current“ se tam nikdy neobjeví. Stejně tak nevím, co to má provést.
Peki | 21. 3. 2011, 11:39 | question
Zdravim, zacinam s Nette a pokusal som sa prejst uz viac tutorialov a zatial bezuspesne. Stiahol som si „NetteFramework-2.0alpha-PHP5.3“ a postupoval som krok po kroku. Stranka vyzera tak ako je hotovy projekt ktory sa da stiahnut avsak v mojom ked stlacim v menu na ktorykolvek iny odkaz ako je Domov, tak nefunguje a vyhodi chybu napr. „The requested URL /moje/www/forum/ was not found on this server.“ navyse ked to nahram na server vyzera to este horsie: „http://nwa.eu.sk/moje/www/“
Pripajam cely projekt na stiahnutie „http://nwa.eu.sk/moje.zip“ Ak by vedel niekto kde je chyba a napise mi co treba opravit budem vdacny. Btw: ked si stiahnem hotovy projekt pod tutorialom ten ide normalne aj na localhoste aj na servri .. zrejme to je ale ina verzia.
Jan Tvrdík | 21. 3. 2011, 15:33 | comment
Nemáš zapnutý mod_rewrite. Hledej, řešilo se to tu
mockrát.
Na serveru ti to nefunguje, protože je tam pravděpodobně PHP ve verzi 5.2.
mrataja | 26. 3. 2011, 12:23 | comment
Používám aktuální verzi Nette.5.3. Poslední krok tutoriálu (zvýraznění) nefunguje: <li {ifCurrent $id}class=„current“{/if}
Je potřeba drobná úprava <li {ifCurrent $id}class=„current“{/ifCurrent}
vtitl | 21. 6. 2011, 12:22 | question
Vytvořil jsem web tohohle návodu, zde ale není popsáno, jak udělat tu stránku s produkty a kontakty, zkoušel jsem to sám. Vytvořil jsem presentery a templates podle toho netteweb.zip, ale hlásí mi to: Server Error
We're sorry! The server encountered an internal error and was unable to complete your request. Please try again later.
error 500 Tušíte, kde může být problém. Respektive můžete mě nasměrovat, jak ty stránky dotvořit? Díky
22 | 2. 7. 2011, 12:52 | comment
update na Nette 2 beta (d2c39f5 released on 2011–07–02) diskuse
pavel_86 | 23. 8. 2011, 20:43 | question
Zdravim, s Nette zacinam a nemuzu rozchodit tenhle projekt. Normalne se mi vse zobrazi vcetne necislovaneho seznamu, odkazy jsou vygenerovane napr. netteweb/contacts/ … coz myslim, ze je taky spravne. Kdyz ale na ten odkaz kliknu, tak se dostanu na error 404. Mam takovy dojem, ze je spatne bud router nebo prislusny presenter. Napr. ContactsProsenter mam uplne prazdny (proste jen class ContactsPresenter extends BasePresenter {}). Je to spravne? Diky za odpoved :-)
22 | 24. 9. 2011, 12:40 | comment
@pavel86: spíš se mi to jeví, jako nefunkční mod_rewrite na tvém serveru. Routy se mi při zběžném pohledu zdají ok.
Kranox | 17. 12. 2011, 2:59 | comment
Za „use Nette\Application\UI\Presenter“ chýba bodkočiarka :) Ale aspoň viem že ladenka funguje :) A niekto tu tuším vymazal aj css nie len ostatné zdrojáky :) Ach jaj, to aby som si tie css vymýšľal sám teraz :(
Jan Tvrdík | 17. 12. 2011, 20:25 | comment
Reakce na Kranox: Díky za upozornění, opravil jsem to.

Jan Tvrdík | 27. 1. 2010, 7:57 | comment
Statický web bych v Nette řešil pomocí jednoho
StaticPresenterua přepsáním metodyPresenter::formatTemplateFiles.