Modules

In Nette, modules represent the logical units that make up an application. They include presenters, templates, possibly also components and model classes.

One directory for presenters and one for templates would not be enough for real projects. Having dozens of files in one folder is at least unorganized. How to get out of it? We simply split them into subdirectories on disk and into namespaces in the code. And that's exactly what the Nette modules do.

So let's forget about a single folder for presenters and templates and instead create modules, for example Admin and Front.

app/
├── Presenters/
├── Modules/              ← directory with modules
│   ├── Admin/            ← module Admin
│   │   ├── Presenters/   ← its presenters
│   │   │   ├── DashboardPresenter.php
│   │   │   └── templates/
│   └── Front/            ← module Front
│       └── Presenters/   ← its presenters
│           └── ...

This directory structure will be reflected by the class namespaces, so for example DashboardPresenter will be in the App\Modules\Admin\Presenters namespace:

namespace App\Modules\Admin\Presenters;

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

The Dashboard presenter inside the Admin module is referenced within the application using the colon notation as Admin:Dashboard, and its default action as Admin:Dashboard:default. And how does Nette proper know that Admin:Dashboard represents the App\Modules\Admin\Presenters\DashboardPresenter class? This is determined by mapping in the configuration. Thus, the given structure is not hard set and you can modify it according to your needs.

Modules can of course contain all other items besides presenters and templates, such as components, model classes, etc.

Nested Modules

Modules don't have to form only a flat structure, you can also create submodules, for example:

app/
├── Modules/              ← directory with modules
│   ├── Blog/             ← module Blog
│   │   ├── Admin/        ← submodule Admin
│   │   │   ├── Presenters/
│   │   │   └── ...
│   │   └── Front/        ← submodule Front
│   │       ├── Presenters/
│   │       └── ...
│   ├── Forum/            ← module Forum
│   │   └── ...

Thus, the Blog module is divided into Admin and Front submodules. Again, this will be reflected in the namespaces, which will be App\Modules\Blog\Admin\Presenters etc. The presenter Dashboard inside the submodule is referred to as Blog:Admin:Dashboard.

The nesting can go as deep as you like, so sub-submodules can be created.

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 $presenter->isModuleCurrent(moduleName) method.

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

Routing

See chapter on routing.

Mapping

Defines the rules by which the class name is derived from the presenter name. We write them in configuration under the application › mapping key.

Let's start with a sample that doesn't use modules. We'll just want the presenter classes to have the App\Presenters namespace. That means that a presenter such as Homepage should map to the App\Presenters\HomepagePresenter class. This can be achieved by the following configuration:

application:
	mapping:
		*: App\Presenters\*Presenter

The presenter name is replaced with the asterisk in the class mask and the result is the class name. Easy!

If we divide presenters into modules, we can have our own mapping for each module:

application:
	mapping:
		Front: App\Modules\Front\Presenters\*Presenter
		Admin: App\Modules\Admin\Presenters\*Presenter
		Api: App\Api\*Presenter

Now presenter Front:Homepage maps to class `App\Modules\Front\Presenters\HomepagePresenter and presenter Admin:Dashboard to class App\Modules\Admin\Presenters\DashboardPresenter.

It is more practical to create a general (star) rule to replace the first two. The extra asterisk will be added to the class mask just for the module:

application:
	mapping:
		*: App\Modules\*\Presenters\*Presenter
		Api: App\Api\*Presenter

But what if we use nested modules and have a presenter Admin:User:Edit? In this case, the segment with an asterisk representing the module for each level is simply repeated and the result is class App\Modules\Admin\User\Presenters\EditPresenter.

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

application:
	mapping:
		*: [App\Modules, *, Presenters\*Presenter]

The default value is *: *Module\*Presenter.