Módulos

Os módulos são unidades independentes de software que são compostos de models (modelos), views (visões), controllers (controladores) e outros componentes de apoio. Os usuários finais podem acessar os controllers (controladores) de um módulo caso esteja implementado na aplicação. Por estas razões, os módulos são muitas vezes enxergados como mini-aplicações. Os módulos diferem das aplicações pelo fato de não poderem ser implementados sozinhos e que devem residir dentro das aplicações.

Criando Módulos

Um módulo é organizado como um diretório que é chamado de yii\base\Module::basePath do módulo. Dentro deste diretório, existem subdiretório, como o controllers, models, views que mantêm os controllers (controladores), models (modelos), views (visões) e outros códigos assim como em uma aplicação. O exemplo a seguir mostra o conteúdo dentro de um módulo:

forum/
    Module.php                   o arquivo da classe do módulo 
    controllers/                 contém os arquivos da classe controller
        DefaultController.php    o arquivo da classe controller padrão
    models/                      contém os arquivos da classe model
    views/                       contém a view do controller e os arquivos de layout
        layouts/                 contém os arquivos de layout
        default/                 contém os arquivos de view para o DefaultController
            index.php            o arquivo de view index 

Classe do Módulo

Cada módulo deve ter uma única classe que estende de yii\base\Module. Esta classe deve estar localizada diretamente sob o yii\base\Module::basePath do módulo e deve ser autoloadable. Quando um módulo estiver sendo acessado, uma única instância da classe módulo correspondente será criada. Assim como as instâncias da aplicação, as instâncias do módulo são usadas para compartilhar dados e componentes para os códigos dentro dos módulos.

Segue um exemplo de uma classe de módulo:

namespace app\modules\forum;

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

        $this->params['foo'] = 'bar';
        // ...  outros códigos de inicialização ...
    }
}

Se o método init() inicializar muitas propriedades do módulo, você poderá salva-los em um arquivo de configuração e carregá-los como mostro no código a seguir no método init():

public function init()
{
    parent::init();
    // inicializa o módulo com as configurações carregadas de config.php
    \Yii::configure($this, require __DIR__ . '/config.php');
}

O arquivo de configuração config.php pode conter o conteúdo a seguir, que é semelhante ao de uma configuração de aplicação.

<?php
return [
    'components' => [
        // lista de configuração de componentes
    ],
    'params' => [
        // lista de parâmetros
    ],
];

Controllers em Módulos

Ao criar controllers (controladores) em um módulo, uma convenção é colocar as classes dos controllers (controladores) sob o sub-namespace controllers do namespace do módulo da classe. Isto também significa que os arquivos da classe controller (controlador) devem ser colocadas no diretório controllers dentro do yii\base\Module::basePath do módulo. Por exemplo, para criar um controller (controlador) post no módulo forum mostrado na última subseção, você deve declarar a classe controller (controlador) conforme o seguinte exemplo:

namespace app\modules\forum\controllers;

use yii\web\Controller;

class PostController extends Controller
{
    // ...
}

Você pode personalizar o namespace da classe do controller (controlador) configurando a propriedade yii\base\Module::$controllerNamespace. No caso de alguns controllers (controladores) estiverem fora do namespace, você poderá torna-los acessíveis pela configuração da propriedade yii\base\Module::$controllerMap, de forma similar ao que você fez na aplicação.

Views em Módulos

As views (visões) devem ser colocadas no diretório views dentro do yii\base\Module::basePath do módulo. Para as views (visões) renderizadas por um controller (controlador) no módulo, devem ser colocadas sob o diretório views/IDdoController, onde o IDdoController refere-se ao ID do controller (controlador). Por exemplo, se a classe do controller (controlador) for PostController, o diretório será views/post dentro do yii\base\Module::basePath do módulo.

Um módulo pode especificar um layout que será aplicado pelas views (visões) renderizadas pelos controllers (controladores) do módulo. Por padrão, o layout deve ser colocado no diretório views/layouts e deve configurar a propriedade yii\base\Module::$layout para apontar o nome do layout. Se você não configurar a propriedade layout, o layout da aplicação será usada em seu lugar.

Usando os Módulos

Para usar um módulo em uma aplicação, basta configurar a aplicação, listando o módulo na propriedade yii\base\Application::modules da aplicação. O código da configuração da aplicação a seguir faz com que o módulo forum seja aplicado:

[
    'modules' => [
        'forum' => [
            'class' => 'app\modules\forum\Module',
            // ... outras configurações do módulo ...
        ],
    ],
]

