Nette Documentation Preview

syntax
Wie funktionieren Anwendungen?
******************************

<div class=perex>

Sie lesen gerade das grundlegende Kapitel der Nette-Dokumentation. Sie erfahren das komplette Prinzip, wie Webanwendungen funktionieren - von A bis Z, vom Moment der Entstehung eines Requests bis zum Ende der Ausführung des PHP-Skripts. Nach der Lektüre werden Sie wissen:

- wie das Ganze funktioniert
- was Bootstrap, Presenter und der DI-Container sind
- wie die Verzeichnisstruktur aussieht

</div>


Verzeichnisstruktur
===================

Öffnen Sie das Beispielskelett einer Webanwendung namens [WebProject|https://github.com/nette/web-project]. Beim Lesen können Sie in die besprochenen Dateien hineinschauen.

Die Verzeichnisstruktur sieht ungefähr so aus:

/--pre
<b>web-project/</b>
├── <b>app/</b>                      ← Verzeichnis der Anwendung
│   ├── <b>Core/</b>                 ← für den Betrieb notwendige Basisklassen
│   │   └── <b>RouterFactory.php</b> ← Konfiguration der URL-Adressen
│   ├── <b>Presentation/</b>         ← Presenter, Templates & Co.
│   │   ├── <b>@layout.latte</b>     ← Template des Layouts
│   │   └── <b>Home/</b>             ← Verzeichnis des Home-Presenters
│   │       ├── <b>HomePresenter.php</b> ← Klasse des Home-Presenters
│   │       └── <b>default.latte</b> ← Template für die Aktion default
│   └── <b>Bootstrap.php</b>         ← Startklasse Bootstrap
├── <b>assets/</b>                   ← Ressourcen (SCSS, TypeScript, Quellbilder)
├── <b>bin/</b>                      ← von der Kommandozeile ausgeführte Skripte
├── <b>config/</b>                   ← Konfigurationsdateien
│   ├── <b>common.neon</b>
│   └── <b>services.neon</b>
├── <b>log/</b>                      ← protokollierte Fehler
├── <b>temp/</b>                     ← temporäre Dateien, Cache, …
├── <b>vendor/</b>                   ← von Composer installierte Bibliotheken
│   ├── ...
│   └── <b>autoload.php</b>          ← Autoloading aller installierten Pakete
├── <b>www/</b>                      ← öffentliches Verzeichnis, Document-Root des Projekts
│   ├── <b>assets/</b>               ← kompilierte statische Dateien (CSS, JS, Bilder, ...)
│   ├── <b>.htaccess</b>             ← Regeln für mod_rewrite
│   └── <b>index.php</b>             ← Startdatei, die die Anwendung startet
└── <b>.htaccess</b>                 ← verbietet den Zugriff auf alle Verzeichnisse außer www
\--

Sie können die Verzeichnisstruktur beliebig ändern, Ordner umbenennen oder verschieben; sie ist völlig flexibel. Nette verfügt außerdem über eine intelligente Autodetection und erkennt den Ort der Anwendung samt ihrer URL-Basis automatisch.

Bei etwas größeren Anwendungen können wir die Ordner mit Presentern und Templates in [Unterverzeichnisse |directory-structure#Presenter und Templates] gliedern und die Klassen in Namespaces zusammenfassen, die wir Module nennen.

Das Verzeichnis `www/` stellt das öffentliche Verzeichnis bzw. den Document-Root des Projekts dar. Sie können es umbenennen, ohne auf der Seite der Anwendung sonst etwas konfigurieren zu müssen. Sie müssen lediglich [das Hosting so einstellen |nette:troubleshooting#Wie ändert oder entfernt man das Verzeichnis www aus der URL?], dass der Document-Root auf dieses Verzeichnis zeigt.

WebProject können Sie samt Nette auch direkt mit [Composer |best-practices:composer] herunterladen:

```shell
composer create-project nette/web-project
```

Setzen Sie unter Linux oder macOS für die Verzeichnisse `log/` und `temp/` [Schreibrechte |nette:troubleshooting#Einstellung der Verzeichnisberechtigungen].

Die Anwendung WebProject ist startbereit; es ist überhaupt nichts zu konfigurieren, und Sie können sie direkt im Browser betrachten, indem Sie den Ordner `www/` aufrufen.


HTTP-Request
============

Alles beginnt damit, dass ein Benutzer im Browser eine Seite öffnet. Der Browser sendet einen HTTP-Request an den Server. Dieser Request zielt auf eine einzige PHP-Datei im öffentlichen Verzeichnis `www/`, nämlich `index.php`. Nehmen wir an, der Request gilt der Adresse `https://example.com/product/123`. Dank einer passenden [Serverkonfiguration |nette:troubleshooting#Wie konfiguriert man den Server für schöne URLs?] wird auch diese URL auf die Datei `index.php` abgebildet, die dann ausgeführt wird.

Ihre Aufgabe ist es:

1) die Umgebung zu initialisieren
2) die Factory zu beschaffen
3) die Nette-Anwendung zu starten, die den Request bearbeitet

Welche Factory? Wir stellen doch keine Traktoren her, wir bauen Websites! Nur Geduld, das wird gleich erklärt.

Mit "Initialisierung der Umgebung" meinen wir zum Beispiel die Aktivierung von [Tracy|tracy:], einem großartigen Werkzeug zum Protokollieren und Visualisieren von Fehlern. Auf dem Produktionsserver protokolliert es Fehler, in der Entwicklungsumgebung zeigt es sie direkt an. Zur Initialisierung gehört daher auch die Entscheidung, ob die Website im Produktions- oder im Entwicklungsmodus läuft. Nette nutzt dafür eine [intelligente Autodetection |bootstrapping#Entwicklungs- vs. Produktionsmodus]: Wenn Sie die Website auf localhost betreiben, läuft sie im Entwicklungsmodus. Sie müssen nichts konfigurieren, und die Anwendung ist sofort sowohl für die Entwicklung als auch für den Live-Betrieb bereit. Diese Schritte werden im Kapitel über die [Klasse Bootstrap|bootstrapping] ausgeführt und ausführlich beschrieben.

Der dritte Punkt (ja, den zweiten haben wir übersprungen, aber wir kommen darauf zurück) ist der Start der Anwendung. Die Bearbeitung von HTTP-Requests ist in Nette Aufgabe der Klasse `Nette\Application\Application` (im Folgenden `Application`). Wenn wir also sagen "die Anwendung starten", meinen wir konkret den Aufruf der treffend benannten Methode `run()` auf einem Objekt dieser Klasse.

Nette ist ein Mentor, der Sie dazu anleitet, saubere Anwendungen nach bewährten Methodiken zu schreiben. Eine der etabliertesten davon heißt **Dependency Injection**, kurz DI. Wir wollen Sie an dieser Stelle nicht mit der Erklärung von DI belasten, dafür gibt es ein [eigenes Kapitel|dependency-injection:introduction]. Die wesentliche Konsequenz ist, dass Schlüsselobjekte üblicherweise von einer Objekt-Factory erzeugt werden, die man **DI-Container** (kurz DIC) nennt. Ja, das ist die Factory, von der eben die Rede war. Sie erzeugt für uns auch das Objekt `Application`, weshalb wir zuerst den Container brauchen. Wir beschaffen ihn mit der Klasse `Configurator`, lassen ihn das Objekt `Application` erzeugen, rufen darauf die Methode `run()` auf, und damit startet die Nette-Anwendung. Genau das passiert in der Datei [index.php |bootstrapping#index.php].


Nette Application
=================

Die Klasse `Application` hat eine einzige Aufgabe: auf den HTTP-Request zu antworten.

In Nette geschriebene Anwendungen sind in viele sogenannte Presenter unterteilt (in anderen Frameworks begegnet Ihnen vielleicht der Begriff "Controller", was im Wesentlichen dasselbe ist). Das sind Klassen, von denen jede eine konkrete Seite der Website repräsentiert: z. B. die Startseite, ein Produkt im E-Shop, ein Anmeldeformular, einen Sitemap-Feed usw. Eine Anwendung kann von einem bis zu Tausenden von Presentern haben.

Die `Application` beginnt damit, dass sie den sogenannten Router fragt, welcher Presenter den aktuellen Request bearbeiten soll. Der Router entscheidet über die Zuständigkeit. Er schaut sich die Eingabe-URL `https://example.com/product/123` an und entscheidet anhand seiner Konfiguration, dass diese Aufgabe zum Beispiel dem **Presenter** `Product` gehört, der die **Aktion** `show` für das Produkt mit `id: 123` ausführen soll. Es ist eine gute Gewohnheit, das Paar Presenter + Aktion durch einen Doppelpunkt getrennt zu schreiben, also `Product:show`.

Der Router hat die URL also in das Paar `Presenter:Aktion` + Parameter umgewandelt, in unserem Fall `Product:show` + `id: 123`. Wie ein solcher Router aussieht, sehen Sie in der Datei `app/Core/RouterFactory.php`, und wir beschreiben ihn ausführlich im Kapitel [Routing |Routing].

Gehen wir weiter. Die `Application` kennt nun den Namen des Presenters und kann fortfahren. Sie erzeugt dazu eine Instanz der Klasse `ProductPresenter`, die den Code des Presenters `Product` enthält. Genauer gesagt bittet sie den DI-Container, den Presenter zu erzeugen, denn das Erzeugen von Objekten ist dessen Aufgabe.

Der Presenter könnte so aussehen:

```php
class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ProductRepository $repository,
	) {
	}

	public function renderShow(int $id): void
	{
		// Daten aus dem Model holen und an das Template übergeben
		$this->template->product = $this->repository->getProduct($id);
	}
}
```

Der Presenter übernimmt die Bearbeitung des Requests. Die Aufgabe ist klar: die Aktion `show` mit `id: 123` ausführen. In der Terminologie der Presenter bedeutet das, dass die Methode `renderShow()` aufgerufen wird, die im Parameter `$id` den Wert `123` erhält.

Ein Presenter kann mehrere Aktionen bearbeiten, also mehrere Methoden `render<Aktion>()` haben. Wir empfehlen jedoch, Presenter mit einer oder möglichst wenigen Aktionen zu entwerfen.

Es wurde also die Methode `renderShow(123)` aufgerufen. Ihr Code ist ein erfundenes Beispiel, zeigt aber, wie Daten an das Template übergeben werden, nämlich durch Schreiben in `$this->template`.

Anschließend gibt der Presenter eine Antwort zurück. Das kann eine HTML-Seite sein, ein Bild, ein XML-Dokument, das Senden einer Datei von der Festplatte, JSON oder auch eine Weiterleitung auf eine andere Seite. Wichtig ist: Wenn wir nicht ausdrücklich sagen, wie geantwortet werden soll (was bei `ProductPresenter` der Fall ist), lautet die Antwort, ein Template in eine HTML-Seite zu rendern. Warum? Weil wir in 99 % der Fälle ein Template rendern wollen. Deshalb macht der Presenter dieses Verhalten zum Standardverhalten und erleichtert uns die Arbeit. Das ist das Wesen von Nette.

Wir müssen nicht einmal angeben, welches Template gerendert werden soll; den Pfad leitet das Framework selbst ab. Im Fall der Aktion `show` versucht es einfach, das Template `show.latte` in dem Verzeichnis zu laden, in dem auch die Klasse `ProductPresenter` liegt. Ebenso versucht es, das Layout in der Datei `@layout.latte` zu finden (mehr zur [Suche nach Templates |templates#Suche nach Templates]).

Danach werden die Templates gerendert. Damit ist die Aufgabe des Presenters und der gesamten Anwendung erfüllt. Existiert das Template nicht, wird eine Fehlerseite 404 zurückgegeben. Mehr über Presenter erfahren Sie auf der Seite [Presenter|presenters].

[* request-flow.svg *]

Zur Sicherheit fassen wir den gesamten Ablauf noch einmal mit einer etwas anderen URL zusammen:

1) Die URL ist `https://example.com`
2) Die Anwendung startet, der DI-Container wird erzeugt und `Application::run()` wird ausgeführt.
3) Der Router dekodiert die URL in das Paar `Home:default`.
4) Es wird eine Instanz der Klasse `HomePresenter` erzeugt.
5) Die Methode `renderDefault()` wird aufgerufen (sofern sie existiert).
6) Das Template, z. B. `default.latte`, wird samt Layout, z. B. `@layout.latte`, gerendert.


