Module
In Nette stellen Module die logischen Einheiten dar, aus denen eine Anwendung besteht. Sie umfassen Presenter, Templates, eventuell auch Komponenten und Modellklassen.
Ein Verzeichnis für Presenter und eines für Templates würde für echte Projekte nicht ausreichen. Dutzende von Dateien in einem Ordner zu haben, ist zumindest unorganisiert. Wie kommt man da wieder raus? Wir teilen sie einfach in Unterverzeichnisse auf der Festplatte und in Namensräume im Code auf. Und das ist genau das, was die Nette-Module tun.
Vergessen wir also einen einzigen Ordner für Präsentatoren und Vorlagen und erstellen wir stattdessen Module, zum Beispiel
Admin
und Front
.
app/ ├──Presenters/├── Modules/ ← Verzeichnis mit Modulen │ ├── Admin/ ← Modul Admin │ │ ├── Presenters/ ← seine Presenters │ │ │ ├── DashboardPresenter.php │ │ │ └── templates/ │ └── Front/ ← Modul Front │ └── Presenters/ ← seine Presenters │ └── ...
Diese Verzeichnisstruktur spiegelt sich in den Klassennamensräumen wider, so dass z. B. DashboardPresenter
im
Namensraum App\Modules\Admin\Presenters
liegt:
namespace App\Modules\Admin\Presenters;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
Der Präsentator Dashboard
innerhalb des Moduls Admin
wird innerhalb der Anwendung mit der
Doppelpunktschreibweise als Admin:Dashboard
referenziert, und seine Aktion default
als
Admin:Dashboard:default
. Und woher weiß Nette selbst, dass Admin:Dashboard
die Klasse
App\Modules\Admin\Presenters\DashboardPresenter
repräsentiert? Dies wird durch ein Mapping in der Konfiguration festgelegt. Die vorgegebene Struktur ist also nicht fest vorgegeben und kann
nach Belieben verändert werden.
Module können neben Presentern und Templates natürlich auch alle anderen Elemente enthalten, wie z.B. Komponenten, Modellklassen, etc.
Verschachtelte Module
Module müssen nicht nur eine flache Struktur bilden, Sie können auch Untermodule erstellen, zum Beispiel:
app/ ├── Modules/ ← Verzeichnis mit Modulen │ ├── Blog/ ← Modul Blog │ │ ├── Admin/ ← Submodul Admin │ │ │ ├── Presenters/ │ │ │ └── ... │ │ └── Front/ ← Submodul Front │ │ ├── Presenters/ │ │ └── ... │ ├── Forum/ ← Modul Forum │ │ └── ...
So wird das Modul Blog
in die Untermodule Admin
und Front
aufgeteilt. Dies spiegelt sich
auch in den Namensräumen wider, die dann App\Modules\Blog\Admin\Presenters
usw. lauten. Der Präsentator
Dashboard
innerhalb des Submoduls wird als Blog:Admin:Dashboard
bezeichnet.
Die Verschachtelung kann beliebig tief gehen, so dass Sub-Submodule erstellt werden können.
Erstellen von Links
Links in Präsentatorvorlagen sind relativ zum aktuellen Modul. So führt der Link Foo:default
zu dem Präsentator
Foo
im gleichen Modul wie der aktuelle Präsentator. Wenn das aktuelle Modul zum Beispiel Front
ist,
sieht der Link so aus:
<a n:href="Product:show">link to Front:Product:show</a>
Ein Link ist auch dann relativ, wenn er den Namen eines Moduls enthält, das dann als Untermodul betrachtet wird:
<a n:href="Shop:Product:show">link to Front:Shop:Product:show</a>
Absolute Links werden analog zu absoluten Pfaden auf der Festplatte geschrieben, jedoch mit Doppelpunkten anstelle von Schrägstrichen. Ein absoluter Link beginnt also mit einem Doppelpunkt:
<a n:href=":Admin:Product:show">link to Admin:Product:show</a>
Um herauszufinden, ob wir uns in einem bestimmten Modul oder dessen Untermodul befinden, können wir die Funktion
isModuleCurrent(moduleName)
verwenden.
<li n:class="isModuleCurrent('MyEshop:Users') ? active">
<a n:href="Product:">...</a>
</li>
Routing
Siehe Kapitel über Routing.
Abbildung
Legt die Regeln fest, nach denen der Klassenname aus dem Namen des Präsentators abgeleitet wird. Wir schreiben sie in die Konfiguration unter dem Schlüssel
application › mapping
.
Beginnen wir mit einem Beispiel, das keine Module verwendet. Wir wollen nur, dass die Presenter-Klassen den Namespace
App\Presenters
haben. Das bedeutet, dass ein Presenter wie Home
auf die Klasse
App\Presenters\HomePresenter
abgebildet werden soll. Dies kann durch die folgende Konfiguration erreicht werden:
application:
mapping:
*: App\Presenters\*Presenter
Der Name des Presenters wird durch das Sternchen in der Klassenmaske ersetzt und das Ergebnis ist der Klassenname. Einfach!
Wenn wir die Vortragenden in Module unterteilen, können wir für jedes Modul eine eigene Zuordnung vornehmen:
application:
mapping:
Front: App\Modules\Front\Presenters\*Presenter
Admin: App\Modules\Admin\Presenters\*Presenter
Api: App\Api\*Presenter
Der Referent Front:Home
wird der Klasse App\Modules\Front\Presenters\HomePresenter
zugeordnet und der
Referent Admin:Dashboard
der Klasse App\Modules\Admin\Presenters\DashboardPresenter
.
Es ist praktischer, eine allgemeine (Stern-)Regel zu erstellen, um die ersten beiden zu ersetzen. Das zusätzliche Sternchen wird der Klassenmaske nur für dieses Modul hinzugefügt:
application:
mapping:
*: App\Modules\*\Presenters\*Presenter
Api: App\Api\*Presenter
Was aber, wenn wir verschachtelte Module verwenden und einen Präsentator Admin:User:Edit
haben? In diesem Fall
wird das Segment mit dem Sternchen, das das Modul für jede Ebene darstellt, einfach wiederholt und das Ergebnis ist die Klasse
App\Modules\Admin\User\Presenters\EditPresenter
.
Eine alternative Schreibweise ist die Verwendung eines Arrays, das aus drei Segmenten anstelle einer Zeichenkette besteht. Diese Notation ist gleichwertig mit der vorherigen:
application:
mapping:
*: [App\Modules, *, Presenters\*Presenter]
Der Standardwert ist *: *Module\*Presenter
.