Komponentenmodell

Ein wichtiger Begriff in Nette ist die Komponente. Wir fügen visuelle interaktive Komponenten in Seiten ein, auch Formulare oder alle ihre Elemente sind Komponenten. Die beiden Basisklassen, von denen alle diese Komponenten erben, sind Teil des Pakets nette/component-model und haben die Aufgabe, eine Baumhierarchie von Komponenten zu erstellen.

Component

Nette\ComponentModel\Component ist der gemeinsame Vorfahre aller Komponenten. Es enthält die Methoden getName(), die den Namen der Komponente zurückgibt, und die Methode getParent(), die ihren Elternteil zurückgibt. Beides kann mit der Methode setParent() eingestellt werden – der erste Parameter ist der Elternteil und der zweite der Komponentenname.

lookup (string $type): ?Component

Sucht in der Hierarchie nach oben nach einem Objekt der gewünschten Klasse oder Schnittstelle. Zum Beispiel gibt $component->lookup(Nette\Application\UI\Presenter::class) den Presenter zurück, wenn die Komponente, auch über mehrere Ebenen hinweg, mit ihm verbunden ist.

lookupPath (string $type): ?string

Gibt den sogenannten Pfad zurück, eine Zeichenkette, die durch die Verkettung der Namen aller Komponenten auf dem Weg zwischen der aktuellen und der gesuchten Komponente entsteht. Zum Beispiel gibt $component->lookupPath(Nette\Application\UI\Presenter::class) einen eindeutigen Bezeichner der Komponente relativ zum Presenter zurück.

Container

Nette\ComponentModel\Container ist die Elternkomponente, d.h. eine Komponente, die Nachkommen enthält und somit eine Baumstruktur bildet. Sie verfügt über Methoden zum einfachen Hinzufügen, Abrufen und Entfernen von Objekten. Sie ist beispielsweise der Vorfahre von Formularen oder den Klassen Control und Presenter.

getComponent (string $name): ?Component

Gibt die Komponente zurück. Beim Versuch, einen undefinierten Nachkommen abzurufen, wird die Factory createComponent($name) aufgerufen. Die Methode createComponent($name) ruft in der aktuellen Komponente die Methode createComponent<Komponentenname> auf und übergibt ihr den Komponentennamen als Parameter. Die erstellte Komponente wird dann der aktuellen Komponente als ihr Nachkomme hinzugefügt. Diese Methoden nennen wir Komponentenfabriken und sie können von Nachkommen der Klasse Container implementiert werden.

getComponents(): array

Gibt die direkten Nachkommen als Array zurück. Die Schlüssel enthalten die Namen dieser Komponenten. Hinweis: In Version 3.0.x gab die Methode anstelle eines Arrays einen Iterator zurück, und ihr erster Parameter bestimmte, ob die Komponenten in die Tiefe durchlaufen werden sollten, und der zweite stellte einen Typfilter dar. Diese Parameter sind deprecated.

getComponentTree(): array

Ruft die gesamte Komponenten-Hierarchie einschließlich aller verschachtelten untergeordneten Komponenten als indiziertes Array ab. Die Suche erfolgt zuerst in die Tiefe.

Überwachung der Vorfahren

Das Komponentenmodell von Nette ermöglicht eine sehr dynamische Arbeit mit dem Baum (Komponenten können entfernt, verschoben, hinzugefügt werden), daher wäre es ein Fehler, sich darauf zu verlassen, dass nach dem Erstellen einer Komponente sofort (im Konstruktor) der Elternteil, der Elternteil des Elternteils usw. bekannt ist. Meistens ist der Elternteil zum Zeitpunkt der Erstellung überhaupt nicht bekannt.

Wie erkennt man, wann eine Komponente in den Presenter-Baum eingehängt wurde? Die Änderung des Elternteils zu beobachten reicht nicht aus, da möglicherweise der Elternteil des Elternteils mit dem Presenter verbunden wurde. Die Methode monitor($type, $attached, $detached) hilft dabei. Jede Komponente kann eine beliebige Anzahl von Klassen und Schnittstellen überwachen. Das Einhängen oder Aushängen wird durch den Aufruf des Callbacks $attached bzw. $detached gemeldet, wobei das Objekt der überwachten Klasse übergeben wird.

Zum besseren Verständnis ein Beispiel: Die Klasse UploadControl, die ein Formularelement für den Datei-Upload in Nette Forms darstellt, muss das Attribut enctype des Formulars auf den Wert multipart/form-data setzen. Zum Zeitpunkt der Objekterstellung muss sie jedoch nicht mit einem Formular verbunden sein. Wann soll das Formular also modifiziert werden? Die Lösung ist einfach – im Konstruktor wird die Überwachung angefordert:

class UploadControl extends Nette\Forms\Controls\BaseControl
{
	public function __construct($label)
	{
		$this->monitor(Nette\Forms\Form::class, function ($form): void {
			$form->setHtmlAttribute('enctype', 'multipart/form-data');
		});
		// ...
	}

	// ...
}

und sobald das Formular verfügbar ist, wird der Callback aufgerufen. (Früher wurde stattdessen die gemeinsame Methode attached bzw. detached verwendet).

Version: 3.x