Nette Documentation Preview

syntax
Moduły
******

.[perex]
W Nette moduły reprezentują logiczne jednostki, które tworzą aplikację. Należą do nich prezentery, szablony, ewentualnie komponenty i klasy modeli.

Jeden komponent dla prezenterów i jeden dla szablonów nie wystarczyłby dla prawdziwych projektów. Posiadanie kilkudziesięciu plików w jednym folderze jest co najmniej niezorganizowane. Jak się z niego wydostać? Po prostu dzielimy je na podkatalogi na dysku i na przestrzenie nazw w kodzie. I właśnie to robią moduły Nette.

Zapomnijmy więc o jednym folderze dla prezenterów i szablonów, a zamiast tego stwórzmy moduły, na przykład `Admin` i `Front`.

/--pre
<b>app/</b>
├── <del>Presenters/</del>
├── <b>Modules/</b>              ← adresář s moduly
│   ├── <b>Admin/</b>            ← modul Admin
│   │   ├── <b>Presenters/</b>   ← jeho presentery
│   │   │   ├── <b>DashboardPresenter.php</b>
│   │   │   └── <b>templates/</b>
│   └── <b>Front/</b>            ← modul Front
│       └── <b>Presenters/</b>   ← jeho presentery
│           └── ...
\--

Ta struktura katalogów będzie odzwierciedlona w przestrzeni nazw klas, więc na przykład `DashboardPresenter` będzie w przestrzeni `App\Modules\Admin\Presenters`:

```php
namespace App\Modules\Admin\Presenters;

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

Prezenter `Dashboard` wewnątrz modułu `Admin` jest określany w aplikacji za pomocą notacji z podwójną kropką jako `Admin:Dashboard`, a jego działanie `default` jest określane jako `Admin:Dashboard:default`.
A skąd Nette own wie, że `Admin:Dashboard` reprezentuje klasę `App\Modules\Admin\Presenters\DashboardPresenter`? Mówimy to za pomocą [mapowania |#Mappings] w konfiguracji.
Tak więc podana struktura nie jest stała i można ją modyfikować według potrzeb.

Moduły mogą oczywiście zawierać wszystkie inne części oprócz prezenterów i szablonów, jak komponenty, klasy modeli itp.


Moduły zagnieżdżone .[#toc-nested-modules]
------------------------------------------

Moduły nie muszą tworzyć tylko płaskiej struktury, można też tworzyć np. submoduły:

/--pre
<b>app/</b>
├── <b>Modules/</b>              ← adresář s moduly
│   ├── <b>Blog/</b>             ← modul Blog
│   │   ├── <b>Admin/</b>        ← submodul Admin
│   │   │   ├── <b>Presenters/</b>
│   │   │   └── ...
│   │   └── <b>Front/</b>        ← submodul Front
│   │       ├── <b>Presenters/</b>
│   │       └── ...
│   ├── <b>Forum/</b>            ← modul Forum
│   │   └── ...
\--

Tak więc moduł `Blog` jest podzielony na podmoduły `Admin` i `Front`. I znowu będzie to odzwierciedlone w przestrzeni nazw, która będzie `App\Modules\Blog\Admin\Presenters` itd. Prezenter `Dashboard` wewnątrz submodułu jest określany jako `Blog:Admin:Dashboard`.

Rozgałęzienie może iść tak głęboko, jak chcesz, więc możesz tworzyć podmoduły.


Tworzenie linków .[#toc-creating-links]
---------------------------------------

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:

```latte
<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ł:

```latte
<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:

```latte
<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)`.

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


Routing .[#toc-routing]
-----------------------

Patrz [rozdział dotyczący routingu |routing#Modules].


Mapowanie .[#toc-mapping]
-------------------------

Określa zasady, według których nazwa klasy jest wyprowadzana z nazwy prezentera. Zapisujemy je w [konfiguracji |configuration] pod kluczem `application › mapping`.

Zacznijmy od próbki, która nie korzysta z modułów. Będziemy chcieli, aby klasy prezentera miały przestrzeń nazw `App\Presenters`. To znaczy, będziemy chcieli, aby prezenter, na przykład, `Home` mapował do klasy `App\Presenters\HomePresenter`. Można to osiągnąć dzięki następującej konfiguracji:

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

Zastąp nazwę prezentera gwiazdką w masce klasy, a wynikiem będzie nazwa klasy. Spokojnie!

Jeśli złamiemy prezenterów na moduły, możemy mieć niestandardowe mapowanie dla każdego modułu:

```neon
application:
	mapping:
		Front: App\Modules\Front\Presenters\*Presenter
		Admin: App\Modules\Admin\Presenters\*Presenter
		Api: App\Api\*Presenter
```

Teraz prezenter `Front:Home` mapuje do klasy `App\Modules\Front\Presenters\HomePresenter`, a prezenter `Admin:Dashboard` mapuje do klasy `App\Modules\Admin\Presenters\DashboardPresenter`.

Bardziej praktyczne będzie stworzenie ogólnej (gwiazdkowej) reguły, która zastąpi pierwsze dwie. W masce klasy zostanie dodana dodatkowa gwiazdka tylko dla tego modułu:

```neon
application:
	mapping:
		*: App\Modules\*\Presenters\*Presenter
		Api: App\Api\*Presenter
