Nette Documentation Preview

syntax
Модули
******

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

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

/--pre
app/
├── UI/
│   ├── <b>Admin/</b>            ← Admin module
│   │   ├── @layout.latte
│   │   ├── Dashboard/
│   │   │   ├── DashboardPresenter.php
│   │   │   └── default.latte
│   │   └── ...
│   ├── <b>Front/</b>            ← Front module
│   │   ├── @layout.latte
│   │   ├── Home/
│   │   │   ├── HomePresenter.php
│   │   │   └── default.latte
│   │   └── ...
\--

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

```php
namespace App\UI\Admin\Dashboard;

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

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

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

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

/--pre
app/
├── UI/
│   ├── Admin/
│   │   ├── <b>Accessory/</b>
│   │   │   ├── FormFactory.php
│   │   │   └── AdminLayout.php
│   │   ├── Dashboard/
│   │   └── ...
\--


Вложени модули .[#toc-nested-modules]
-------------------------------------

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

/--pre
app/
├── UI/
│   ├── <b>Blog/</b>             ← Blog module
│   │   ├── <b>Admin/</b>        ← Admin submodule
│   │   │   ├── Dashboard/
│   │   │   └── ...
│   │   ├── <b>Front/</b>        ← Front submodule
│   │   │   ├── @layout.latte
│   │   │   ├── Home/
│   │   │   └── ...
│   ├── <b>Forum/</b>            ← Forum module
│   │   └── ...
\--

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

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

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


Създаване на връзки .[#toc-creating-links]
------------------------------------------

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

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

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

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

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

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

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

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


Маршрутизиране .[#toc-routing]
------------------------------

Вижте [главата за маршрутизиране |routing#modules].


Картографиране .[#toc-mapping]
------------------------------

Съпоставянето определя правилата за извеждане на името на класа от името на водещия. Тези правила се посочват в [конфигурацията |configuration] под ключа `application › mapping`.

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

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

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

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

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

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

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

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

```neon
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` имат сходен подход на картографиране и вероятно има повече такива модули, е възможно да се създаде общо правило, което да ги замени. Към маската на класа се добавя нова звездичка за модула:

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

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

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

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

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

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

Модули

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