Módulos

Los módulos son unidades de software independientes que consisten en modelos, vistas, controladores, y otros componentes de apoyo. Los usuarios finales pueden acceder a los controladores de un módulo cuando éste está instalado en la aplicación. Por éstas razones, los módulos a menudo se considerados como mini-aplicaciones. Los módulos difieren de las aplicaciones en que los módulos no pueden ser desplegados solos y tienen que residir dentro de aplicaciones.

Creación de Módulos

Un módulo está organizado de tal manera que contiene un directorio llamado [[yii\base\Module::basePath|base path]] del módulo. Dentro de este directorio, hay subdirectorios tales como 'controllers', 'models', 'views', que contienen controladores, modelos, vistas y otro código, exactamente como una aplicación. El siguiente ejemplo muestra el contenido dentro de un módulo:

forum/
    Module.php                   archivo clase módulo
    controllers/                 contiene archivos de la clase controlador
        DefaultController.php    archivo clase controlador por defecto
    models/                      contiene los archivos de clase modelo
    views/                       contiene las vistas de controlador y los archivos de diseño
        layouts/                 contiene los archivos de diseño de las vistas
        default/                 contiene los archivos de vista del DefaultController
            index.php            archivo de vista del index

Clases Módulo

Cada módulo debe tener una única clase módulo que extiende a [[yii\base\Module]]. La clase debe encontrarse directamente debajo del [[yii\base\Module::basePath|base path]] y debe ser autocargable. Cuando se está accediendo a un módulo, se creará una única instancia de la clase módulo correspondiente. Como en las instancias de aplicación, las instancias de módulo se utilizan para compartir datos y componentes de código dentro de los módulos.

El siguiente ejemplo muestra como podría ser una clase módulo.

namespace app\modules\forum;

class Module extends \yii\base\Module
{
    public function init()
    {
        parent::init();

        $this->params['foo'] = 'bar';
        // ...  otro código de inicialización ...
    }
}

Si el método 'init()' contiene mucho código de inicialización de las propiedades del módulo, también se puede guardar en términos de configuración y cargarlo con el siguiente código ‘init()’:

public function init()
{
    parent::init();
    // inicializa el módulo con la configuración cargada desde config.php
    \Yii::configure($this, require(__DIR__ . '/config.php'));
}

donde el archivo de configuración ‘config.php’ puede contener el siguiente contenido, similar al de configuraciones de aplicación.

<?php
return [
    'components' => [
        // lista de configuraciones de componente
    ],
    'params' => [
        // lista de parámetros
    ],
];

Controladores en Módulos

Cuando se crean controladores en un modelo, una convención es poner las clases controlador debajo del sub-espacio de nombres de ‘controllers’ del espacio de nombres de la clase módulo. Esto también significa que los archivos de la clase controlador deben ponerse en el directorio ‘controllers’ dentro del [[yii\base\Module::basePath|base path]] del módulo. Por ejemplo, para crear un controlador ‘post’ en el módulo ‘forum’ mostrado en la última subdivisión, se debe declarar la clase controlador de la siguiente manera:

namespace app\modules\forum\controllers;

use yii\web\Controller;

class PostController extends Controller
{
    // ...
}

Se puede personalizar el espacio de nombres de las clases controlador configurando la propiedad [[yii\base\Module::controllerNamespace]]. En el caso que alguno de los controladores esté fuera del espacio de nombres, se puede hacer accesible configurando la propiedad [[yii\base\Module::controllerMap]], similar a como se hace en una aplicación.

Vistas en Módulos

Las vistas en un módulo deben alojarse en el directorio ‘views’ dentro del módulo del [[yii\base\Module::basePath|base path]]. Las vistas renderizadas por un controlador en el módulo, deben alojarse en el directorio ‘views/ControllerID’, donde el ‘ControllerID’ hace referencia al ID del controlador. Por ejemplo, si la clase controlador es ‘PostController’, el directorio sería ‘views/post’ dentro del [[yii\base\Module::basePath|base path]] del módulo.

Un modulo puede especificar un layout que se aplica a las vistas renderizadas por los controladores del módulo. El layout debe alojarse en el directorio ‘views/layouts’ por defecto, y se puede configurar la propiedad [[yii\base\Module::layout]] para apuntar al nombre del layout. Si no se configura la propiedad ‘layout’, se usar el layout de la aplicación.

Uso de los Módulos

Para usar un módulo en una aplicación, simplemente se tiene que configurar la aplicación añadiendo el módulo en la propiedad [[yii\base\Application::modules|modules]] de la aplicación. El siguiente ejemplo de la configuración de la aplicación usa el modelo ‘forum’:

[
    'modules' => [
        'forum' => [
            'class' => 'app\modules\forum\Module',
            // ... otras configuraciones para el módulo ...
        ],
    ],
]

La propiedad [[yii\base\Application::modules|modules]] contiene un array de configuraciones de módulo. Cada clave del array representa un ID de módulo que identifica de forma única el módulo de entre todos los módulos de la aplicación, y el correspondiente valor del array es la configuración para crear el módulo.

