Nette Framework: adresářová struktura aplikace

Pokračujeme s aplikací Automat na kávu a zaměříme se na její adresářovou strukturu. K čemu slouží zaváděcí soubor a jak souvisí Nette Framework se životním prostředím? Lze dát sbohem příkazu require_once?

Seriál: Začínáme s Nette Framework (17 dílů)

  1. Nette Framework: zvyšte svoji produktivitu 10.3.2009
  2. Nette Framework: Odvšivujeme 17.3.2009
  3. Nette Framework: MVC & MVP 24.3.2009
  4. Nette Framework: Refactoring 31.3.2009
  5. Nette Framework: Chytré šablony 7.4.2009
  6. Nette Framework: adresářová struktura aplikace 14.4.2009
  7. Nette Framework: AJAX 21.4.2009
  8. Nette Framework: AJAX (pokračování) 28.4.2009
  9. Nette Framework: AJAX (dokončení) 5.5.2009
  10. Nette Framework: Sessions 12.5.2009
  11. Nette Framework: Přihlašování uživatelů 19.5.2009
  12. Nette Framework: Ověřování oprávnění a role 26.5.2009
  13. Nette Framework: Neprůstřelné formuláře 2.6.2009
  14. Nette Framework: Neprůstřelné formuláře II 9.6.2009
  15. Nette Framework: Neprůstřelné formuláře III 16.6.2009
  16. Nette Framework: Cache 23.6.2009
  17. Nette Framework: Co se do seriálu nevešlo? 30.6.2009

Pojďme se podívat podrobněji na adresářovou strukturu a jednotlivé soubory aplikace Automat na kávu (ke stažení na konci článku). Celý projekt je rozdělen do tří adresářů:

  • app  – obsahuje všechny soubory serverové části aplikace
  • libs  – obsahuje knihovny třetích stran, mohou být společné pro více aplikací
  • document_root  – kořenový adresář dostupný přes prohlížeč

Jakýkoliv požadavek na HTTP server je směrován dovnitř adresáře document_root. Zde se nacházejí všechny obrázky, kaskádové styly, javascriptové soubory. A také soubor index.php, přes který vedou všechny požadavky na HTML stránky. Pokud bychom používali tzv. Cool URL, vytvořili bychom pravidlo mod_rewrite, které by opět všechny požadavky na stránku nasměrovalo skrz index.php.

Přičemž index.php nedelá nic jiného, než že definuje cesty k ostatním dvou adresářům app a libs (jako konstanty) a předá řízení zaváděcímu souboru aplikace.

define('WWW_DIR', dirname(__FILE__)); // path to the web root
define('APP_DIR', WWW_DIR . '/../app'); // path to the application root
define('LIBS_DIR', WWW_DIR . '/../libs'); // path to the libraries

require APP_DIR . '/bootstrap.php'; // load bootstrap file 

Pojmenování a umístění jednotlivých adresářů je zcela ve vaší režii. Pokud preferujete jiné konvence, račte si je dopřát. Stačí jen změnit cesty v  index.php a aplikace dál poběží, jako by se nechumelilo. Nezapomeňte dohlédnout na to, aby adresáře aplikace a knihoven byly nepřístupné z webového prohlížeče. Například pomocí pravidel v souboru  .htaccess:

Order Allow,Deny
Deny from all 

Zaváděcí soubor

Zaváděcí soubor app/bootstrap.php nejprve vykoná nám již známé operace. Načte framework, aktivuje Laděnku a pro jistotu zkontroluje, zda lze zapisovat do adresáře pro dočasné soubory.

// Krok 1: Načtení Nette Framework
require LIBS_DIR . '/Nette/loader.php';

// Krok 2: Konfigurace prostředí
// 2a) zapne NetteDebug pro lepší vizualizaci a zpracování chyb
Debug::enable();

// 2b) kontrola, zda je složka /app/temp zapisovatelná
if (@file_put_contents(Environment::expand('%tempDir%/_check'), '') === FALSE) {
        throw new Exception("Make directory '" . Environment::getVariable('tempDir') . "' writable!");
} 

Poté následuje nastavení routeru a samotné spuštění aplikace. Zatímco routování je kapitolou samo o sobě (tedy alespoň z pohledu tohoto seriálu), o třídě NetteEnviron­ment, jejíž jméno v ukázce zdrojového kódu padlo, si něco povíme hned.

Třída Environment

