Модули

Модулите внасят яснота в приложенията на Nette, като улесняват лесното им разделяне на логически единици.

Подобно на организирането на файловете в папки на твърдия диск, в Nette можем да разделим презентатори, шаблони и други спомагателни класове на модули. Как работи това на практика? Просто чрез включване на нови поддиректории в структурата. Ето един пример за структура с два модула – Front и Admin:

app/
├── UI/
│   ├── Admin/            ← Admin module
│   │   ├── @layout.latte
│   │   ├── Dashboard/
│   │   │   ├── DashboardPresenter.php
│   │   │   └── default.latte
│   │   └── ...
│   ├── Front/            ← Front module
│   │   ├── @layout.latte
│   │   ├── Home/
│   │   │   ├── HomePresenter.php
│   │   │   └── default.latte
│   │   └── ...

Тази структура на директориите е отразена в пространствата от имена на класовете, така че например DashboardPresenter се намира в пространството от имена App\UI\Admin\Dashboard:

namespace App\UI\Admin\Dashboard;

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

В приложението се позоваваме на презентатора Dashboard в рамките на модула Admin, като използваме запис с двоеточие като Admin:Dashboard. За неговото действие default го наричаме Admin:Dashboard:default.

Представената структура не е твърда; в конфигурацията можете напълно да я адаптирате към вашите нужди.

Модулите могат да включват всички други файлове, като компоненти и спомагателни класове, в допълнение към презентаторите и шаблоните. Ако обмисляте къде да ги поставите, помислете за използването на папка Accessory:

app/
├── UI/
│   ├── Admin/
│   │   ├── Accessory/
│   │   │   ├── FormFactory.php
│   │   │   └── AdminLayout.php
│   │   ├── Dashboard/
│   │   └── ...

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

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

app/
├── UI/
│   ├── Blog/             ← Blog module
│   │   ├── Admin/        ← Admin submodule
│   │   │   ├── Dashboard/
│   │   │   └── ...
│   │   ├── Front/        ← Front submodule
│   │   │   ├── @layout.latte
│   │   │   ├── Home/
│   │   │   └── ...
│   ├── Forum/            ← Forum module
│   │   └── ...

Модулът Blog е разделен на подмодули Admin и Front. Това е отразено и в пространствата от имена, които след това се появяват като App\UI\Blog\Admin и по подобен начин. За да се позовем на презентатора Dashboard в рамките на подмодула Admin, го наричаме Blog:Admin:Dashboard.

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

Например, ако в администрацията имате много презентатори, свързани с управлението на поръчки, като OrderDetail, OrderEdit, OrderDispatch и т.н., може да създадете модул Order, в който ще бъдат организирани презентатори като Detail, Edit, Dispatch и други.

Връзките в главните шаблони са относителни към текущия модул. По този начин връзка 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.

Структурите на директориите, споменати по-рано на тази страница, се основават на следното съпоставяне:

application:
	mapping: App\UI\*\**Presenter

Как работи картографирането? За по-добро разбиране нека първо си представим приложение без модули. Искаме класовете на презентаторите да попадат в пространството от имена App\UI, така че презентаторът Home да се съпостави с класа App\UI\HomePresenter. Това може да се постигне с тази конфигурация:

application:
	mapping: App\UI\*Presenter

Това съпоставяне се извършва чрез замяна на звездичката в маската App\UI\*Presenter с името на презентатора Home, в резултат на което се получава крайното име на класа App\UI\HomePresenter. Просто!

Въпреки това, както можете да видите в примерите в тази и други глави, ние поставяме класовете на водещите в едноименни поддиректории, например водещият Home е картографиран към клас App\UI\Home\HomePresenter. Това се постига чрез удвояване на звездичката (изисква Nette Application 3.2):

application:
	mapping: App\UI\**Presenter

Сега нека преминем към картографиране на презентатори в модули. Можем да дефинираме специфични съпоставки за всеки модул:

application:
	mapping:
		Front: App\UI\Front\**Presenter
		Admin: App\UI\Admin\**Presenter
		Api: App\Api\*Presenter

Според тази конфигурация презентаторът Front:Home се съотнася към класа App\UI\Front\Home\HomePresenter, а презентаторът Api:OAuth се съотнася към класа App\Api\OAuthPresenter.

Тъй като модулите Front и Admin имат сходен подход на картографиране и вероятно има повече такива модули, е възможно да се създаде общо правило, което да ги замени. Към маската на класа се добавя нова звездичка за модула:

application:
	mapping:
		*: App\UI\*\**Presenter
		Api: App\Api\*Presenter

За вложени модули на няколко нива, като например водещия Admin:User:Edit, сегментът със звездичка се повтаря за всяко ниво, в резултат на което се получава клас App\UI\Admin\User\Edit\EditPresenter.

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

application:
	mapping:
		*: [App\UI, *, **Presenter]
		Api: [App\Api, '', *Presenter]

Ако имаме само едно правило в конфигурацията, общото, можем да го напишем накратко:

application:
	mapping: App\UI\*\**Presenter