Módulos
Os módulos dão clareza aos aplicativos Nette, facilitando a divisão em unidades lógicas.
Da mesma forma que organizamos os arquivos em pastas em um disco rígido, na Nette podemos dividir apresentadores, modelos e outras classes auxiliares em módulos. Como isso funciona na prática? Simplesmente incorporando novos subdiretórios à estrutura. Aqui está um exemplo de uma estrutura com dois módulos, Front e Admin:
app/ ├── UI/ │ ├── Admin/ ← Admin module │ │ ├── @layout.latte │ │ ├── Dashboard/ │ │ │ ├── DashboardPresenter.php │ │ │ └── default.latte │ │ └── ... │ ├── Front/ ← Front module │ │ ├── @layout.latte │ │ ├── Home/ │ │ │ ├── HomePresenter.php │ │ │ └── default.latte │ │ └── ...
Essa estrutura de diretórios é refletida nos namespaces das classes, portanto, por exemplo, DashboardPresenter
está localizado no namespace App\UI\Admin\Dashboard
:
namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
No aplicativo, nos referimos ao apresentador Dashboard
dentro do módulo Admin
usando a notação de
dois pontos como Admin:Dashboard
. Para sua ação default
, nos referimos a ela como
Admin:Dashboard:default
.
A estrutura apresentada não é rígida; você pode personalizá-la totalmente de acordo com suas necessidades na configuração.
Os módulos podem incluir todos os outros arquivos, como componentes e classes auxiliares, além de apresentadores e modelos.
Se estiver pensando em onde colocá-los, considere o uso de uma pasta Accessory
:
app/ ├── UI/ │ ├── Admin/ │ │ ├── Accessory/ │ │ │ ├── FormFactory.php │ │ │ └── AdminLayout.php │ │ ├── Dashboard/ │ │ └── ...
Módulos aninhados
Os módulos podem ter vários níveis de aninhamento, semelhante a uma estrutura de diretórios em um disco:
app/ ├── UI/ │ ├── Blog/ ← Blog module │ │ ├── Admin/ ← Admin submodule │ │ │ ├── Dashboard/ │ │ │ └── ... │ │ ├── Front/ ← Front submodule │ │ │ ├── @layout.latte │ │ │ ├── Home/ │ │ │ └── ... │ ├── Forum/ ← Forum module │ │ └── ...
O módulo Blog
é dividido em submódulos Admin
e Front
. Isso também se reflete nos
namespaces, que aparecem como App\UI\Blog\Admin
e similares. Para nos referirmos ao apresentador
Dashboard
dentro do submódulo Admin
, nos referimos a ele como Blog:Admin:Dashboard
.
O aninhamento pode ser tão profundo quanto necessário, permitindo a criação de sub-submódulos.
Por exemplo, se na administração você tem muitos apresentadores relacionados ao gerenciamento de pedidos, como
OrderDetail
, OrderEdit
, OrderDispatch
, etc., você pode criar um módulo Order
no qual apresentadores como Detail
, Edit
, Dispatch
e outros serão organizados.
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
O mapeamento define as regras para derivar o nome da classe do nome do apresentador. Essas regras são especificadas na configuração sob a chave application › mapping
.
As estruturas de diretório mencionadas anteriormente nesta página são baseadas no seguinte mapeamento:
application:
mapping: App\UI\*\**Presenter
Como funciona o mapeamento? Para entender melhor, vamos primeiro imaginar um aplicativo sem módulos. Queremos que as classes
do apresentador se enquadrem no namespace App\UI
, de modo que o apresentador Home
mapeie para a classe
App\UI\HomePresenter
. Isso pode ser obtido com esta configuração:
application:
mapping: App\UI\*Presenter
Esse mapeamento funciona substituindo o asterisco na máscara App\UI\*Presenter
pelo nome do apresentador
Home
, resultando no nome final da classe App\UI\HomePresenter
. Simples!
Entretanto, como você pode ver nos exemplos deste e de outros capítulos, colocamos as classes de apresentador em
subdiretórios homônimos, por exemplo, o apresentador Home
é mapeado para a classe
App\UI\Home\HomePresenter
. Isso é feito duplicando-se o asterisco (requer o Nette Application 3.2):
application:
mapping: App\UI\**Presenter
Agora, vamos passar a mapear os apresentadores em módulos. Podemos definir mapeamentos específicos para cada módulo:
application:
mapping:
Front: App\UI\Front\**Presenter
Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
De acordo com essa configuração, o apresentador Front:Home
mapeia para a classe
App\UI\Front\Home\HomePresenter
, enquanto o apresentador Api:OAuth
mapeia para a classe
App\Api\OAuthPresenter
.
Como os módulos Front
e Admin
têm uma abordagem de mapeamento semelhante e é provável que haja
mais módulos desse tipo, é possível criar uma regra geral que os substitua. Um novo asterisco para o módulo é adicionado à
máscara de classe:
application:
mapping:
*: App\UI\*\**Presenter
Api: App\Api\*Presenter
Para módulos aninhados em vários níveis, como o apresentador Admin:User:Edit
, o segmento de asterisco se
repete para cada nível, resultando na classe App\UI\Admin\User\Edit\EditPresenter
.
Uma notação alternativa é usar uma matriz composta de três segmentos em vez de uma cadeia de caracteres. Essa notação é equivalente à anterior:
application:
mapping:
*: [App\UI, *, **Presenter]
Api: [App\Api, '', *Presenter]
Se tivermos apenas uma regra na configuração, a geral, podemos escrever de forma resumida:
application:
mapping: App\UI\*\**Presenter