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).