Модули

В 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.