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.
Creación de enlaces
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
.