Модули

В Nette модулите са логическите единици, от които се състои едно приложение. Те включват главни модули, шаблони, евентуално компоненти и класове модели.

Един компонент за презентатори и един за шаблони няма да са достатъчни за реални проекти. Натрупването на десетки файлове в една папка е меко казано неорганизирано. Как да излезем от тази ситуация? Просто ги разделяме на поддиректории на диска и на пространства от имена в кода. Точно това правят модулите Nette.

Така че нека забравим за една папка за презентатори и шаблони и вместо това да създадем модули като Admin и Front.

app/
├── Presenters/
├── Modules/              ← директория с модулями
│   ├── Admin/            ← модуль Admin
│   │   ├── Presenters/   ← его презентеры
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← модуль Front
│       └── Presenters/   ← его презентеры
│           └── ...

Тази структура на директориите ще бъде отразена в пространствата за имена на класовете, така че например DashboardPresenter ще бъде в пространството App\Modules\Admin\Presenters:

namespace App\Modules\Admin\Presenters;

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

Главното устройство Dashboard в модула Admin се обозначава в приложението с помощта на запис с двойна точка като Admin:Dashboard, а неговото действие default се обозначава като Admin:Dashboard:default. И откъде Nette знае, че Admin:Dashboard представлява класа App\Modules\Admin\Presenters\DashboardPresenter? Говорим за това, като използваме картографирането в конфигурацията. Така че дадената структура не е фиксирана и можете да я променяте по свое усмотрение.

Модулите, разбира се, могат да съдържат всички други части, освен презентатори и шаблони, като компоненти, класове модели и др.

Вложени модули

Модулите не трябва да образуват само плоска структура, можете да създавате и подмодули, например:

app/
├── Modules/              ← директория с модулями
│   ├── Blog/             ← модуль Blog
│   │   ├── Admin/        ← подмодуль Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← подмодуль Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← модуль Forum
│   │   └── ...

Така модулът Blog се разделя на подмодули Admin и Front. Това отново ще бъде отразено в пространствата от имена, които ще бъдат App\Modules\Blog\Admin\Presenters и т.н. Главният модул Dashboard в рамките на подмодула се нарича Blog:Admin:Dashboard.

Разклоненията могат да бъдат толкова дълбоки, колкото искате, така че можете да създавате подмодули.

Връзките в главните шаблони са относителни към текущия модул. По този начин връзка Foo:default води до главния Foo в същия модул като текущия главен. Например, ако текущият модул е Front, връзката изглежда по следния начин

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

Връзката е относителна, дори ако името на модула е част от нея, тогава той се счита за подмодул:

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

Абсолютните връзки се записват подобно на абсолютните пътища на диска, но с двоеточие вместо с наклонена черта. Така абсолютната връзка започва с двоеточие:

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

За да разберем дали се намираме в определен модул или подмодул, използваме функцията isModuleCurrent(moduleName).

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

Маршрутизиране

Вижте главата за маршрутизиране.

Картографиране

Определя правилата, по които името на класа се извежда от главното име. Записваме ги в конфигурацията под ключа application › mapping.

Нека започнем с пример, при който не се използват модули. Искаме само главните класове да имат пространството от имена App\Presenters. Това означава, че искаме главното име, например Home, да се съпостави с класа App\Presenters\HomePresenter. Това може да се постигне със следната конфигурация:

application:
	mapping:
		*: App\Presenters\*Presenter

Името на водещия се заменя със звездичка и резултатът е името на класа. Лесно!

Ако разделим презентаторите на модули, можем да използваме различни карти за всеки модул:

application:
	mapping:
		Front: App\Modules\Front\Presenters\*Presenter
		Admin: App\Modules\Admin\Presenters\*Presenter
		Api: App\Api\*Presenter

Сега водещият Front:Home е определен от класа App\Modules\Front\HomePresenter, а презентер Admin:Dashboard – App\AdminModule\DashboardPresenter.

Би било по-удобно да се създаде общо правило (звездичка), което да замени първите две правила, и да се добави допълнителна звездичка само за модула:

application:
	mapping:
		*: App\Modules\*\Presenters\*Presenter
		Api: App\Api\*Presenter

Но какво става, ако използваме няколко вложени модула и имаме например главен модул Admin:User:Edit? В този случай сегментът със звездичка, представляващ модула за всяко ниво, просто ще се повтори и резултатът ще бъде класът App\Modules\Admin\User\Presenters\EditPresenter.

Алтернативен начин за записване е използването на масив от три сегмента вместо низ. Този запис е еквивалентен на предишния:

application:
	mapping:
		*: [App\Modules, *, Presenters\*Presenter]

Стойността по подразбиране е *: *Module\*Presenter.