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.
Creating Links
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>
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
.