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
│   ├── Presenters/           ← Presenter-Klassen
│   │   ├── HomePresenter.php ← Home presenterklasse
│   │   └── templates/        ← Vorlagenverzeichnis
│   │       ├── @layout.latte ← Vorlage für gemeinsames Layout
│   │       └── Home/         ← Vorlagen für Home-presenter
│   │           └── default.latte  ← Vorlage für Aktion `default`
│   ├── Router/               ← Konfiguration von URL-Adressen
│   └── 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:

  1. die Umgebung zu initialisieren
  2. Abrufen der Fabrik
  3. 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/Router/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 gezeichnet werden soll, er leitet den Pfad dorthin nach einer einfachen Logik ab. Im Fall von presenter Product und action show versucht er zu sehen, ob eine dieser Vorlagendateien relativ zu dem Verzeichnis existiert, in dem sich die Klasse ProductPresenter befindet:

  • templates/Product/show.latte
  • templates/Product.show.latte

Außerdem wird versucht, das Layout in der Datei @layout.latte zu finden, und dann wird die Vorlage gerendert. Nun ist die Aufgabe des Präsentators und der gesamten Anwendung abgeschlossen. Wenn die Vorlage nicht existiert, wird eine Seite mit dem Fehler 404 zurückgegeben. 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:

  1. Die URL lautet dann https://example.com
  2. wir booten die Anwendung, erstellen einen Container und starten Application::run()
  3. der Router dekodiert die URL als ein Paar Home:default
  4. ein HomePresenter Objekt wird erstellt
  5. die Methode renderDefault() wird aufgerufen (falls vorhanden)
  6. eine Vorlage templates/Home/default.latte mit einem Layout templates/@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 💙.

Version: 4.0