Vielleicht sind Ihnen gerade viele neue Begriffe begegnet, aber wir glauben, dass sie Sinn ergeben. Anwendungen in Nette zu entwickeln ist bemerkenswert unkompliziert.


Templates
=========

Da wir gerade bei Templates sind: Nette verwendet das Templating-System [Latte |latte:]. Deshalb haben die Template-Dateien die Endung `.latte`. Latte wird vor allem deshalb verwendet, weil es das sicherste Templating-System für PHP ist und zugleich das intuitivste. Sie müssen nicht viel Neues lernen; Kenntnisse von PHP und einigen wenigen Tags genügen. Alles Nötige finden Sie [in der Dokumentation |templates].

Im Template [erstellen Sie Links |creating-links] auf andere Presenter & Aktionen so:

```latte
<a n:href="Product:show $productId">Produktdetail</a>
```

Schreiben Sie einfach das vertraute Paar `Presenter:Aktion` statt der tatsächlichen URL und ergänzen Sie eventuelle Parameter. Der Trick steckt in `n:href`, das Nette sagt, dieses Attribut zu verarbeiten. Es erzeugt dann:

```latte
<a href="/product/456">Produktdetail</a>
```

Um die Erzeugung der URL kümmert sich der bereits erwähnte Router. Router sind in Nette außergewöhnlich, weil sie nicht nur die Umwandlung einer URL in das Paar `Presenter:Aktion` beherrschen, sondern auch den umgekehrten Weg: aus dem Namen des Presenters, der Aktion und den Parametern eine URL zu erzeugen. Dadurch können Sie in einer fertigen Anwendung in Nette das URL-Format vollständig ändern, ohne in den Templates oder Presentern ein einziges Zeichen anzufassen - Sie ändern lediglich den Router. Das ermöglicht auch die sogenannte Kanonisierung, eine weitere einzigartige Eigenschaft von Nette, die das SEO (Search Engine Optimization) verbessert, indem sie automatisch verhindert, dass derselbe Inhalt unter verschiedenen URLs existiert. Viele Programmierer finden das erstaunlich.


