Modules

Les modules apportent de la clarté aux applications Nette en facilitant la division en unités logiques.

À l'instar de l'organisation des fichiers en dossiers sur un disque dur, Nette permet de diviser les présentateurs, les modèles et les autres classes auxiliaires en modules. Comment cela fonctionne-t-il en pratique ? Simplement en incorporant de nouveaux sous-répertoires dans la structure. Voici un exemple de structure avec deux modules, Front et Admin :

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

Cette structure de répertoires se reflète dans les espaces de noms des classes. Ainsi, par exemple, DashboardPresenter est situé dans l'espace de noms App\UI\Admin\Dashboard:

namespace App\UI\Admin\Dashboard;

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

Dans l'application, nous faisons référence au présentateur Dashboard dans le module Admin en utilisant la notation des deux points comme Admin:Dashboard. Pour son action default, nous l'appelons Admin:Dashboard:default.

La structure présentée n'est pas rigide ; vous pouvez l'adapter entièrement à vos besoins dans la configuration.

Les modules peuvent inclure tous les autres fichiers, tels que les composants et les classes auxiliaires, en plus des présentateurs et des modèles. Si vous vous demandez où placer ces derniers, envisagez d'utiliser un dossier Accessory:

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

Modules imbriqués

Les modules peuvent avoir plusieurs niveaux d'imbrication, comme la structure d'un répertoire sur un disque :

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

Le module Blog est divisé en sous-modules Admin et Front. Cela se reflète également dans les espaces de noms, qui apparaissent alors comme App\UI\Blog\Admin et similaires. Pour désigner le présentateur Dashboard au sein du sous-module Admin, nous l'appelons Blog:Admin:Dashboard.

L'imbrication peut être aussi poussée que nécessaire, ce qui permet de créer des sous-sous-modules.

Par exemple, si dans l'administration vous avez de nombreux présentateurs liés à la gestion des commandes, tels que OrderDetail, OrderEdit, OrderDispatch, etc., vous pouvez créer un module Order dans lequel les présentateurs tels que Detail, Edit, Dispatch, et d'autres seront organisés.

Les liens dans les modèles de présentateur sont relatifs au module actuel. Ainsi, le lien Foo:default mène au présentateur Foo dans le même module que le présentateur actuel. Si le module actuel est Front, par exemple, le lien est le suivant :

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

Un lien est relatif même s'il inclut le nom d'un module, qui est alors considéré comme un sous-module :

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

Les liens absolus sont écrits de manière analogue aux chemins absolus sur le disque, mais avec des deux-points à la place des barres obliques. Ainsi, un lien absolu commence par un deux-points :

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

Pour savoir si nous sommes dans un certain module ou son sous-module, nous pouvons utiliser la fonction isModuleCurrent(moduleName).

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

Acheminement

Voir le chapitre sur le routage.

Cartographie

Le mappage définit les règles permettant de dériver le nom de la classe à partir du nom du présentateur. Ces règles sont spécifiées dans la configuration sous la clé application › mapping.

Les structures de répertoire mentionnées plus haut sur cette page sont basées sur la correspondance suivante :

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

Comment fonctionne la cartographie ? Pour mieux comprendre, imaginons d'abord une application sans modules. Nous voulons que les classes de présentateurs relèvent de l'espace de noms App\UI, de sorte que le présentateur Home soit associé à la classe App\UI\HomePresenter. Cette configuration permet d'atteindre cet objectif :

application:
	mapping: App\UI\*Presenter

Ce mappage fonctionne en remplaçant l'astérisque du masque App\UI\*Presenter par le nom du présentateur Home, ce qui donne le nom de classe final App\UI\HomePresenter. C'est simple !

Cependant, comme vous pouvez le voir dans les exemples de ce chapitre et d'autres chapitres, nous plaçons les classes de présentateurs dans des sous-répertoires éponymes, par exemple, le présentateur Home est associé à la classe App\UI\Home\HomePresenter. Pour ce faire, il suffit de doubler l'astérisque (Nette Application 3.2 requise) :

application:
	mapping: App\UI\**Presenter

Passons maintenant au mappage des présentateurs dans les modules. Nous pouvons définir des correspondances spécifiques pour chaque module :

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

Selon cette configuration, le présentateur Front:Home correspond à la classe App\UI\Front\Home\HomePresenter, tandis que le présentateur Api:OAuth correspond à la classe App\Api\OAuthPresenter.

Étant donné que les modules Front et Admin ont une approche de mappage similaire et qu'il est probable qu'il y ait d'autres modules de ce type, il est possible de créer une règle générale qui les remplace. Un nouvel astérisque pour le module est ajouté au masque de classe :

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

Pour les modules imbriqués à plusieurs niveaux, tels que le présentateur Admin:User:Edit, le segment astérisque se répète pour chaque niveau, ce qui donne la classe App\UI\Admin\User\Edit\EditPresenter.

Une autre notation consiste à utiliser un tableau composé de trois segments au lieu d'une chaîne. Cette notation est équivalente à la précédente :

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