Modules

Modules bring clarity to Nette applications by facilitating easy division into logical units.

Similar to organizing files into folders on a hard drive, in Nette we can divide presenters, templates, and other auxiliary classes into modules. How does this work in practice? Simply by incorporating new subdirectories into the structure. Here’s an example of a structure with two modules, Front and Admin:

app/
├── UI/
│   ├── Admin/            ← Admin module
│   │   ├── @layout.latte
│   │   ├── Dashboard/
│   │   │   ├── DashboardPresenter.php
│   │   │   └── default.latte
│   │   └── ...
│   ├── Front/            ← Front module
│   │   ├── @layout.latte
│   │   ├── Home/
│   │   │   ├── HomePresenter.php
│   │   │   └── default.latte
│   │   └── ...

This directory structure is reflected in the namespaces of the classes, so for example, DashboardPresenter is located in the namespace App\UI\Admin\Dashboard:

namespace App\UI\Admin\Dashboard;

class DashboardPresenter extends Nette\Application\UI\Presenter
{
	// ...
}

In the application, we refer to the Dashboard presenter within the Admin module using colon notation as Admin:Dashboard. For its default action, we refer to it as Admin:Dashboard:default.

The structure presented is not rigid; you can fully customize it to your needs in the configuration.

Modules can include all other files, such as components and auxiliary classes, in addition to presenters and templates. If you are considering where to place these, consider using an Accessory folder:

app/
├── UI/
│   ├── Admin/
│   │   ├── Accessory/
│   │   │   ├── FormFactory.php
│   │   │   └── AdminLayout.php
│   │   ├── Dashboard/
│   │   └── ...

Nested Modules

Modules can have multiple levels of nesting, similar to a directory structure on a disk:

app/
├── UI/
│   ├── Blog/             ← Blog module
│   │   ├── Admin/        ← Admin submodule
│   │   │   ├── Dashboard/
│   │   │   └── ...
│   │   ├── Front/        ← Front submodule
│   │   │   ├── @layout.latte
│   │   │   ├── Home/
│   │   │   └── ...
│   ├── Forum/            ← Forum module
│   │   └── ...

The Blog module is divided into Admin and Front submodules. This is also reflected in the namespaces, which then appear as App\UI\Blog\Admin and similarly. To refer to the Dashboard presenter within the Admin submodule, we refer to it as Blog:Admin:Dashboard.

Nesting can be as deep as needed, allowing the creation of sub-submodules.

For example, if in administration you have many presenters related to order management, such as OrderDetail, OrderEdit, OrderDispatch, etc., you might create an Order module in which presenters like Detail, Edit, Dispatch, and others will be organized.

Links in presenter templates are relative to the current module. Thus, the link Foo:default leads to the presenter Foo in the same module as the current presenter. If the current module is Front, for example, then the link goes like this:

<a n:href="Product:show">link to Front:Product:show</a>

A link is relative even if it includes the name of a module, which is then considered a submodule:

<a n:href="Shop:Product:show">link to Front:Shop:Product:show</a>

Absolute links are written analogously to absolute paths on disk, but with colons instead of slashes. Thus, an absolute link starts with a colon:

<a n:href=":Admin:Product:show">link to Admin:Product:show</a>

To find out if we are in a certain module or its submodule we can use isModuleCurrent(moduleName) function.

<li n:class="isModuleCurrent('MyEshop:Users') ? active">
	<a n:href="Product:">...</a>
</li>

Routing

See chapter on routing.

Mapping

Mapping defines the rules for deriving the class name from the presenter name. These rules are specified in the configuration under the key application › mapping.

The directory structures mentioned earlier on this page are based on the following mapping:

application:
	mapping: App\UI\*\**Presenter

How does the mapping work? For a better understanding, let's first imagine an application without modules. We want the presenter classes to fall under the namespace App\UI, so that the Home presenter maps to the class App\UI\HomePresenter. This can be achieved with this configuration:

application:
	mapping: App\UI\*Presenter

This mapping works by replacing the asterisk in the mask App\UI\*Presenter with the presenter name Home, resulting in the final class name App\UI\HomePresenter. Simple!

However, as you can see in the examples in this and other chapters, we place presenter classes in eponymous subdirectories, e.g., the Home presenter is mapped to the class App\UI\Home\HomePresenter. This is achieved by doubling the asterisk (requires Nette Application 3.2):

application:
	mapping: App\UI\**Presenter

Now, let's move on to mapping presenters into modules. We can define specific mappings for each module:

application:
	mapping:
		Front: App\UI\Front\**Presenter
		Admin: App\UI\Admin\**Presenter
		Api: App\Api\*Presenter

According to this configuration, the presenter Front:Home maps to the class App\UI\Front\Home\HomePresenter, while the presenter Api:OAuth maps to the class App\Api\OAuthPresenter.

Since the Front and Admin modules have a similar mapping approach and there are likely to be more such modules, it is possible to create a general rule that replaces them. A new asterisk for the module is added to the class mask:

application:
	mapping:
		*: App\UI\*\**Presenter
		Api: App\Api\*Presenter

For multi-level nested modules, such as the presenter Admin:User:Edit, the asterisk segment repeats for each level, resulting in the class App\UI\Admin\User\Edit\EditPresenter.

An alternative notation is to use an array composed of three segments instead of a string. This notation is equivalent to the previous one:

application:
	mapping:
		*: [App\UI, *, **Presenter]
		Api: [App\Api, '', *Presenter]

If we have only one rule in the configuration, the general one, we can write briefly:

application:
	mapping: App\UI\*\**Presenter