A propriedade yii\base\Application::modules é composto por um array de configurações de módulos. Cada chave do array representa um ID do módulo que identifica exclusivamente o módulo entre todos módulos da aplicação e o valor do array correspondente é uma configuração para a criação do módulo.

Rotas

Assim como acessar os controllers (controladores) em uma aplicação, as rotas são usadas para tratar os controllers (controladores) em um módulo. Uma rota para um controller (controlador) dentro de um módulo deve iniciar com o ID do módulo seguido pelo ID do controller (controlador) e pelo ID da ação. Por exemplo, se uma aplicação usar um modulo chamado forum, então a rota forum/post/index representará a ação index do controller (controlador) post no módulo. Se a rota conter apenas o ID do módulo, então a propriedade yii\base\Module::$defaultRoute, na qual o valor padrão é default, determinará qual controller/action deverá ser usado. Isto significa que a rota forum representará o controller (controlador) default no módulo forum.

Acessando os Módulos

Dentro de um módulo, você poderá precisar muitas vezes obter a instância do módulo da classe para que você possa acessar o ID, os parâmetros, os componentes e etc do módulo. Você pode fazer isso usando a seguinte declaração:

$module = MyModuleClass::getInstance();

O MyModuleClass refere-se ao nome da classe do módulo que você está interessado. O método getInstance() retornará a instância que foi solicitada pela requisição. Se o módulo não for solicitado pela requisição, o método retornará null. Observe que você não vai querer criar uma nova instância manualmente da classe do módulo pois será diferente do criado pelo Yii em resposta a uma requisição.

Informação: Ao desenvolver um módulo, você não deve assumir que o módulo usará um ID fixo. Isto porque um módulo pode ser associado a um ID arbitrário quando usado em uma aplicação ou dentro de outro módulo. A fim de obter o ID do módulo, você deve usar a abordagem anterior para obter primeiramente a instância do módulo e em seguida obter o ID através de $module->id.

Você também pode acessar a instância do módulo usando as seguintes abordagens:

// obter o módulo cujo ID é "forum"
$module = \Yii::$app->getModule('forum');

// obter o módulo pelo controller solicitado pela requisição
$module = \Yii::$app->controller->module;

A primeira abordagem só é útil quando você sabe o ID do módulo, enquanto a segunda abordagem é melhor utilizada quando você sabe sobre os controllers (controladores) que está sendo solicitado.

Uma vez tendo a instância do módulo, você pode acessar as propriedade e componentes registrados no módulo. Por exemplo,

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

Inicializando os Módulos

Alguns módulos precisam ser executados a cada requisição. O módulo debug é um exemplo desta necessidade. Para isto, você deverá listar os IDs deste módulos na propriedade bootstrap da aplicação.

Por exemplo, a configuração da aplicação a seguir garante que o módulo debug seja sempre carregado:

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

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

Módulos Aninhados

Os módulos podem ser aninhados em níveis ilimitados. Isto é, um módulo pode conter um outro módulo que pode conter ainda um outro módulo. Nós chamamos dos anteriores de módulo parente enquanto os próximos de módulo filho. Os módulos filhos devem ser declarados na propriedade yii\base\Module::modules de seus módulos parentes. Por exemplo,

namespace app\modules\forum;

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

        $this->modules = [
            'admin' => [
                // você pode considerar em usar um namespace mais curto aqui!
                'class' => 'app\modules\forum\modules\admin\Module',
            ],
        ];
    }
}

Para um controller (controlador) dentro de um módulo aninhado, a rota deve incluir os IDs de todos os seus módulos ancestrais. Por exemplo, a rota forum/admin/dashboard/index representa a ação index do controller (controlador) dashboard no módulo admin que é um módulo filho do módulo forum.

Informação: O método getModule() retorna apenas o módulo filho diretamente pertencente ao seu módulo parente. A propriedade yii\base\Application::$loadedModules mantém uma lista dos módulos carregados, incluindo os módulos filhos e parentes aninhados, indexados pelos seus nomes de classes.

Boas Práticas

Os módulos são melhores usados em aplicações de larga escala, cujas características podem ser divididas em vários grupos, cada um constituídas por um conjuntos de recursos relacionados. Cada grupo de recurso pode ser desenvolvido em um módulo que é desenvolvido e mantido por um desenvolvedor ou equipe específica.

Módulos também são uma boa maneira de reutilizar códigos no nível de grupo de recurso. Algumas recursos comumente utilizados, tais como gerenciamento de usuários, gerenciamento de comentários, podem ser todos desenvolvidos em módulos, para que possam ser utilizados em projetos futuros.