Interaktive Komponenten
=======================

Über Presenter müssen wir Ihnen noch eines sagen: Sie haben ein eingebautes Komponentensystem. Erfahrenere erinnern sich vielleicht an etwas Ähnliches aus Delphi oder ASP.NET Web Forms; React oder Vue.js bauen auf entfernt verwandten Konzepten auf. In der Welt der PHP-Frameworks ist das eine völlig einzigartige Eigenschaft.

Komponenten sind eigenständige, wiederverwendbare Einheiten, die wir in Seiten (also in Presenter) einbetten. Das können [Formulare |forms:in-presenter] sein, [Datagrids |https://componette.org/contributte/datagrid/], Menüs, Umfragen - kurz alles, was sich sinnvoll wiederverwenden lässt. Wir können eigene Komponenten erstellen oder einige aus der [riesigen Auswahl |https://componette.org] an Open-Source-Komponenten nutzen.

Komponenten beeinflussen die Herangehensweise an die Anwendungsentwicklung grundlegend. Sie eröffnen neue Möglichkeiten, Seiten aus vorbereiteten Einheiten zusammenzusetzen. Und sie haben auch etwas mit [Hollywood |components#Hollywood Style] gemeinsam.


DI-Container und Konfiguration
==============================

Der DI-Container, also die Objekt-Factory, ist das Herz der gesamten Anwendung.

Keine Sorge, es ist keine magische Blackbox, wie es die vorangegangenen Zeilen vielleicht nahelegen. In Wirklichkeit ist es eine ziemlich langweilige PHP-Klasse, die Nette erzeugt und im Cache-Verzeichnis ablegt. Sie enthält viele Methoden mit Namen wie `createServiceAbcd()`, von denen jede ein bestimmtes Objekt erzeugen und zurückgeben kann. Ja, darunter ist auch die Methode `createServiceApplication__application()`, die die Instanz von `Nette\Application\Application` erzeugt, die wir in `index.php` zum Starten der Anwendung gebraucht haben. Und es gibt Methoden zum Erzeugen der einzelnen Presenter und so weiter.

Die vom DI-Container erzeugten Objekte nennt man aus irgendeinem Grund Services.

Das wirklich Besondere an dieser Klasse ist, dass Sie sie nicht programmieren - das übernimmt das Framework. Es erzeugt tatsächlich den PHP-Code und speichert ihn auf der Festplatte. Sie geben nur Anweisungen, welche Objekte der Container erzeugen können soll und wie genau. Diese Anweisungen stehen in [Konfigurationsdateien |bootstrapping#Konfiguration des DI-Containers], die das Format [NEON|neon:format] verwenden und daher die Endung `.neon` haben.

Konfigurationsdateien dienen ausschließlich dazu, den DI-Container zu instruieren. Wenn Sie also zum Beispiel im Abschnitt [session |http:configuration#Session] die Option `expiration: 14 days` angeben, ruft der DI-Container beim Erzeugen des Objekts `Nette\Http\Session`, das die Session repräsentiert, dessen Methode `setExpiration('14 days')` auf und macht die Konfiguration damit Wirklichkeit.

Für Sie ist ein ganzes Kapitel vorbereitet, das beschreibt, was sich alles [konfigurieren |nette:configuring] lässt und wie Sie [eigene Services definieren |dependency-injection:services].

Sobald Sie sich ein wenig in das Erzeugen von Services vertieft haben, begegnet Ihnen der Begriff [Autowiring |dependency-injection:autowiring]. Das ist eine Eigenschaft, die Ihnen das Leben unglaublich erleichtert. Sie kann Objekte automatisch dorthin übergeben, wo Sie sie brauchen (zum Beispiel in die Konstruktoren Ihrer Klassen), ohne dass Sie etwas tun müssen. Sie werden feststellen, dass der DI-Container in Nette ein kleines Wunder ist.


Wie geht es weiter?
===================

Wir haben die grundlegenden Prinzipien von Anwendungen in Nette durchgenommen. Bisher war es nur ein Blick an die Oberfläche, aber Sie werden bald tiefer eintauchen und mit der Zeit großartige Webanwendungen erschaffen. Wo geht es weiter? Haben Sie schon das Tutorial [Erstellen Sie Ihre erste Anwendung|quickstart:] ausprobiert?

Über das oben Beschriebene hinaus bietet Nette ein ganzes Arsenal [nützlicher Klassen|utils:], eine [Datenbankschicht|database:] usw. Klicken Sie sich ruhig durch die Dokumentation. Oder besuchen Sie den [Blog|https://blog.nette.org]. Sie werden viel Interessantes entdecken.

Möge Ihnen das Framework viel Freude bereiten 💙

Wie funktionieren Anwendungen?

Sie lesen gerade das grundlegende Kapitel der Nette-Dokumentation. Sie erfahren das komplette Prinzip, wie Webanwendungen funktionieren – von A bis Z, vom Moment der Entstehung eines Requests bis zum Ende der Ausführung des PHP-Skripts. Nach der Lektüre werden Sie wissen:

  • wie das Ganze funktioniert
  • was Bootstrap, Presenter und der DI-Container sind
  • wie die Verzeichnisstruktur aussieht

Verzeichnisstruktur

Öffnen Sie das Beispielskelett einer Webanwendung namens WebProject. Beim Lesen können Sie in die besprochenen Dateien hineinschauen.

Die Verzeichnisstruktur sieht ungefähr so aus:

web-project/
├── app/                      ← Verzeichnis der Anwendung
│   ├── Core/                 ← für den Betrieb notwendige Basisklassen
│   │   └── RouterFactory.php ← Konfiguration der URL-Adressen
│   ├── Presentation/         ← Presenter, Templates & Co.
│   │   ├── @layout.latte     ← Template des Layouts
│   │   └── Home/             ← Verzeichnis des Home-Presenters
│   │       ├── HomePresenter.php ← Klasse des Home-Presenters
│   │       └── default.latte ← Template für die Aktion default
│   └── Bootstrap.php         ← Startklasse Bootstrap
├── assets/                   ← Ressourcen (SCSS, TypeScript, Quellbilder)
├── bin/                      ← von der Kommandozeile ausgeführte Skripte
├── config/                   ← Konfigurationsdateien
│   ├── common.neon
│   └── services.neon
├── log/                      ← protokollierte Fehler
├── temp/                     ← temporäre Dateien, Cache, …
├── vendor/                   ← von Composer installierte Bibliotheken
│   ├── ...
│   └── autoload.php          ← Autoloading aller installierten Pakete
├── www/                      ← öffentliches Verzeichnis, Document-Root des Projekts
│   ├── assets/               ← kompilierte statische Dateien (CSS, JS, Bilder, ...)
│   ├── .htaccess             ← Regeln für mod_rewrite
│   └── index.php             ← Startdatei, 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; sie ist völlig flexibel. Nette verfügt außerdem über eine intelligente Autodetection und erkennt den Ort der Anwendung samt ihrer URL-Basis automatisch.

Bei etwas größeren Anwendungen können wir die Ordner mit Presentern und Templates in Unterverzeichnisse gliedern und die Klassen in Namespaces zusammenfassen, die wir Module nennen.

Das Verzeichnis www/ stellt das öffentliche Verzeichnis bzw. den Document-Root des Projekts dar. Sie können es umbenennen, ohne auf der Seite der Anwendung sonst etwas konfigurieren zu müssen. Sie müssen lediglich das Hosting so einstellen, dass der Document-Root auf dieses Verzeichnis zeigt.

WebProject können Sie samt Nette auch direkt mit Composer herunterladen:

composer create-project nette/web-project

Setzen Sie unter Linux oder macOS für die Verzeichnisse log/ und temp/ Schreibrechte.

Die Anwendung WebProject ist startbereit; es ist überhaupt nichts zu konfigurieren, und Sie können sie direkt im Browser betrachten, indem Sie den Ordner www/ aufrufen.

HTTP-Request

Alles beginnt damit, dass ein Benutzer im Browser eine Seite öffnet. Der Browser sendet einen HTTP-Request an den Server. Dieser Request zielt auf eine einzige PHP-Datei im öffentlichen Verzeichnis www/, nämlich index.php. Nehmen wir an, der Request gilt der Adresse https://example.com/product/123. Dank einer passenden Serverkonfiguration wird auch diese URL auf die Datei index.php abgebildet, die dann ausgeführt wird.

Ihre Aufgabe ist es:

  1. die Umgebung zu initialisieren
  2. die Factory zu beschaffen
  3. die Nette-Anwendung zu starten, die den Request bearbeitet

Welche Factory? Wir stellen doch keine Traktoren her, wir bauen Websites! Nur Geduld, das wird gleich erklärt.

Mit „Initialisierung der Umgebung“ meinen wir zum Beispiel die Aktivierung von Tracy, einem großartigen Werkzeug zum Protokollieren und Visualisieren von Fehlern. Auf dem Produktionsserver protokolliert es Fehler, in der Entwicklungsumgebung zeigt es sie direkt an. Zur Initialisierung gehört daher auch die Entscheidung, ob die Website im Produktions- oder im Entwicklungsmodus läuft. Nette nutzt dafür eine intelligente Autodetection: Wenn Sie die Website auf localhost betreiben, läuft sie im Entwicklungsmodus. Sie müssen nichts konfigurieren, und die Anwendung ist sofort sowohl für die Entwicklung als auch für den Live-Betrieb bereit. Diese Schritte werden im Kapitel über die Klasse Bootstrap ausgeführt und ausführlich beschrieben.

Der dritte Punkt (ja, den zweiten haben wir übersprungen, aber wir kommen darauf zurück) ist der Start der Anwendung. Die Bearbeitung von HTTP-Requests ist in Nette Aufgabe der Klasse Nette\Application\Application (im Folgenden Application). Wenn wir also sagen „die Anwendung starten“, meinen wir konkret den Aufruf der treffend benannten Methode run() auf einem Objekt dieser Klasse.

Nette ist ein Mentor, der Sie dazu anleitet, saubere Anwendungen nach bewährten Methodiken zu schreiben. Eine der etabliertesten davon heißt Dependency Injection, kurz DI. Wir wollen Sie an dieser Stelle nicht mit der Erklärung von DI belasten, dafür gibt es ein eigenes Kapitel. Die wesentliche Konsequenz ist, dass Schlüsselobjekte üblicherweise von einer Objekt-Factory erzeugt werden, die man DI-Container (kurz DIC) nennt. Ja, das ist die Factory, von der eben die Rede war. Sie erzeugt für uns auch das Objekt Application, weshalb wir zuerst den Container brauchen. Wir beschaffen ihn mit der Klasse Configurator, lassen ihn das Objekt Application erzeugen, rufen darauf die Methode run() auf, und damit startet die Nette-Anwendung. Genau das passiert in der Datei index.php.

Nette Application

Die Klasse Application hat eine einzige Aufgabe: auf den HTTP-Request zu antworten.

In Nette geschriebene Anwendungen sind in viele sogenannte Presenter unterteilt (in anderen Frameworks begegnet Ihnen vielleicht der Begriff „Controller“, was im Wesentlichen dasselbe ist). Das sind Klassen, von denen jede eine konkrete Seite der Website repräsentiert: z. B. die Startseite, ein Produkt im E-Shop, ein Anmeldeformular, einen Sitemap-Feed usw. Eine Anwendung kann von einem bis zu Tausenden von Presentern haben.

Die Application beginnt damit, dass sie den sogenannten Router fragt, welcher Presenter den aktuellen Request bearbeiten soll. Der Router entscheidet über die Zuständigkeit. Er schaut sich die Eingabe-URL https://example.com/product/123 an und entscheidet anhand seiner Konfiguration, dass diese Aufgabe zum Beispiel dem Presenter Product gehört, der die Aktion show für das Produkt mit id: 123 ausführen soll. Es ist eine gute Gewohnheit, das Paar Presenter + Aktion durch einen Doppelpunkt getrennt zu schreiben, also Product:show.

Der Router hat die URL also in das Paar Presenter:Aktion + Parameter umgewandelt, in unserem Fall Product:show + id: 123. Wie ein solcher Router aussieht, sehen Sie in der Datei app/Core/RouterFactory.php, und wir beschreiben ihn ausführlich im Kapitel Routing.

Gehen wir weiter. Die Application kennt nun den Namen des Presenters und kann fortfahren. Sie erzeugt dazu eine Instanz der Klasse ProductPresenter, die den Code des Presenters Product enthält. Genauer gesagt bittet sie den DI-Container, den Presenter zu erzeugen, denn das Erzeugen von Objekten ist dessen Aufgabe.

Der Presenter könnte so aussehen:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ProductRepository $repository,
	) {
	}

	public function renderShow(int $id): void
	{
		// Daten aus dem Model holen und an das Template übergeben
		$this->template->product = $this->repository->getProduct($id);
	}
}

Der Presenter übernimmt die Bearbeitung des Requests. Die Aufgabe ist klar: die Aktion show mit id: 123 ausführen. In der Terminologie der Presenter bedeutet das, dass die Methode renderShow() aufgerufen wird, die im Parameter $id den Wert 123 erhält.

Ein Presenter kann mehrere Aktionen bearbeiten, also mehrere Methoden render<Aktion>() haben. Wir empfehlen jedoch, Presenter mit einer oder möglichst wenigen Aktionen zu entwerfen.

Es wurde also die Methode renderShow(123) aufgerufen. Ihr Code ist ein erfundenes Beispiel, zeigt aber, wie Daten an das Template übergeben werden, nämlich durch Schreiben in $this->template.

Anschließend gibt der Presenter eine Antwort zurück. Das kann eine HTML-Seite sein, ein Bild, ein XML-Dokument, das Senden einer Datei von der Festplatte, JSON oder auch eine Weiterleitung auf eine andere Seite. Wichtig ist: Wenn wir nicht ausdrücklich sagen, wie geantwortet werden soll (was bei ProductPresenter der Fall ist), lautet die Antwort, ein Template in eine HTML-Seite zu rendern. Warum? Weil wir in 99 % der Fälle ein Template rendern wollen. Deshalb macht der Presenter dieses Verhalten zum Standardverhalten und erleichtert uns die Arbeit. Das ist das Wesen von Nette.

Wir müssen nicht einmal angeben, welches Template gerendert werden soll; den Pfad leitet das Framework selbst ab. Im Fall der Aktion show versucht es einfach, das Template show.latte in dem Verzeichnis zu laden, in dem auch die Klasse ProductPresenter liegt. Ebenso versucht es, das Layout in der Datei @layout.latte zu finden (mehr zur Suche nach Templates).

Danach werden die Templates gerendert. Damit ist die Aufgabe des Presenters und der gesamten Anwendung erfüllt. Existiert das Template nicht, wird eine Fehlerseite 404 zurückgegeben. Mehr über Presenter erfahren Sie auf der Seite Presenter.

Zur Sicherheit fassen wir den gesamten Ablauf noch einmal mit einer etwas anderen URL zusammen:

  1. Die URL ist https://example.com
  2. Die Anwendung startet, der DI-Container wird erzeugt und Application::run() wird ausgeführt.
  3. Der Router dekodiert die URL in das Paar Home:default.
  4. Es wird eine Instanz der Klasse HomePresenter erzeugt.
  5. Die Methode renderDefault() wird aufgerufen (sofern sie existiert).
  6. Das Template, z. B. default.latte, wird samt Layout, z. B. @layout.latte, gerendert.

Vielleicht sind Ihnen gerade viele neue Begriffe begegnet, aber wir glauben, dass sie Sinn ergeben. Anwendungen in Nette zu entwickeln ist bemerkenswert unkompliziert.

Templates

Da wir gerade bei Templates sind: Nette verwendet das Templating-System Latte. Deshalb haben die Template-Dateien die Endung .latte. Latte wird vor allem deshalb verwendet, weil es das sicherste Templating-System für PHP ist und zugleich das intuitivste. Sie müssen nicht viel Neues lernen; Kenntnisse von PHP und einigen wenigen Tags genügen. Alles Nötige finden Sie in der Dokumentation.

Im Template erstellen Sie Links auf andere Presenter & Aktionen so:

<a n:href="Product:show $productId">Produktdetail</a>

Schreiben Sie einfach das vertraute Paar Presenter:Aktion statt der tatsächlichen URL und ergänzen Sie eventuelle Parameter. Der Trick steckt in n:href, das Nette sagt, dieses Attribut zu verarbeiten. Es erzeugt dann:

<a href="/product/456">Produktdetail</a>

Um die Erzeugung der URL kümmert sich der bereits erwähnte Router. Router sind in Nette außergewöhnlich, weil sie nicht nur die Umwandlung einer URL in das Paar Presenter:Aktion beherrschen, sondern auch den umgekehrten Weg: aus dem Namen des Presenters, der Aktion und den Parametern eine URL zu erzeugen. Dadurch können Sie in einer fertigen Anwendung in Nette das URL-Format vollständig ändern, ohne in den Templates oder Presentern ein einziges Zeichen anzufassen – Sie ändern lediglich den Router. Das ermöglicht auch die sogenannte Kanonisierung, eine weitere einzigartige Eigenschaft von Nette, die das SEO (Search Engine Optimization) verbessert, indem sie automatisch verhindert, dass derselbe Inhalt unter verschiedenen URLs existiert. Viele Programmierer finden das erstaunlich.

Interaktive Komponenten

Über Presenter müssen wir Ihnen noch eines sagen: Sie haben ein eingebautes Komponentensystem. Erfahrenere erinnern sich vielleicht an etwas Ähnliches aus Delphi oder ASP.NET Web Forms; React oder Vue.js bauen auf entfernt verwandten Konzepten auf. In der Welt der PHP-Frameworks ist das eine völlig einzigartige Eigenschaft.

Komponenten sind eigenständige, wiederverwendbare Einheiten, die wir in Seiten (also in Presenter) einbetten. Das können Formulare sein, Datagrids, Menüs, Umfragen – kurz alles, was sich sinnvoll wiederverwenden lässt. Wir können eigene Komponenten erstellen oder einige aus der riesigen Auswahl an Open-Source-Komponenten nutzen.

Komponenten beeinflussen die Herangehensweise an die Anwendungsentwicklung grundlegend. Sie eröffnen neue Möglichkeiten, Seiten aus vorbereiteten Einheiten zusammenzusetzen. Und sie haben auch etwas mit Hollywood gemeinsam.

DI-Container und Konfiguration

Der DI-Container, also die Objekt-Factory, ist das Herz der gesamten Anwendung.

Keine Sorge, es ist keine magische Blackbox, wie es die vorangegangenen Zeilen vielleicht nahelegen. In Wirklichkeit ist es eine ziemlich langweilige PHP-Klasse, die Nette erzeugt und im Cache-Verzeichnis ablegt. Sie enthält viele Methoden mit Namen wie createServiceAbcd(), von denen jede ein bestimmtes Objekt erzeugen und zurückgeben kann. Ja, darunter ist auch die Methode createServiceApplication__application(), die die Instanz von Nette\Application\Application erzeugt, die wir in index.php zum Starten der Anwendung gebraucht haben. Und es gibt Methoden zum Erzeugen der einzelnen Presenter und so weiter.

Die vom DI-Container erzeugten Objekte nennt man aus irgendeinem Grund Services.

Das wirklich Besondere an dieser Klasse ist, dass Sie sie nicht programmieren – das übernimmt das Framework. Es erzeugt tatsächlich den PHP-Code und speichert ihn auf der Festplatte. Sie geben nur Anweisungen, welche Objekte der Container erzeugen können soll und wie genau. Diese Anweisungen stehen in Konfigurationsdateien, die das Format NEON verwenden und daher die Endung .neon haben.

Konfigurationsdateien dienen ausschließlich dazu, den DI-Container zu instruieren. Wenn Sie also zum Beispiel im Abschnitt session die Option expiration: 14 days angeben, ruft der DI-Container beim Erzeugen des Objekts Nette\Http\Session, das die Session repräsentiert, dessen Methode setExpiration('14 days') auf und macht die Konfiguration damit Wirklichkeit.

Für Sie ist ein ganzes Kapitel vorbereitet, das beschreibt, was sich alles konfigurieren lässt und wie Sie eigene Services definieren.

Sobald Sie sich ein wenig in das Erzeugen von Services vertieft haben, begegnet Ihnen der Begriff Autowiring. Das ist eine Eigenschaft, die Ihnen das Leben unglaublich erleichtert. Sie kann Objekte automatisch dorthin übergeben, wo Sie sie brauchen (zum Beispiel in die Konstruktoren Ihrer Klassen), ohne dass Sie etwas tun müssen. Sie werden feststellen, dass der DI-Container in Nette ein kleines Wunder ist.

Wie geht es weiter?

Wir haben die grundlegenden Prinzipien von Anwendungen in Nette durchgenommen. Bisher war es nur ein Blick an die Oberfläche, aber Sie werden bald tiefer eintauchen und mit der Zeit großartige Webanwendungen erschaffen. Wo geht es weiter? Haben Sie schon das Tutorial Erstellen Sie Ihre erste Anwendung ausprobiert?

Über das oben Beschriebene hinaus bietet Nette ein ganzes Arsenal nützlicher Klassen, eine Datenbankschicht usw. Klicken Sie sich ruhig durch die Dokumentation. Oder besuchen Sie den Blog. Sie werden viel Interessantes entdecken.

Möge Ihnen das Framework viel Freude bereiten 💙