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