Модули

Модули вносят ясность в приложения 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>

Маршрутизация

См. главу о маршрутизации.

Составление карты

Mapping определяет правила получения имени класса из имени ведущего. Эти правила задаются в конфигурации под ключом 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