Wie funktionieren Bewerbungen?
Sie lesen gerade das Basisdokument der Nette-Dokumentation. Sie werden das ganze Prinzip der Webanwendungen kennenlernen. Nizza von A bis Z, vom Moment der Geburt bis zum letzten Atemzug des PHP-Skripts. Nach der Lektüre werden Sie wissen:
- wie das Ganze funktioniert
- was Bootstrap, Presenter und DI-Container sind
- wie die Verzeichnisstruktur aussieht
Struktur des Verzeichnisses
Öffnen Sie ein Beispiel für eine Webanwendung namens WebProject und beobachten Sie, wie die Dateien beschrieben werden.
Die Verzeichnisstruktur sieht in etwa so aus:
web-project/ ├── app/ ← Verzeichnis mit Anwendung │ ├── Core/ ← grundlegende notwendige Klassen │ │ └── RouterFactory.php ← Konfiguration der URL-Adressen │ ├── UI/ ← Moderatoren, Vorlagen & Co. │ │ ├── @layout.latte ← Vorlage für gemeinsames Layout │ │ └── Home/ ← Home Presenter Verzeichnis │ │ ├── HomePresenter.php ← Home Presenter Klasse │ │ └── default.latte ← Vorlage für Aktion default │ └── Bootstrap.php ← bootende Klasse Bootstrap ├── bin/ ← Skripte für die Kommandozeile ├── config/ ← Konfigurationsdateien │ ├── common.neon │ └── services.neon ├── log/ ← Fehlerprotokolle ├── temp/ ← temporäre Dateien, Cache, … ├── vendor/ ← vom Composer installierte Bibliotheken │ ├── ... │ └── autoload.php ← Automatisches Laden der vom Composer installierten Bibliotheken ├── www/ ← öffentliches Verzeichnis, Dokumentenstamm des Projekts │ ├── .htaccess ← mod_rewrite-Regeln usw. │ └── index.php ← Anfangsdatei, die die Anwendung startet └── .htaccess ← verbietet den Zugriff auf alle Verzeichnisse außer www
Sie können die Verzeichnisstruktur beliebig ändern, Ordner umbenennen oder verschieben, und dann einfach die Pfade zu
log/
und temp/
in der Datei Bootstrap.php
und den Pfad zu dieser Datei in
composer.json
im Abschnitt autoload
ändern. Nichts weiter, keine komplizierte Neukonfiguration, keine
ständigen Änderungen. Nette hat eine intelligente automatische
Erkennung.
Für etwas größere Anwendungen können wir Ordner mit Präsentatoren und Vorlagen in Unterverzeichnisse (auf der Festplatte) und in Namensräume (im Code) unterteilen, die wir Module nennen.
Das Verzeichnis www/
ist das öffentliche Verzeichnis oder die Dokumenten-Wurzel des Projekts. Sie können es
umbenennen, ohne etwas anderes auf der Anwendungsseite einstellen zu müssen. Sie müssen nur das Hosting so konfigurieren, dass die
Dokumentenwurzel in dieses Verzeichnis führt.
Sie können das WebProjekt auch direkt herunterladen, einschließlich Nette, indem Sie Composer verwenden:
composer create-project nette/web-project
Unter Linux oder macOS setzen Sie die Schreibrechte für die Verzeichnisse
log/
und temp/
.
Die WebProject-Anwendung ist einsatzbereit, es muss nichts weiter konfiguriert werden und Sie können sie direkt im Browser
anzeigen, indem Sie auf den Ordner www/
zugreifen.
HTTP-Anfrage
Alles beginnt damit, dass ein Benutzer die Seite in einem Browser öffnet und der Browser mit einer HTTP-Anfrage an den Server
klopft. Die Anfrage geht an eine PHP-Datei, die sich im öffentlichen Verzeichnis www/
befindet, also an
index.php
. Nehmen wir an, dass es sich um eine Anfrage an https://example.com/product/123
zugeordnet und
ausgeführt.
Seine Aufgabe ist:
- die Umgebung zu initialisieren
- Abrufen der Fabrik
- die Nette-Anwendung zu starten, die die Anfrage bearbeitet
Welche Art von Fabrik? Wir stellen keine Traktoren her, sondern Websites! Warten Sie, ich erkläre es Ihnen gleich.
Mit “die Umgebung initialisieren” meinen wir zum Beispiel, dass Tracy aktiviert wird, ein erstaunliches Werkzeug zur Protokollierung oder Visualisierung von Fehlern. Es protokolliert Fehler auf dem Produktionsserver und zeigt sie direkt auf dem Entwicklungsserver an. Daher muss bei der Initialisierung auch entschieden werden, ob die Site im Produktions- oder im Entwicklermodus läuft. Hierfür verwendet Nette eine automatische Erkennung: Wenn Sie die Site auf localhost ausführen, läuft sie im Entwicklermodus. Sie müssen nichts konfigurieren, und die Anwendung ist sowohl für die Entwicklung als auch für den Produktionseinsatz bereit. Diese Schritte werden im Kapitel über die Bootstrap-Klasse durchgeführt und ausführlich beschrieben.
Der dritte Punkt (ja, wir haben den zweiten übersprungen, aber wir werden darauf zurückkommen) ist das Starten der Anwendung.
Die Bearbeitung von HTTP-Anfragen in Nette erfolgt durch die Klasse Nette\Application\Application
(im Folgenden
Application
genannt). Wenn wir also sagen “eine Anwendung starten”, meinen wir den Aufruf einer Methode mit dem
Namen run()
auf einem Objekt dieser Klasse.
Nette ist ein Mentor, der Sie anleitet, saubere Anwendungen nach bewährten Methoden zu schreiben. Und die bewährteste heißt
dependency injection, abgekürzt DI. Wir wollen Sie an dieser Stelle nicht mit der Erklärung von DI belasten, dafür gibt
es ein eigenes Kapitel, wichtig ist, dass die
Schlüsselobjekte in der Regel von einer Fabrik für Objekte namens DI-Container (abgekürzt DIC) erzeugt werden. Ja, das
ist die Fabrik, die vor einiger Zeit erwähnt wurde. Und sie erstellt auch das Application
Objekt für uns, also
brauchen wir zuerst einen Container. Den holen wir uns mit der Klasse Configurator
und lassen ihn das Objekt
Application
erzeugen, rufen die Methode run()
auf und starten damit die Nette-Anwendung. Das ist genau
das, was in der Datei index.php passiert.
Nette-Anwendung
Die Klasse Application hat eine einzige Aufgabe: Sie soll auf eine HTTP-Anfrage antworten.
In Nette geschriebene Anwendungen sind in viele so genannte Presenter unterteilt (in anderen Frameworks stößt man vielleicht auf den Begriff Controller, der dasselbe bedeutet), bei denen es sich um Klassen handelt, die eine bestimmte Website-Seite repräsentieren: z. B. Homepage; Produkt im E-Shop; Anmeldeformular; Sitemap-Feed usw. Die Anwendung kann zwischen einem und Tausenden von Presentern haben.
Die Anwendung beginnt damit, dass sie den so genannten Router bittet, zu entscheiden, an welchen der Presenter die aktuelle
Anfrage zur Bearbeitung weitergeleitet werden soll. Der Router entscheidet, wer dafür zuständig ist. Er sieht sich die
Eingabe-URL https://example.com/product/123
handelt, der ein Produkt mit id: 123
als Aktion an
show
weiterleiten möchte. Es ist eine gute Angewohnheit, ein durch einen Doppelpunkt getrenntes Paar aus
Präsentator + Aktion als Product:show
zu schreiben.
Der Router verwandelt also die URL in ein Paar Presenter:action
+ Parameter, in unserem Fall
Product:show
+ id: 123
. Sie können sehen, wie ein Router in der Datei
app/Core/RouterFactory.php
aussieht, und wir werden ihn im Kapitel Routing ausführlich beschreiben.
Machen wir weiter. Die Anwendung kennt bereits den Namen des Präsentators und kann fortfahren. Sie erstellt ein Objekt
ProductPresenter
, das den Code des Presenters Product
darstellt. Genauer gesagt, sie bittet den
DI-Container um die Erstellung des Presenters, denn die Erstellung von Objekten ist seine Aufgabe.
Der Presenter könnte wie folgt aussehen:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// wir beziehen Daten aus dem Modell und übergeben sie an die Vorlage
$this->template->product = $this->repository->getProduct($id);
}
}
Die Anfrage wird vom Präsentator bearbeitet. Und die Aufgabe ist klar: Führe die Aktion show
mit
id: 123
aus. Was in der Sprache der Moderatoren bedeutet, dass die Methode renderShow()
aufgerufen wird
und im Parameter $id
steht 123
.
Ein Presenter kann mehrere Aktionen verarbeiten, also mehrere Methoden haben render<Action>()
. Wir empfehlen
jedoch, Presenter mit einer oder so wenigen Aktionen wie möglich zu entwerfen.
So wurde die Methode renderShow(123)
aufgerufen, deren Code ein fiktives Beispiel ist, aber Sie können daran
sehen, wie die Daten an die Vorlage übergeben werden, d.h. durch Schreiben an $this->template
.
Anschließend gibt der Präsentator die Antwort zurück. Dies kann eine HTML-Seite, ein Bild, ein XML-Dokument, das Senden
einer Datei von der Festplatte, JSON oder die Routing zu einer anderen Seite sein. Wichtig ist, dass, wenn wir nicht ausdrücklich
sagen, wie zu antworten ist (was bei ProductPresenter
der Fall ist), die Antwort darin besteht, die Vorlage mit einer
HTML-Seite wiederzugeben. Und warum? Nun, weil wir in 99 % der Fälle eine Vorlage zeichnen wollen, so dass der Präsentator
dieses Verhalten als Standard annimmt und uns die Arbeit erleichtern will. Das ist der Punkt von Nette.
Wir müssen nicht einmal angeben, welche Vorlage gerendert werden soll; das Framework wird den Pfad selbst ermitteln. Im Fall
der Aktion show
versucht es einfach, die Vorlage show.latte
im Verzeichnis mit der Klasse
ProductPresenter
zu laden. Es versucht auch, das Layout in der Datei @layout.latte
zu finden (mehr über
die Vorlagensuche).
Anschließend werden die Vorlagen gerendert. Damit ist die Aufgabe des Präsentators und der gesamten Anwendung abgeschlossen, und die Arbeit ist getan. Wenn die Vorlage nicht vorhanden wäre, würde eine 404-Fehlerseite zurückgegeben werden. Weitere Informationen über Präsentatoren finden Sie auf der Seite Präsentatoren.
Um sicherzugehen, versuchen wir, den gesamten Prozess mit einer etwas anderen URL zu rekapitulieren:
- Die URL lautet dann
https://example.com
- wir booten die Anwendung, erstellen einen Container und starten
Application::run()
- der Router dekodiert die URL als ein Paar
Home:default
- ein
HomePresenter
Objekt wird erstellt - die Methode
renderDefault()
wird aufgerufen (falls vorhanden) - eine Vorlage
default.latte
mit einem Layout@layout.latte
wird gerendert
Vielleicht sind Sie jetzt auf eine Menge neuer Konzepte gestoßen, aber wir glauben, dass sie sinnvoll sind. Das Erstellen von Anwendungen in Nette ist ein Kinderspiel.
Schablonen
Für die Vorlagen verwendet Nette das Latte-Vorlagensystem. Deshalb enden die Dateien
mit Vorlagen mit .latte
. Latte wird verwendet, weil es das sicherste Templatesystem für PHP und gleichzeitig das
intuitivste System ist. Sie müssen nicht viel Neues lernen, Sie müssen nur PHP und ein paar Latte-Tags kennen. Sie werden alles
in der Dokumentation finden.
In der Vorlage erstellen wir eine Verknüpfung zu anderen Moderatoren & Aktionen wie folgt:
<a n:href="Product:show $productId">product detail</a>
Schreiben Sie einfach das bekannte Presenter:action
-Paar anstelle der echten URL und fügen Sie beliebige
Parameter ein. Der Trick ist n:href
, das besagt, dass dieses Attribut von Nette verarbeitet wird. Und es wird
erzeugt:
<a href="/product/456">product detail</a>
Der bereits erwähnte Router ist für die Generierung der URL zuständig. Die Router in Nette sind insofern einzigartig, als sie nicht nur Transformationen von einer URL in ein Presenter:Action-Paar durchführen können, sondern auch umgekehrt eine URL aus dem Namen des Presenters + Action + Parameter generieren können. Dadurch kann man in Nette die Form der URL in der gesamten fertigen Anwendung komplett ändern, ohne auch nur ein einziges Zeichen in der Vorlage oder dem Presenter zu ändern, indem man einfach den Router modifiziert. Und dank dessen funktioniert die so genannte Kanonisierung, ein weiteres einzigartiges Feature von Nette, das die SEO (Optimierung der Auffindbarkeit im Internet) verbessert, indem es automatisch das Vorhandensein von doppeltem Inhalt unter verschiedenen URLs verhindert. Viele Programmierer finden das erstaunlich.
Interaktive Komponenten
Es gibt noch eine weitere Sache, die wir Ihnen über Presenter erzählen wollen: Sie haben ein eingebautes Komponentensystem. Die Älteren unter Ihnen erinnern sich vielleicht an etwas Ähnliches aus Delphi oder ASP.NET Web Forms. React oder Vue.js bauen auf etwas entfernt Ähnlichem auf. In der Welt der PHP-Frameworks ist dies eine völlig einzigartige Funktion.
Komponenten sind separate wiederverwendbare Einheiten, die wir in Seiten (d.h. Präsentatoren) einfügen. Dabei kann es sich um Formulare, Datenfelder, Menüs, Umfragen, eigentlich um alles handeln, was für eine wiederholte Verwendung sinnvoll ist. Wir können unsere eigenen Komponenten erstellen oder eine der zahlreichen Open-Source-Komponenten verwenden.
Komponenten verändern den Ansatz der Anwendungsentwicklung grundlegend. Sie eröffnen neue Möglichkeiten, Seiten aus vordefinierten Einheiten zusammenzustellen. Und sie haben etwas mit Hollywood gemeinsam.
DI-Container und Konfiguration
Der DI-Container (Fabrik für Objekte) ist das Herzstück der gesamten Anwendung.
Keine Sorge, es handelt sich nicht um eine magische Blackbox, wie es nach den vorangegangenen Worten den Anschein haben
könnte. Eigentlich handelt es sich um eine ziemlich langweilige PHP-Klasse, die von Nette generiert und in einem
Cache-Verzeichnis gespeichert wird. Sie hat eine Menge Methoden mit dem Namen createServiceAbcd()
und jede von ihnen
erzeugt ein Objekt und gibt es zurück. Ja, es gibt auch eine Methode createServiceApplication()
, die
Nette\Application\Application
erzeugt, die wir in der Datei index.php
benötigen, um die Anwendung
auszuführen. Und es gibt Methoden zur Erzeugung einzelner Präsentatoren. Und so weiter.
Die Objekte, die der DI-Container erzeugt, werden aus irgendeinem Grund Dienste genannt.
Das Besondere an dieser Klasse ist, dass sie nicht von Ihnen programmiert wird, sondern von dem Framework. Es generiert den
PHP-Code und speichert ihn auf der Festplatte. Sie geben lediglich Anweisungen, welche Objekte der Container wie genau erzeugen
soll. Und diese Anweisungen werden in Konfigurationsdateien im NEON-Format geschrieben und haben daher die Endung .neon
.
Die Konfigurationsdateien dienen nur dazu, den DI-Container zu instruieren. Wenn ich also zum Beispiel die Option
expiration: 14 days
im Abschnitt Session
angebe, wird der DI-Container bei der Erstellung des Nette\Http\Session
-Objekts, das die Session repräsentiert,
seine Methode setExpiration('14 days')
aufrufen, und damit wird die Konfiguration Wirklichkeit.
Es steht ein ganzes Kapitel für Sie bereit, in dem beschrieben wird, was konfiguriert werden kann und wie Sie Ihre eigenen Dienste definieren können.
Sobald Sie sich mit der Erstellung von Diensten befassen, werden Sie auf das Wort Autowiring stoßen. Das ist ein Gadget, das Ihnen das Leben unglaublich erleichtern wird. Es kann Objekte automatisch dort übergeben, wo Sie sie brauchen (z. B. in den Konstruktoren Ihrer Klassen), ohne dass Sie etwas tun müssen. Sie werden feststellen, dass der DI-Container in Nette ein kleines Wunderwerk ist.
Wie geht es weiter?
Wir haben die Grundprinzipien von Anwendungen in Nette durchgenommen. Bisher sehr oberflächlich, aber Sie werden bald in die Tiefe gehen und schließlich wunderbare Webanwendungen erstellen. Wo soll es weitergehen? Haben Sie schon das Tutorial Erstellen Sie Ihre erste Anwendung ausprobiert?
Darüber hinaus verfügt Nette über ein ganzes Arsenal an nützlichen Klassen, Datenbankschichten usw. Klicken Sie sich doch einfach mal durch die Dokumentation. Oder besuchen Sie den Blog. Sie werden eine Menge interessanter Dinge entdecken.
Möge das Framework Ihnen viel Freude bereiten 💙.