Módulos

En Nette, los módulos representan las unidades lógicas que componen una aplicación. Incluyen presentadores, plantillas, posiblemente también componentes y clases modelo.

Un directorio para los presentadores y otro para las plantillas no serían suficientes para los proyectos reales. Tener docenas de archivos en una carpeta es, como mínimo, desorganizado. ¿Cómo salir de ello? Simplemente los dividimos en subdirectorios en el disco y en espacios de nombres en el código. Y eso es exactamente lo que hacen los módulos de Nette.

Así que olvidémonos de una única carpeta para presentadores y plantillas y en su lugar creemos módulos, por ejemplo Admin y Front.

app/
├── Presenters/
├── Modules/              ← directorio con módulos
│   ├── Admin/            ← módulo Admin
│   │   ├── Presenters/   ← sus presentadores
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← módulo Front
│       └── Presenters/   ← sus presentadores
│           └── ...

Esta estructura de directorios se reflejará en los espacios de nombres de las clases, así por ejemplo DashboardPresenter estará en el espacio de nombres App\Modules\Admin\Presenters:

namespace App\Modules\Admin\Presenters;

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

El presentador Dashboard dentro del módulo Admin es referenciado dentro de la aplicación usando la notación de dos puntos como Admin:Dashboard, y su acción default como Admin:Dashboard:default. ¿Y cómo sabe Nette que Admin:Dashboard representa la clase App\Modules\Admin\Presenters\DashboardPresenter? Esto se determina mediante el mapeo en la configuración. Por lo tanto, la estructura dada no es rígida y puede modificarla según sus necesidades.

Por supuesto, los módulos pueden contener todos los demás elementos además de presentadores y plantillas, como componentes, clases modelo, etc.

Módulos anidados

Los módulos no tienen por qué formar sólo una estructura plana, también puedes crear submódulos, por ejemplo:

app/
├── Modules/              ← directorio con módulos
│   ├── Blog/             ← módulo Blog
│   │   ├── Admin/        ← submódulo Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← submódulo Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← módulo Forum
│   │   └── ...

Así, el módulo Blog se divide en los submódulos Admin y Front. De nuevo, esto se reflejará en los espacios de nombres, que serán App\Modules\Blog\Admin\Presenters, etc. El presentador Dashboard dentro del submódulo se denomina Blog:Admin:Dashboard.

El anidamiento puede ser tan profundo como se desee, por lo que pueden crearse submódulos.

Los enlaces de las plantillas de presentador son relativos al módulo actual. Así, el enlace Foo:default lleva al presentador Foo en el mismo módulo que el presentador actual. Si el módulo actual es Front, por ejemplo, el enlace será el siguiente:

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

Un enlace es relativo aunque incluya el nombre de un módulo, que se considera entonces un submódulo:

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

Los enlaces absolutos se escriben de forma análoga a las rutas absolutas en disco, pero con dos puntos en lugar de barras. Así, un enlace absoluto comienza con dos puntos:

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

Para saber si estamos en un módulo determinado o en su submódulo podemos utilizar la función isModuleCurrent(moduleName).

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

Enrutamiento

Véase el capítulo sobre en rutamiento.

Mapeo

Define las reglas por las que el nombre de la clase se deriva del nombre del presentador. Las escribimos en configuración bajo la clave application › mapping.

Empecemos con un ejemplo que no utiliza módulos. Sólo querremos que las clases del presentador tengan el espacio de nombres App\Presenters. Eso significa que un presentador como Home debe mapearse a la clase App\Presenters\HomePresenter. Esto se puede lograr con la siguiente configuración:

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

El nombre del presentador se sustituye por el asterisco en la máscara de clase y el resultado es el nombre de la clase. Muy fácil.

Si dividimos a los presentadores en módulos, podemos tener nuestra propia asignación para cada módulo:

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

Ahora el presentador Front:Home se asigna a la clase App\Modules\Front\Presenters\HomePresenter y el presentador Admin:Dashboard a la clase App\Modules\Admin\Presenters\DashboardPresenter.

Es más práctico crear una regla general (estrella) para sustituir a las dos primeras. El asterisco adicional se añadirá a la máscara de clase sólo para el módulo:

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

Pero, ¿y si utilizamos módulos anidados y tenemos un presentador Admin:User:Edit? En este caso, el segmento con un asterisco que representa el módulo para cada nivel simplemente se repite y el resultado es la clase App\Modules\Admin\User\Presenters\EditPresenter.

Una notación alternativa es utilizar una matriz formada por tres segmentos en lugar de una cadena. Esta notación es equivalente a la anterior:

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

El valor por defecto es *: *Module\*Presenter.

versión: 4.0