Module
Module bringen Klarheit in Nette-Anwendungen, indem sie eine einfache Unterteilung in logische Einheiten ermöglichen.
Ähnlich wie bei der Organisation von Dateien in Ordnern auf einer Festplatte, können wir in Nette Presenter, Vorlagen und andere Hilfsklassen in Module unterteilen. Wie funktioniert das in der Praxis? Ganz einfach, indem man neue Unterverzeichnisse in die Struktur einfügt. Hier ist ein Beispiel für eine Struktur mit zwei Modulen, Front und Admin:
app/ ├── UI/ │ ├── Admin/ ← Admin module │ │ ├── @layout.latte │ │ ├── Dashboard/ │ │ │ ├── DashboardPresenter.php │ │ │ └── default.latte │ │ └── ... │ ├── Front/ ← Front module │ │ ├── @layout.latte │ │ ├── Home/ │ │ │ ├── HomePresenter.php │ │ │ └── default.latte │ │ └── ...
Diese Verzeichnisstruktur spiegelt sich in den Namespaces der Klassen wider, so befindet sich z.B.
DashboardPresenter
im Namespace App\UI\Admin\Dashboard
:
namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
// ...
}
In der Anwendung wird der Presenter Dashboard
innerhalb des Moduls Admin
mit Doppelpunkt als
Admin:Dashboard
bezeichnet. Für die Aktion default
wird er als Admin:Dashboard:default
bezeichnet.
Die vorgestellte Struktur ist nicht starr; Sie können sie in der Konfiguration vollständig an Ihre Bedürfnisse anpassen.
Module können neben Presentern und Vorlagen auch alle anderen Dateien, wie Komponenten und Hilfsklassen, enthalten. Wenn Sie
überlegen, wo Sie diese ablegen wollen, sollten Sie einen Ordner Accessory
verwenden:
app/ ├── UI/ │ ├── Admin/ │ │ ├── Accessory/ │ │ │ ├── FormFactory.php │ │ │ └── AdminLayout.php │ │ ├── Dashboard/ │ │ └── ...
Verschachtelte Module
Module können mehrere Verschachtelungsebenen haben, ähnlich wie eine Verzeichnisstruktur auf einer Festplatte:
app/ ├── UI/ │ ├── Blog/ ← Blog module │ │ ├── Admin/ ← Admin submodule │ │ │ ├── Dashboard/ │ │ │ └── ... │ │ ├── Front/ ← Front submodule │ │ │ ├── @layout.latte │ │ │ ├── Home/ │ │ │ └── ... │ ├── Forum/ ← Forum module │ │ └── ...
Das Modul Blog
ist in die Untermodule Admin
und Front
unterteilt. Dies spiegelt sich
auch in den Namespaces wider, die dann als App\UI\Blog\Admin
und ähnlich erscheinen. Um auf den Präsentator
Dashboard
innerhalb des Submoduls Admin
zu verweisen, wird er als Blog:Admin:Dashboard
bezeichnet.
Die Verschachtelung kann so tief wie nötig sein und erlaubt die Erstellung von Sub-Submodulen.
Wenn Sie zum Beispiel in der Verwaltung viele Präsentatoren haben, die mit der Auftragsverwaltung zusammenhängen, wie
OrderDetail
, OrderEdit
, OrderDispatch
, usw., könnten Sie ein Order
Modul
erstellen, in dem Präsentatoren wie Detail
, Edit
, Dispatch
und andere organisiert
werden.
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.
Kartierung
Mapping definiert die Regeln für die Ableitung des Klassennamens aus dem Presenter-Namen. Diese Regeln werden in der Konfiguration unter dem Schlüssel
application › mapping
angegeben.
Die oben auf dieser Seite erwähnten Verzeichnisstrukturen basieren auf der folgenden Zuordnung:
application:
mapping: App\UI\*\**Presenter
Wie funktioniert das Mapping? Zum besseren Verständnis stellen wir uns zunächst eine Anwendung ohne Module vor. Wir wollen,
dass die Presenter-Klassen in den Namensraum App\UI
fallen, so dass der Presenter Home
auf die Klasse
App\UI\HomePresenter
abgebildet wird. Dies kann mit dieser Konfiguration erreicht werden:
application:
mapping: App\UI\*Presenter
Diese Zuordnung funktioniert, indem das Sternchen in der Maske App\UI\*Presenter
durch den Presenter-Namen
Home
ersetzt wird, was zu dem endgültigen Klassennamen App\UI\HomePresenter
führt. Einfach!
Wie Sie jedoch in den Beispielen in diesem und anderen Kapiteln sehen können, platzieren wir Presenter-Klassen in
gleichnamigen Unterverzeichnissen, z. B. wird der Presenter Home
der Klasse App\UI\Home\HomePresenter
zugeordnet. Dies wird durch die Verdoppelung des Sternchens erreicht (erfordert Nette Application 3.2):
application:
mapping: App\UI\**Presenter
Gehen wir nun dazu über, Presenter in Modulen abzubilden. Für jedes Modul können wir spezifische Zuordnungen definieren:
application:
mapping:
Front: App\UI\Front\**Presenter
Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
Nach dieser Konfiguration wird der Präsentator Front:Home
der Klasse App\UI\Front\Home\HomePresenter
zugeordnet, während der Präsentator Api:OAuth
der Klasse App\Api\OAuthPresenter
zugeordnet wird.
Da die Module Front
und Admin
einen ähnlichen Zuordnungsansatz haben und es wahrscheinlich noch mehr
solcher Module gibt, ist es möglich, eine allgemeine Regel zu erstellen, die sie ersetzt. In der Klassenmaske wird ein neues
Sternchen für das Modul hinzugefügt:
application:
mapping:
*: App\UI\*\**Presenter
Api: App\Api\*Presenter
Bei mehrstufig verschachtelten Modulen, wie z. B. dem Moderator Admin:User:Edit
, wird das Sternchen-Segment für
jede Stufe wiederholt, was zu der Klasse App\UI\Admin\User\Edit\EditPresenter
führt.
Eine alternative Schreibweise ist die Verwendung eines Arrays, das aus drei Segmenten besteht, anstelle einer Zeichenkette. Diese Notation ist äquivalent zur vorherigen:
application:
mapping:
*: [App\UI, *, **Presenter]
Api: [App\Api, '', *Presenter]
Wenn wir nur eine Regel in der Konfiguration haben, die allgemeine, können wir kurz schreiben:
application:
mapping: App\UI\*\**Presenter