```

Ale co w przypadku, gdy korzystamy z wielu zagnieżdżonych modułów i mamy np. prezentera `Admin:User:Edit`? W takim przypadku segment z gwiazdką reprezentujący moduł dla każdego poziomu zostanie po prostu powtórzony, a wynikiem będzie klasa `App\Modules\Admin\User\Presenters\EditPresenter`.

Alternatywną notacją jest użycie tablicy składającej się z trzech segmentów zamiast ciągu. Ta notacja jest równoważna z poprzednią:

```neon
application:
	mapping:
		*: [App\Modules, *, Presenters\*Presenter]
```

Wartość domyślna to `*: *Module\*Presenter`.

Moduły

W Nette moduły reprezentują logiczne jednostki, które tworzą aplikację. Należą do nich prezentery, szablony, ewentualnie komponenty i klasy modeli.

Jeden komponent dla prezenterów i jeden dla szablonów nie wystarczyłby dla prawdziwych projektów. Posiadanie kilkudziesięciu plików w jednym folderze jest co najmniej niezorganizowane. Jak się z niego wydostać? Po prostu dzielimy je na podkatalogi na dysku i na przestrzenie nazw w kodzie. I właśnie to robią moduły Nette.

Zapomnijmy więc o jednym folderze dla prezenterów i szablonów, a zamiast tego stwórzmy moduły, na przykład Admin i Front.

app/
├── Presenters/
├── Modules/              ← adresář s moduly
│   ├── Admin/            ← modul Admin
│   │   ├── Presenters/   ← jeho presentery
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← modul Front
│       └── Presenters/   ← jeho presentery
│           └── ...

Ta struktura katalogów będzie odzwierciedlona w przestrzeni nazw klas, więc na przykład DashboardPresenter będzie w przestrzeni App\Modules\Admin\Presenters:

namespace App\Modules\Admin\Presenters;

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

Prezenter Dashboard wewnątrz modułu Admin jest określany w aplikacji za pomocą notacji z podwójną kropką jako Admin:Dashboard, a jego działanie default jest określane jako Admin:Dashboard:default. A skąd Nette own wie, że Admin:Dashboard reprezentuje klasę App\Modules\Admin\Presenters\DashboardPresenter? Mówimy to za pomocą mapowania w konfiguracji. Tak więc podana struktura nie jest stała i można ją modyfikować według potrzeb.

Moduły mogą oczywiście zawierać wszystkie inne części oprócz prezenterów i szablonów, jak komponenty, klasy modeli itp.

Moduły zagnieżdżone

Moduły nie muszą tworzyć tylko płaskiej struktury, można też tworzyć np. submoduły:

app/
├── Modules/              ← adresář s moduly
│   ├── Blog/             ← modul Blog
│   │   ├── Admin/        ← submodul Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← submodul Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← modul Forum
│   │   └── ...

Tak więc moduł Blog jest podzielony na podmoduły Admin i Front. I znowu będzie to odzwierciedlone w przestrzeni nazw, która będzie App\Modules\Blog\Admin\Presenters itd. Prezenter Dashboard wewnątrz submodułu jest określany jako Blog:Admin:Dashboard.

Rozgałęzienie może iść tak głęboko, jak chcesz, więc możesz tworzyć podmoduły.

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

Określa zasady, według których nazwa klasy jest wyprowadzana z nazwy prezentera. Zapisujemy je w konfiguracji pod kluczem application › mapping.

Zacznijmy od próbki, która nie korzysta z modułów. Będziemy chcieli, aby klasy prezentera miały przestrzeń nazw App\Presenters. To znaczy, będziemy chcieli, aby prezenter, na przykład, Home mapował do klasy App\Presenters\HomePresenter. Można to osiągnąć dzięki następującej konfiguracji:

application:
	mapping:
		*: App\Presenters\*Presenter

Zastąp nazwę prezentera gwiazdką w masce klasy, a wynikiem będzie nazwa klasy. Spokojnie!

Jeśli złamiemy prezenterów na moduły, możemy mieć niestandardowe mapowanie dla każdego modułu:

application:
	mapping:
		Front: App\Modules\Front\Presenters\*Presenter
		Admin: App\Modules\Admin\Presenters\*Presenter
		Api: App\Api\*Presenter

Teraz prezenter Front:Home mapuje do klasy App\Modules\Front\Presenters\HomePresenter, a prezenter Admin:Dashboard mapuje do klasy App\Modules\Admin\Presenters\DashboardPresenter.

Bardziej praktyczne będzie stworzenie ogólnej (gwiazdkowej) reguły, która zastąpi pierwsze dwie. W masce klasy zostanie dodana dodatkowa gwiazdka tylko dla tego modułu:

application:
	mapping:
		*: App\Modules\*\Presenters\*Presenter
		Api: App\Api\*Presenter

Ale co w przypadku, gdy korzystamy z wielu zagnieżdżonych modułów i mamy np. prezentera Admin:User:Edit? W takim przypadku segment z gwiazdką reprezentujący moduł dla każdego poziomu zostanie po prostu powtórzony, a wynikiem będzie klasa App\Modules\Admin\User\Presenters\EditPresenter.

Alternatywną notacją jest użycie tablicy składającej się z trzech segmentów zamiast ciągu. Ta notacja jest równoważna z poprzednią:

application:
	mapping:
		*: [App\Modules, *, Presenters\*Presenter]

Wartość domyślna to *: *Module\*Presenter.