Kladnozelený vztah Nette Frameworku k životnímu prostředí webové aplikace signalizuje skutečnost, že si nevytváří žádné globální proměnné nebo konstanty. Celé prostředí má pod palcem statická třída NetteEnviron­ment. Ta slouží jako globální úložiště pro:

  • proměnné prostředí (obvykle cesty, třeba k dočasnému adresáři)
  • název a režimy prostředí
  • konfiguraci aplikace
  • singletony

Proměnné prostředí lze nastavit a získat pomocí těchto dvou metod:

// pokud používáte verzi pro PHP 5.3, odkomentujte následující řádek:
// use NetteEnvironment;

Environment::setVariable('foo', 'Hello World');
echo Environment::getVariable('foo'); // -> Hello World 

Framework zjednoduší provázání i na konstanty definované v souboru index.php. Pokud například požádáte o nedefinovanou proměnnou appDir, zkusí se podívat, jestli neexistuje konstanta APP_DIR a vrátit její hodnotu. Hlavní výhoda tohoto řešení se projeví při využití další vlastnosti konstant, a tou je rozvíjení.

// mezi znaky % je název konstanty
Environment::setVariable('foo', 'Rozvíjej se %poupatko%');
Environment::setVariable('poupatko', 'programátore');
echo Environment::getVariable('foo'); // -> Rozvíjej se programátore 

Díky tomu je možné definovat jako proměnné absolutní cesty, ačkoliv známe jen cestu relativní. Například jako dočasný adresář chceme nastavit app/temp, ale absolutní cestu k app  neznáme (tu definuje index.php konstatnou APP_DIR). Lze však nastavit:

Environment::setVariable('tempDir', '%appDir%/temp');
echo Environment::getVariable('tempDir');
// -> vypíše absolutní cestu, neboť nahradí %appDir% za konstantu APP_DIR 

Pro rozvinutí proměnné bez její definice lze použít metodu expand, jak toho využívá kód v  bootstrap.php ověřující, zda lze do dočasného adresáře zapisovat.

Sbohem všem require dej

PHP disponuje čtyřmi příkazy pro načtení skriptu z jiného souboru. Tedy require, include a jejich sourozenci s koncovkou _once. Pokud je cesta k souboru relativní, dohledává se skript mně naprosto nepochopitelným způsobem, proto také poučení programátoři používají cesty absolutní. A jelikož magická konstanta __DIR__ přijde až s PHP 5.3, hromadí se na začátcích souborů haldy něčeho takového:

require_once dirname(__FILE__) . '/libs/ClassA.php';
require_once dirname(__FILE__) . '/libs/ClassB.php';
require_once dirname(__FILE__) . '/libs/ClassC.php';
... 

Z estetického hlediska jde o zástupce ASCII art deco, povšimněte si zvláště půvabného spojení závorek s podtržítky. V odborných kruzích však podobné obrazy nesou název „Serverova smrt“ a společně s výjevem Hieronyma Bosche „.htaccess obsahující 486 pravidel RewriteRule“ se jimi straší malé, čerstvě vylíhlé, revize Apache.

Skutečně se ukazuje, že jedním z největších zabijáků výkonu PHP je načítání velkého množství souborů (navíc nejsou-li absolutně adresováné). Co se s tím dá dělat? Účinnou zbraní je kompaktní minimalizovaná verze frameworku, viz první díl seriálu. Díky ní celý Nette Framework načtete jedním jediným příkazem:

require 'Nette/loader.php'; 

Pokud ale minimalizované verze nejsou k dispozici nebo by jejich použití nebylo vhodné, dá se dosáhnout velké úspory výkonu tím, že budeme načítat pouze soubory, které skutečně potřebujeme. A tomu slouží autoloading.

Nutno říci, že zvýšení výkonu aplikací je pouze druhotným efektem autoloadingu. Prim drží pohodlí, které s ním programátor získá. Bude moci přestat používat příkaz require a velmi rychle zjístí, jak je to návykové.

Autoloading zajišťuje obslužná funkce, která jako parametr dostane jméno třídy/interface a jejím úkolem je načíst skript s definicí. Otázkou zůstává, jak obecně odvodit z názvu třídy jméno souboru?

(Poznámka: špatně napsaný autoloadovací handler může vést k citelnému snížení výkonu aplikace.)

(Poznámka č.2: vyšší zátěž serverů vede ke globálnímu oteplování serverovny.)

RobotLoader

