Módulos
Em Nette, os módulos representam as unidades lógicas que compõem uma aplicação. Eles incluem apresentadores, gabaritos, possivelmente também componentes e classes de modelos.
Um diretório para apresentadores e um para modelos não seria suficiente para projetos reais. Ter dezenas de arquivos em uma pasta é pelo menos desorganizado. Como sair dela? Nós simplesmente os dividimos em subdiretórios em disco e em namespaces no código. E é exatamente isso que os módulos Nette fazem.
Portanto, vamos esquecer uma única pasta para apresentadores e modelos e, em vez disso, criar módulos, por exemplo
Admin
e Front
.
app/ ├──Presenters/├── Modules/ ← directory with modules │ ├── Admin/ ← module Admin │ │ ├── Presenters/ ← its presenters │ │ │ ├── DashboardPresenter.php │ │ │ └── templates/ │ └── Front/ ← module Front │ └── Presenters/ ← its presenters │ └── ...
Esta estrutura de diretório será refletida pelos namespaces de classe, portanto, por exemplo DashboardPresenter
estará no namespace App\Modules\Admin\Presenters
:
namespace App\Modules\Admin\Presenters;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
O Dashboard
apresentador dentro do módulo Admin
é referenciado dentro da aplicação usando a
notação de cólon como Admin:Dashboard
, e sua ação default
como
Admin:Dashboard:default
. E como a Nette propriamente dita sabe que Admin:Dashboard
representa a classe
App\Modules\Admin\Presenters\DashboardPresenter
? Isto é determinado pelo mapeamento na
configuração. Assim, a estrutura dada não é difícil de definir e você pode modificá-la de acordo com suas necessidades.
Os módulos podem naturalmente conter todos os outros itens além de apresentadores e modelos, tais como componentes, classes de modelos, etc.
Módulos aninhados
Os módulos não precisam formar apenas uma estrutura plana, você também pode criar submódulos, por exemplo:
app/ ├── Modules/ ← directory with modules │ ├── Blog/ ← module Blog │ │ ├── Admin/ ← submodule Admin │ │ │ ├── Presenters/ │ │ │ └── ... │ │ └── Front/ ← submodule Front │ │ ├── Presenters/ │ │ └── ... │ ├── Forum/ ← module Forum │ │ └── ...
Assim, o módulo Blog
está dividido em Admin
e Front
submódulos. Mais uma vez, isto
se refletirá nos namespaces, que serão App\Modules\Blog\Admin\Presenters
etc. O apresentador
Dashboard
dentro do submódulo é referido como Blog:Admin:Dashboard
.
O ninho pode ir tão fundo quanto você desejar, de modo que sub-submódulos podem ser criados.
Criação de links
Os links nos modelos de apresentadores são relativos ao módulo atual. Assim, o link Foo:default
leva ao
apresentador Foo
no mesmo módulo que o apresentador atual. Se o módulo atual é Front
, por exemplo,
então o link vai assim:
<a n:href="Product:show">link to Front:Product:show</a>
Um link é relativo mesmo que inclua o nome de um módulo, que é então considerado um submódulo:
<a n:href="Shop:Product:show">link to Front:Shop:Product:show</a>
Links absolutos são escritos analogamente a caminhos absolutos em disco, mas com colons ao invés de cortes. Assim, uma ligação absoluta começa com dois-pontos:
<a n:href=":Admin:Product:show">link to Admin:Product:show</a>
Para saber se estamos em um determinado módulo ou em seu submódulo, podemos usar a função
isModuleCurrent(moduleName)
.
<li n:class="isModuleCurrent('MyEshop:Users') ? active">
<a n:href="Product:">...</a>
</li>
Roteiro
Ver capítulo sobre roteamento.
Mapeamento
Define as regras pelas quais o nome da classe é derivado do nome do apresentador. Nós as escrevemos na configuração sob a chave application › mapping
.
Vamos começar com uma amostra que não utiliza módulos. Queremos apenas que as classes de apresentadores tenham o namespace
App\Presenters
. Isso significa que um apresentador como o Home
deve mapear para a classe
App\Presenters\HomePresenter
. Isto pode ser conseguido através da seguinte configuração:
application:
mapping:
*: App\Presenters\*Presenter
O nome do apresentador é substituído pelo asterisco na máscara da classe e o resultado é o nome da classe. Fácil!
Se dividirmos os apresentadores em módulos, podemos ter nosso próprio mapeamento para cada módulo:
application:
mapping:
Front: App\Modules\Front\Presenters\*Presenter
Admin: App\Modules\Admin\Presenters\*Presenter
Api: App\Api\*Presenter
Agora o apresentador Front:Home
mapeia para a classe App\Modules\Front\Presenters\HomePresenter
e
o apresentador Admin:Dashboard
para a classe App\Modules\Admin\Presenters\DashboardPresenter
.
É mais prático criar uma regra geral (estrela) para substituir as duas primeiras. O asterisco extra será adicionado à máscara de classe apenas para o módulo:
application:
mapping:
*: App\Modules\*\Presenters\*Presenter
Api: App\Api\*Presenter
Mas e se usarmos módulos aninhados e tivermos um apresentador Admin:User:Edit
? Neste caso, o segmento com um
asterisco representando o módulo para cada nível é simplesmente repetido e o resultado é a classe
App\Modules\Admin\User\Presenters\EditPresenter
.
Uma notação alternativa é utilizar um conjunto composto de três segmentos em vez de um fio. Esta notação é equivalente à anterior:
application:
mapping:
*: [App\Modules, *, Presenters\*Presenter]
O valor padrão é *: *Module\*Presenter
.