Adresářová struktura aplikace
Jak navrhnout přehlednou a škálovatelnou adresářovou strukturu pro projekty v Nette Framework? Ukážeme si osvědčené postupy, které vám pomohou s organizací kódu. Dozvíte se:
- jak logicky rozčlenit aplikaci do adresářů
- jak strukturu navrhnout tak, aby dobře škálovala s růstem projektu
- jaké jsou možné alternativy a jejich výhody či nevýhody
Důležité je zmínit, že Nette Framework samotný na žádné konkrétní struktuře nelpí. Je navržen tak, aby se dal snadno přizpůsobit jakýmkoliv potřebám a preferencím.
Základní struktura projektu
Přestože Nette Framework nediktuje žádnou pevnou adresářovou strukturu, existuje osvědčené výchozí uspořádání v podobě Web Project:
web-project/ ├── app/ ← adresář s aplikací ├── assets/ ← soubory SCSS, JS, obrázky..., alternativně resources/ ├── bin/ ← skripty pro příkazovou řádku ├── config/ ← konfigurace ├── log/ ← logované chyby ├── temp/ ← dočasné soubory, cache ├── tests/ ← testy ├── vendor/ ← knihovny instalované Composerem └── www/ ← veřejný adresář (document-root)
Tuto strukturu můžete libovolně upravovat podle svých potřeb – složky přejmenovat či přesouvat. Poté stačí pouze
upravit relativní cesty k adresářům v souboru Bootstrap.php
a případně composer.json
. Nic víc
není potřeba, žádná složitá rekonfigurace, žádné změny konstant. Nette disponuje chytrou autodetekcí a automaticky
rozpozná umístění aplikace včetně její URL základny.
Moduly
Moduly představují v Nette logické celky, ze kterých se aplikace skládá. Jejich součástí jsou presentery, šablony, případně i komponenty a modelové třídy.
S jednou složkou pro presentery a jednou pro šablony bychom si u reálných projektů nevystačili. Mít v jedné složce desítky souborů je minimálně nepřehledné. Jak z toho ven? Jednoduše je na disku rozdělíme do podadresářů a v kódu do jmenných prostorů. A přesně to jsou v Nette moduly.
Zapomeňme tedy na jednu složku pro presentery a šablony a místo toho vytvoříme moduly, například Admin
a
Front
.
app/ ├──presenters/├── modules/ ← adresář s moduly │ ├── Admin/ ← modul Admin │ │ ├── presenters/ ← jeho presentery │ │ │ ├── DashboardPresenter.php │ │ │ └── templates/ │ └── Front/ ← modul Front │ └── presenters/ ← jeho presentery │ └── ...
Tuto adresářovou strukturu budou reflektovat jmenné prostory tříd, takže třeba DashboardPresenter
bude
v prostoru App\Modules\Admin\Presenters
:
namespace App\Modules\Admin\Presenters;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
Na presenter Dashboard
uvnitř modulu Admin
se v rámci aplikace odkazujeme pomocí dvojtečkové
notace jako na Admin:Dashboard
, na jeho akci default
potom jako na Admin:Dashboard:default
.
A jak Nette vlastní ví, že Admin:Dashboard
představuje třídu
App\Modules\Admin\Presenters\DashboardPresenter
? To mu řekneme pomocí mapování
v konfiguraci. Tedy uvedená struktura není pevná a můžete si ji upravit podle potřeb.
Moduly mohou kromě presenterů a šablon samozřejmě obsahovat všechny další součásti, jako jsou třeba komponenty, modelové třídy, atd.
Vnořené moduly
Moduly nemusí tvořit jen plochou strukturu, lze vytvářet i submoduly, například:
app/ ├── modules/ ← adresář s moduly │ ├── Blog/ ← modul Blog │ │ ├── Admin/ ← submodul Admin │ │ │ ├── presenters/ │ │ │ └── ... │ │ └── Front/ ← submodul Front │ │ ├── presenters/ │ │ └── ... │ ├── Forum/ ← modul Forum │ │ └── ...
Tedy modul Blog
je rozdělen do submodulů Admin
a Front
. A opět se to odrazí na
jmenných prostorech, které budou App\Modules\Blog\Admin\Presenters
apod. Na presenter Dashboard
uvnitř submodulu se odkazujeme jako Blog:Admin:Dashboard
.
Zanořování může pokračovat libovolně hluboko, lze tedy vytvářet sub-submoduly.
Mapování presenterů
Definuje pravidla, podle kterých se z názvu presenteru odvodí název třídy. Zapisujeme je v konfiguraci pod klíčem application › mapping
.
Začněme ukázkou, která moduly nepoužívá. Budeme jen chtít, aby třídy presenterů měly jmenný prostor
App\Presenters
. Tedy aby se presenter například Homepage
mapoval na třídu
App\Presenters\HomepagePresenter
. Toho lze docílit následující konfigurací:
application:
mapping:
*: App\Presenters\*Presenter
Název presenteru se nahradí za hvezdičku v masce třídy a výsledkem je název třídy. Snadné!
Pokud presentery členíme do modulů, můžeme pro každý modul mít vlastní mapování:
application:
mapping:
Front: App\Modules\Front\Presenters\*Presenter
Admin: App\Modules\Admin\Presenters\*Presenter
Api: App\Api\*Presenter
Nyní se presenter Front:Homepage
mapuje na třídu App\Modules\Front\Presenters\HomepagePresenter
a
presenter Admin:Dashboard
na třídu App\Modules\Admin\Presenters\DashboardPresenter
.
Praktičtější bude vytvořit obecné (hvězdičkové) pravidlo, které první dvě nahradí. V masce třídy přibude hvezdička navíc právě pro modul:
application:
mapping:
*: App\Modules\*\Presenters\*Presenter
Api: App\Api\*Presenter
Ale co když používáme vícenásobně zanořené moduly a máme třeba presenter Admin:User:Edit
? V takovém
případě se segment s hvězdičkou představující modul pro každou úroveň jednoduše zopakuje a výsledkem bude třída
App\Modules\Admin\User\Presenters\EditPresenter
.
Alternativním zápisem je místo řetězce použít pole skládající se ze tří segmentů. Tento zápis je ekvivaletní s předchozím:
application:
mapping:
*: [App\Modules, *, Presenters\*Presenter]
Výchozí hodnotou je *: *Module\*Presenter
.