Rutas

De Igual manera que el acceso a los controladores en una aplicación, las rutas se utiliza para dirigirse a los controladores en un módulo. Una ruta para un controlador dentro de un módulo debe empezar con el ID del módulo seguido por el ID del controlador y el ID de la acción. Por ejemplo, si una aplicación usa un módulo llamado ‘forum’, la ruta ‘forum/post/index’ representaría la acción ‘index’ del controlador ‘post’ en el módulo. Si la ruta sólo contiene el ID del módulo, entonces la propiedad [[yii\base\Module::defaultRoute]] que por defecto es ‘default’, determinara que controlador/acción debe usarse. Esto significa que la ruta ‘forum’ representaría el controlador ‘default’ en el módulo ‘forum’.

Acceder a los Módulos

Dentro de un módulo, se puede necesitar obtener la instancia de la clase módulo para poder acceder al ID del módulo, componentes del módulo, etc. Se puede hacer usando la siguiente declaración:

$module = MyModuleClass::getInstance();

Dónde ‘MyModuleClass’ hace referencia al nombre de la clase módulo en la que estemos interesados. El método ‘getInstance()’ devolverá la instancia actualmente solicitada de la clase módulo. Si no se solicita el módulo, el método devolverá nulo. Hay que tener en cuenta que si se crea una nueva instancia del módulo, esta será diferente a la creada por Yii en respuesta a la solicitud.

Información: Cuando se desarrolla un módulo, no se debe dar por sentado que el módulo usará un ID fijo. Esto se debe a que un módulo puede asociarse a un ID arbitrario cuando se usa en una aplicación o dentro de otro módulo. Para obtener el ID del módulo, primero se debe usar el código del anterior ejemplo para obtener la instancia y luego el ID mediante ‘$modeule->id’.

También se puede acceder a la instancia de un módulo usando las siguientes declaraciones:

// obtiene el modulo hijo cuyo ID es “forum”
$module = \Yii::$app->getModule('forum');

// obtiene el módulo al que pertenece la petición actual
$module = \Yii::$app->controller->module;

El primer ejemplo sólo es útil cuando conocemos el ID del módulo, mientras que el segundo es mejor usarlo cuando conocemos los controladores que se están solicitando.

Una vez obtenida la instancia del módulo, se puede acceder a parámetros o componentes registrados con el módulo. Por ejemplo:

$maxPostCount = $module->params['maxPostCount'];

Bootstrapping Módulos

Puede darse el caso en que necesitemos que un módulo se ejecute en cada petición. El módulo [[yii\debug\Module|debug]] es un ejemplo. Para hacerlo, tenemos que listar los IDs de los módulos en la propiedad [[yii\base\Application::bootstrap|bootstrap]] de la aplicación.

Por ejemplo, la siguiente configuración de aplicación se asegura de que el módulo ‘debug’ siempre se cargue:

[
    'bootstrap' => [
        'debug',
    ],

    'modules' => [
        'debug' => 'yii\debug\Module',
    ],
]

Módulos anidados

Los módulos pueden ser anidados sin límite de niveles. Es decir, un módulo puede contener un módulo y éste a la vez contener otro módulo. Nombramos padre al primero mientras que al segundo lo nombramos hijo. Los módulos hijo se tienen que declarar en la propiedad [[yii\base\Module::modules|modules]] de sus módulos padre. Por ejemplo:

namespace app\modules\forum;

class Module extends \yii\base\Module
{
    public function init()
    {
        parent::init();

        $this->modules = [
            'admin' => [
                // debe considerarse usar un nombre de espacios más corto!
                'class' => 'app\modules\forum\modules\admin\Module',
            ],
        ];
    }
}

En un controlador dentro de un módulo anidado, la ruta debe incluir el ID de todos los módulos antecesores. Por ejemplo, la ruta ‘forum/admin/dashboard/index’ representa la acción ‘index’ del controlador ‘dashboard’ en el módulo ‘admin’ que es el módulo hijo del módulo ‘forum’.

Información: El método [[yii\base\Module::getModule()|getModule()]] sólo devuelve el módulo hijo que pertenece directamente a su padre. La propiedad [[yii\base\Application::loadedModules]] contiene una lista de los módulos cargados, incluyendo los hijos directos y los anidados, indexados por sus nombres de clase.

Mejores Prácticas

Es mejor usar los módulos en grandes aplicaciones en las que sus funcionalidades puedan ser divididas en diferentes grupos, cada uno compuesto por funcionalidades directamente relacionadas. Cada grupo de funcionalidades se puede desarrollar como un módulo que puede ser desarrollado y mantenido por un programador o equipo específico.

Los módulos también son una buena manera de reutilizar código a nivel de grupo de funcionalidades. Algunas funcionalidades de uso común, tales como la gestión de usuarios o la gestión de comentarios, pueden ser desarrollados como módulos para que puedan ser fácilmente reutilizados en futuros proyectos.