Module

În Nette, modulele reprezintă unitățile logice care alcătuiesc o aplicație. Acestea includ prezentatori, șabloane, eventual și componente și clase de model.

Un singur director pentru prezentatori și unul pentru șabloane nu ar fi suficient pentru proiectele reale. A avea zeci de fișiere într-un singur dosar este cel puțin neorganizat. Cum se poate ieși din asta? Pur și simplu le împărțim în subdirectoare pe disc și în spații de nume în cod. Și asta este exact ceea ce fac modulele Nette.

Așadar, să uităm de un singur dosar pentru prezentatori și șabloane și să creăm în schimb module, de exemplu Admin și Front.

app/
├── Presenters/
├── Modules/              ← directory with modules
│   ├── Admin/            ← module Admin
│   │   ├── Presenters/   ← its presenters
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← module Front
│       └── Presenters/   ← its presenters
│           └── ...

Această structură de directoare va fi reflectată de spațiile de nume ale claselor, astfel încât, de exemplu, DashboardPresenter va fi în spațiul de nume App\Modules\Admin\Presenters:

namespace App\Modules\Admin\Presenters;

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

Prezentatorul Dashboard din cadrul modulului Admin este referit în cadrul aplicației folosind notația de două puncte ca Admin:Dashboard, iar acțiunea default ca Admin:Dashboard:default. Și de unde știe Nette proper că Admin:Dashboard reprezintă clasa App\Modules\Admin\Presenters\DashboardPresenter? Acest lucru este determinat de cartografierea din configurație. Așadar, structura dată nu este prestabilită și o puteți modifica în funcție de nevoile dumneavoastră.

Modulele pot conține, bineînțeles, toate celelalte elemente în afară de prezentatori și șabloane, cum ar fi componente, clase de modele etc.

Module imbricate

Modulele nu trebuie să formeze doar o structură plată, ci puteți crea și submodule, de exemplu:

app/
├── Modules/              ← directory with modules
│   ├── Blog/             ← module Blog
│   │   ├── Admin/        ← submodule Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← submodule Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← module Forum
│   │   └── ...

Astfel, modulul Blog este împărțit în submodulele Admin și Front. Din nou, acest lucru se va reflecta în spațiile de nume, care vor fi App\Modules\Blog\Admin\Presenters etc. Prezentatorul Dashboard din interiorul submodulului este denumit Blog:Admin:Dashboard.

Anveloparea poate merge cât de adânc doriți, astfel încât pot fi create sub-submodule.

Legăturile din șabloanele de prezentator sunt relative la modulul curent. Astfel, legătura Foo:default duce la prezentatorul Foo din același modul ca și prezentatorul curent. Dacă modulul curent este Front, de exemplu, atunci legătura se prezintă astfel:

<a n:href="Product:show">link to Front:Product:show</a>

O legătură este relativă chiar dacă include numele unui modul, care este considerat atunci un submodul:

<a n:href="Shop:Product:show">link to Front:Shop:Product:show</a>

Legăturile absolute sunt scrise în mod analog cu căile absolute de acces de pe disc, dar cu două puncte în loc de bară oblică. Astfel, o legătură absolută începe cu două puncte:

<a n:href=":Admin:Product:show">link to Admin:Product:show</a>

Pentru a afla dacă ne aflăm într-un anumit modul sau într-un submodul al acestuia, putem utiliza funcția isModuleCurrent(moduleName).

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

Rutarea

A se vedea capitolul privind rutarea.

Cartografiere

Definește regulile prin care numele clasei este derivat din numele prezentatorului. Le scriem în configurație sub cheia application › mapping.

Să începem cu un exemplu care nu folosește module. Vom dori doar ca clasele de prezentator să aibă spațiul de nume App\Presenters. Aceasta înseamnă că un prezentator precum Home ar trebui să se mapeze la clasa App\Presenters\HomePresenter. Acest lucru poate fi realizat prin următoarea configurație:

application:
	mapping: App\Presenters\*Presenter

Numele prezentatorului este înlocuit cu un asterisc în masca clasei, iar rezultatul este numele clasei. Ușor!

Dacă împărțim prezentatorii în module, putem avea propria mapare pentru fiecare modul:

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

Acum, prezentatorul Front:Home se referă la clasa App\Modules\Front\Presenters\HomePresenter și prezentatorul Admin:Dashboard la clasa App\Modules\Admin\Presenters\DashboardPresenter.

Este mai practic să creăm o regulă generală (stea) care să le înlocuiască pe primele două. Asteriscul suplimentar va fi adăugat la masca clasei doar pentru modul:

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

Dar ce se întâmplă dacă folosim module imbricate și avem un prezentator Admin:User:Edit? În acest caz, segmentul cu un asterisc care reprezintă modulul pentru fiecare nivel se repetă pur și simplu, iar rezultatul este clasa App\Modules\Admin\User\Presenters\EditPresenter.

O notație alternativă este utilizarea unui array format din trei segmente în loc de un șir de caractere. Această notație este echivalentă cu cea anterioară:

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

Valoarea implicită este *Module\*Presenter.