Modules

Dans Nette, les modules représentent les unités logiques qui composent une application. Ils comprennent des présentateurs, des modèles, éventuellement aussi des composants et des classes de modèles.

Un répertoire pour les présentateurs et un autre pour les modèles ne seraient pas suffisants pour les projets réels. Avoir des dizaines de fichiers dans un seul dossier est pour le moins inorganisé. Comment s'en sortir ? Il suffit de les répartir en sous-répertoires sur le disque et en espaces de noms dans le code. Et c'est exactement ce que font les modules Nette.

Oublions donc le dossier unique pour les présentateurs et les modèles et créons plutôt des modules, par exemple Admin et Front.

app/
├── Presenters/
├── Modules/              ← répertoire avec les modules
│   ├── Admin/            ← module Admin
│   │   ├── Presenters/   ← ses présentateurs
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← module Front
│       └── Presenters/   ← ses présentateurs
│           └── ...

Cette structure de répertoire sera reflétée par les espaces de noms des classes, ainsi par exemple DashboardPresenter sera dans l'espace de noms App\Modules\Admin\Presenters:

namespace App\Modules\Admin\Presenters;

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

Le présentateur Dashboard dans le module Admin est référencé dans l'application en utilisant la notation deux points comme Admin:Dashboard, et son action default comme Admin:Dashboard:default. Et comment Nette proper sait-elle que Admin:Dashboard représente la classe App\Modules\Admin\Presenters\DashboardPresenter? Cela est déterminé par le mappage dans la configuration. Ainsi, la structure donnée n'est pas figée et vous pouvez la modifier en fonction de vos besoins.

Les modules peuvent bien sûr contenir tous les éléments autres que les présentateurs et les modèles, tels que les composants, les classes de modèles, etc.

Modules imbriqués

Les modules ne doivent pas uniquement former une structure plate, vous pouvez également créer des sous-modules, par exemple :

app/
├── Modules/              ← répertoire avec les modules
│   ├── Blog/             ← module Blog
│   │   ├── Admin/        ← sous-module Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← sous-module Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← module Forum
│   │   └── ...

Ainsi, le module Blog est divisé en sous-modules Admin et Front. Là encore, cela se reflétera dans les espaces de noms, qui seront App\Modules\Blog\Admin\Presenters etc. Le présentateur Dashboard à l'intérieur du sous-module est désigné par Blog:Admin:Dashboard.

L'imbrication peut aller aussi loin que vous le souhaitez, de sorte que des sous-sous-modules peuvent être créé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

Définit les règles par lesquelles le nom de la classe est dérivé du nom du présentateur. On les inscrit dans la configuration sous la clé application › mapping.

Commençons par un exemple qui n'utilise pas de modules. Nous voulons simplement que les classes du présentateur aient l'espace de nom App\Presenters. Cela signifie qu'un présentateur tel que Home doit correspondre à la classe App\Presenters\HomePresenter. Ceci peut être réalisé par la configuration suivante :

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

Le nom du présentateur est remplacé par l'astérisque dans le masque de classe et le résultat est le nom de la classe. Facile !

Si nous divisons les présentateurs en modules, nous pouvons avoir notre propre mappage pour chaque module :

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

Maintenant, le présentateur Front:Home correspond à la classe App\Modules\Front\Presenters\HomePresenter et le présentateur Admin:Dashboard à la classe App\Modules\Admin\Presenters\DashboardPresenter.

Il est plus pratique de créer une règle générale (étoile) pour remplacer les deux premières. L'astérisque supplémentaire sera ajouté au masque de classe uniquement pour le module :

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

Mais qu'en est-il si nous utilisons des modules imbriqués et que nous avons un présentateur Admin:User:Edit? Dans ce cas, le segment avec un astérisque représentant le module pour chaque niveau est simplement répété et le résultat est la classe App\Modules\Admin\User\Presenters\EditPresenter.

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

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

La valeur par défaut est *: *Module\*Presenter.