Moduły

Moduły zapewniają przejrzystość aplikacji Nette, ułatwiając podział na logiczne jednostki.

Podobnie jak w przypadku organizowania plików w foldery na dysku twardym, w Nette możemy podzielić prezenterów, szablony i inne klasy pomocnicze na moduły. Jak to działa w praktyce? Po prostu poprzez włączenie nowych podkatalogów do struktury. Oto przykład struktury z dwoma modułami, Front i Admin:

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

Ta struktura katalogów jest odzwierciedlona w przestrzeniach nazw klas, więc na przykład DashboardPresenter znajduje się w przestrzeni nazw App\UI\Admin\Dashboard:

namespace App\UI\Admin\Dashboard;

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

W aplikacji odnosimy się do prezentera Dashboard w module Admin używając notacji dwukropka jako Admin:Dashboard. W przypadku akcji default odnosimy się do niej jako Admin:Dashboard:default.

Przedstawiona struktura nie jest sztywna; można ją w pełni dostosować do własnych potrzeb w konfiguracji.

Moduły mogą zawierać wszystkie inne pliki, takie jak komponenty i klasy pomocnicze, oprócz prezenterów i szablonów. Jeśli zastanawiasz się, gdzie je umieścić, rozważ użycie folderu Accessory:

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

Moduły zagnieżdżone

Moduły mogą mieć wiele poziomów zagnieżdżenia, podobnie jak struktura katalogów na dysku:

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

Moduł Blog jest podzielony na podmoduły Admin i Front. Jest to również odzwierciedlone w przestrzeniach nazw, które następnie pojawiają się jako App\UI\Blog\Admin i podobnie. Aby odnieść się do prezentera Dashboard w podmodule Admin, odnosimy się do niego jako Blog:Admin:Dashboard.

Zagnieżdżanie może być tak głębokie, jak potrzeba, umożliwiając tworzenie podmodułów.

Na przykład, jeśli w administracji masz wiele prezenterów związanych z zarządzaniem zamówieniami, takich jak OrderDetail, OrderEdit, OrderDispatch, itp., możesz utworzyć moduł Order, w którym będą zorganizowane prezentery takie jak Detail, Edit, Dispatch, i inne.

Linki w szablonach prezenterów są względne do bieżącego modułu. Tak więc link Foo:default prowadzi do prezentera Foo w tym samym module co aktualny prezenter. Na przykład, jeśli bieżący moduł to Front, to link idzie tak:

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

Link jest względny, nawet jeśli nazwa modułu jest jego częścią, jest wtedy uważany za submoduł:

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

Odwołania bezwzględne są zapisywane analogicznie do ścieżek bezwzględnych na dysku, ale z dwukropkami zamiast ukośników. Tak więc link bezwzględny zaczyna się od dwukropka:

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

Aby dowiedzieć się, czy jesteśmy w danym module lub submodule, korzystamy z funkcji isModuleCurrent(moduleName).

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

Routing

Patrz rozdział dotyczący routingu.

Mapowanie

Mapowanie definiuje zasady wyprowadzania nazwy klasy z nazwy prezentera. Reguły te są określone w konfiguracji pod kluczem application › mapping.

Struktury katalogów wspomniane wcześniej na tej stronie są oparte na następującym mapowaniu:

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

Jak działa mapowanie? Dla lepszego zrozumienia, wyobraźmy sobie najpierw aplikację bez modułów. Chcemy, aby klasy prezenterów należały do przestrzeni nazw App\UI, tak aby prezenter Home był mapowany na klasę App\UI\HomePresenter. Można to osiągnąć za pomocą tej konfiguracji:

application:
	mapping: App\UI\*Presenter

Mapowanie to polega na zastąpieniu gwiazdki w masce App\UI\*Presenter nazwą prezentera Home, co daje końcową nazwę klasy App\UI\HomePresenter. Proste!

Jednakże, jak widać w przykładach w tym i innych rozdziałach, umieszczamy klasy prezenterów w podkatalogach o tej samej nazwie, np. prezenter Home jest mapowany na klasę App\UI\Home\HomePresenter. Osiąga się to poprzez podwojenie gwiazdki (wymaga Nette Application 3.2):

application:
	mapping: App\UI\**Presenter

Przejdźmy teraz do mapowania prezenterów na moduły. Możemy zdefiniować konkretne mapowania dla każdego modułu:

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

Zgodnie z tą konfiguracją, prezenter Front:Home mapuje się do klasy App\UI\Front\Home\HomePresenter, podczas gdy prezenter Api:OAuth mapuje się do klasy App\Api\OAuthPresenter.

Ponieważ moduły Front i Admin mają podobne podejście do mapowania i prawdopodobnie będzie więcej takich modułów, możliwe jest utworzenie ogólnej reguły, która je zastąpi. Nowa gwiazdka dla modułu jest dodawana do maski klasy:

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

W przypadku wielopoziomowych zagnieżdżonych modułów, takich jak prezenter Admin:User:Edit, segment gwiazdki powtarza się dla każdego poziomu, dając w rezultacie klasę App\UI\Admin\User\Edit\EditPresenter.

Alternatywnym zapisem jest użycie tablicy złożonej z trzech segmentów zamiast łańcucha. Ta notacja jest równoważna poprzedniej:

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

Jeśli mamy tylko jedną regułę w konfiguracji, tę ogólną, możemy napisać krótko:

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