Třída NetteLoadersRobotLoader na to jde způsobem, který znáte od vyhledávačů. Podobně jako roboti vyhledávačů procházejí a indexují všechny stránky, tak i RobotLoader prochází všechny PHP skripty a zaznamenává si, které třídy a rozhraní v nich našel. Výsledky bádání si poté uloží do cache a použije při dalším HTTP požadavku. Stačí tedy určit, které adresáře má procházet (předpokládejme, že cesty se nacházejí v konstantách APP_DIRLIBS_DIR):

Následující řádky je možné přidat do zaváděcího souboru bootstrap.php a poté lze odstranit všechny require_once použité v aplikaci.

// pokud používáte verzi pro PHP 5.3, odkomentujte následující řádek:
// use NetteLoadersRobotLoader;

$loader = new RobotLoader();
$loader->addDirectory(APP_DIR);
$loader->addDirectory(LIBS_DIR);
$loader->register(); 

Pokud byste chtěli využít služeb RobotLoaderu mimo MVP aplikace Nette, je potřeba nastavit cestu k dočasnému adresáři do proměnné prostředí  tempDir:

Environment::setVariable('tempDir', '/absolutní/cesta/k/temp'); 

RobotLoader pracuje s cache inteligentně. Při vytvoření nové třídy ji invaliduje a zároveň si pamatuje, které třídy v adresářové struktuře nenašel. Můžete tedy pohodlně rozvíjet svou aplikaci a RobotLoader vám v tom bude sekundovat.

Ještě perlička na závěr: pokud byste chtěli určitý podadresář z indexování vynechat, vytvořte soubor netterobots.txt se známou syntaxí:

Disallow: Zend 
Zdrojový kód ukázek je k dispozici ke stažení.

Pokračování příště

Příště nás čeká atraktivní téma: JavaScript, AJAX a bohaté aplikace.


Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Pravidelně pořádá školení pro tvůrce webových aplikací, vyvíjí open-source knihovny Texy, dibi a Nette Framework.

David Grudl školí, je autorem PHP knihoven Nette Framework, databázové vrstvy dibi a formátovače HTML kódu Texy!.

Komentáře: 42

Přehled komentářů

Mastodont Styl Wordpressu
Martin Malý Re: Styl Wordpressu
Mastodont Re: Styl Wordpressu
Martin Malý Re: Styl Wordpressu
Jiří Knesl Re: Styl Wordpressu
David Grudl Re: Styl Wordpressu
Martin Malý Autoloader
aprilchild Re: Autoloader
Martin Malý Re: Autoloader
David Grudl Re: Autoloader
Martin Malý Re: Autoloader
David Grudl Re: Autoloader
Martin Malý Re: Autoloader
v6ak Problém vrstvy navíc
Martin Malý Re: Problém vrstvy navíc
v6ak Re: Problém vrstvy navíc
Martin Malý Re: Problém vrstvy navíc
Jiří Knesl Re: Problém vrstvy navíc
Martin Malý Re: Problém vrstvy navíc
v6ak Re: Problém vrstvy navíc
yeah RE: Nette Framework: adresářová struktura aplikace
hejhula Re: RE: Nette Framework: adresářová struktura aplikace
Borek Bernard Víc konfigurací
David Grudl Re: Víc konfigurací
Borek Bernard Re: Víc konfigurací
Pavel Voska Re: Víc konfigurací
tomik.vitek Re: Víc konfigurací
David Grudl Re: Víc konfigurací
Srigi Re: Víc konfigurací
Miloslav Pojman RE: Nette Framework: adresářová struktura aplikace
David Grudl RE: Nette Framework: adresářová struktura aplikace
v6ak RE: Nette Framework: adresářová struktura aplikace
Miloslav Pojman RE: Nette Framework: adresářová struktura aplikace
David Grudl RE: Nette Framework: adresářová struktura aplikace
David Grudl RE: Nette Framework: adresářová struktura aplikace
Miloslav Pojman RE: Nette Framework: adresářová struktura aplikace
David Grudl RE: Nette Framework: adresářová struktura aplikace
Jakub Vrána RE: Nette Framework: adresářová struktura aplikace
Miloslav Pojman RE: Nette Framework: adresářová struktura aplikace
Jakub Vrána RE: Nette Framework: adresářová struktura aplikace
Miloslav Pojman RE: Nette Framework: adresářová struktura aplikace
Jakub Vrána RE: Nette Framework: adresářová struktura aplikace
Zdroj: https://www.zdrojak.cz/?p=2988