Moduli

I moduli conferiscono chiarezza alle applicazioni Nette, facilitando la suddivisione in unità logiche.

Analogamente all'organizzazione dei file in cartelle su un disco rigido, in Nette possiamo dividere presentatori, modelli e altre classi ausiliarie in moduli. Come funziona in pratica? Semplicemente incorporando nuove sottodirectory nella struttura. Ecco un esempio di struttura con due moduli, Front e Admin:

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

Questa struttura di directory si riflette negli spazi dei nomi delle classi, per cui, ad esempio, DashboardPresenter si trova nello spazio dei nomi App\UI\Admin\Dashboard:

namespace App\UI\Admin\Dashboard;

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

Nell'applicazione, ci si riferisce al presentatore Dashboard all'interno del modulo Admin usando la notazione dei due punti come Admin:Dashboard. Per l'azione default, ci si riferisce ad essa come Admin:Dashboard:default.

La struttura presentata non è rigida; è possibile personalizzarla completamente in base alle proprie esigenze nella configurazione.

I moduli possono includere tutti gli altri file, come i componenti e le classi ausiliarie, oltre ai presentatori e ai modelli. Se si sta valutando dove collocare questi ultimi, si può prendere in considerazione l'uso di una cartella Accessory:

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

Moduli annidati

I moduli possono avere più livelli di annidamento, simili a una struttura di directory su disco:

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

Il modulo Blog è diviso nei sottomoduli Admin e Front. Questo si riflette anche negli spazi dei nomi, che appaiono come App\UI\Blog\Admin e simili. Per riferirsi al presentatore Dashboard all'interno del sottomodulo Admin, ci si riferisce ad esso come Blog:Admin:Dashboard.

L'annidamento può essere profondo quanto necessario, consentendo la creazione di sottomoduli.

Ad esempio, se nell'amministrazione sono presenti molti presentatori relativi alla gestione degli ordini, come OrderDetail, OrderEdit, OrderDispatch, ecc. si può creare un modulo Order in cui saranno organizzati presentatori come Detail, Edit, Dispatch, e altri.

I collegamenti nei modelli di presentatore sono relativi al modulo corrente. Pertanto, il collegamento Foo:default porta al presentatore Foo nello stesso modulo del presentatore corrente. Se il modulo corrente è Front, ad esempio, il collegamento si presenta in questo modo:

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

Un collegamento è relativo anche se include il nome di un modulo, che viene considerato un sottomodulo:

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

I collegamenti assoluti sono scritti in modo analogo ai percorsi assoluti su disco, ma con i due punti al posto degli slash. Pertanto, un collegamento assoluto inizia con i due punti:

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

Per scoprire se ci troviamo in un certo modulo o in un suo sottomodulo possiamo usare la funzione isModuleCurrent(moduleName).

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

Instradamento

Vedere il capitolo sull'instradamento.

Mappatura

La mappatura definisce le regole per derivare il nome della classe dal nome del presentatore. Queste regole sono specificate nella configurazione sotto la chiave application › mapping.

Le strutture di directory menzionate in precedenza in questa pagina si basano sulla seguente mappatura:

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

Come funziona la mappatura? Per capire meglio, immaginiamo prima un'applicazione senza moduli. Vogliamo che le classi del presentatore rientrino nello spazio dei nomi App\UI, in modo che il presentatore Home sia mappato nella classe App\UI\HomePresenter. Ciò può essere ottenuto con questa configurazione:

application:
	mapping: App\UI\*Presenter

Questa mappatura funziona sostituendo l'asterisco nella maschera App\UI\*Presenter con il nome del presenter Home, ottenendo il nome finale della classe App\UI\HomePresenter. Semplice!

Tuttavia, come si può vedere negli esempi di questo e di altri capitoli, le classi dei presentatori sono collocate in sottodirectory eponime, ad esempio il presentatore Home è mappato nella classe App\UI\Home\HomePresenter. Questo si ottiene raddoppiando l'asterisco (richiede Nette Application 3.2):

application:
	mapping: App\UI\**Presenter

Passiamo ora alla mappatura dei presentatori nei moduli. Possiamo definire mappature specifiche per ogni modulo:

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

In base a questa configurazione, il presentatore Front:Home si riferisce alla classe App\UI\Front\Home\HomePresenter, mentre il presentatore Api:OAuth si riferisce alla classe App\Api\OAuthPresenter.

Poiché i moduli Front e Admin hanno un approccio di mappatura simile e probabilmente ci saranno altri moduli di questo tipo, è possibile creare una regola generale che li sostituisca. Un nuovo asterisco per il modulo viene aggiunto alla maschera della classe:

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

Per i moduli annidati a più livelli, come il presentatore Admin:User:Edit, il segmento dell'asterisco si ripete per ogni livello, dando luogo alla classe App\UI\Admin\User\Edit\EditPresenter.

Una notazione alternativa consiste nell'utilizzare un array composto da tre segmenti invece di una stringa. Questa notazione è equivalente alla precedente:

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

Se abbiamo una sola regola nella configurazione, quella generale, possiamo scrivere brevemente:

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