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.

Vytváření odkazů

Odkazy v šablonách presenterů jsou relativní vůči aktuálnímu modulu. Tedy odkaz Foo:default vede na presenter Foo v tomtéž modulu, v jakém je aktuální presenter. Pokud je aktuální modul například Front, pak odkaz vede takto:

<a n:href="Product:show">odkaz na Front:Product:show</a>

Odkaz je relativní i pokud je jeho součástí název modulu, ten se pak považuje za submodul:

<a n:href="Shop:Product:show">odkaz na Front:Shop:Product:show</a>

Absolutní odkazy zapisujeme analogicky k absolutním cestám na disku, jen místo lomítek jsou dvojtečky. Tedy absolutní odkaz začíná dvojtečkou:

<a n:href=":Admin:Product:show">odkaz na Admin:Product:show</a>

Pro zjištění, zda jsme v určitém modulu nebo jeho submodulu, použijeme metodu $presenter->isModuleCurrent(moduleName).

<li n:class="$presenter->isModuleCurrent('Forum:Users') ? active">
	<a n:href="Product:">...</a>
</li>

Routování

Viz kapitola o routování.

Mapování

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.