Komponenten-Modell
Ein wichtiges Konzept in Nette ist die Komponente. Wir fügen visuelle interaktive Komponenten in Seiten, Formulare oder alle ihre
Elemente sind ebenfalls Komponenten. Es gibt zwei Basisklassen, von denen alle diese Komponenten erben, die Teil des Pakets
nette/component-model
sind und für die Erstellung der Komponentenbaumhierarchie verantwortlich sind.
Component
Nette\ComponentModel\Component ist
der gemeinsame Vorfahre aller Komponenten. Sie enthält die Methode getName()
, die den Namen der Komponente
zurückgibt, und die Methode getParent()
, die die übergeordnete Komponente zurückgibt. Beide können mit der
Methode setParent()
gesetzt werden – der erste Parameter ist der Elternteil und der zweite der
Komponentenname.
lookup(string $type): ?Component
Sucht in der Hierarchie nach einem Objekt der gewünschten Klasse oder Schnittstelle. Zum Beispiel gibt
$component->lookup(Nette\Application\UI\Presenter::class)
presenter zurück, wenn die Komponente trotz mehrerer
Ebenen mit ihm verbunden ist.
lookupPath(string $type): ?string
Gibt den so genannten Pfad zurück, d. h. eine Zeichenkette, die aus der Verkettung der Namen aller Komponenten auf dem Pfad
zwischen der aktuellen Komponente und der gesuchten Komponente besteht. So gibt z. B.
$component->lookupPath(Nette\Application\UI\Presenter::class)
den eindeutigen Bezeichner der Komponente relativ
zum Präsentator zurück.
Container
Nette\ComponentModel\Container ist
die übergeordnete Komponente, d. h. die Komponente, die die Kinder enthält und somit die Baumstruktur bildet. Er verfügt über
Methoden zum einfachen Hinzufügen, Abrufen und Entfernen von Komponenten. Er ist der Vorfahre z.B. des Formulars oder der Klassen
Control
und Presenter
.
getComponent(string $name): ?Component
Gibt eine Komponente zurück. Der Versuch, ein undefiniertes Kind aufzurufen, führt zum Aufruf der Fabrik createComponent($name).
Die Methode createComponent($name)
ruft die Methode createComponent<component name>
in der
aktuellen Komponente auf und übergibt den Namen der Komponente als Parameter. Die erstellte Komponente wird dann an die aktuelle
Komponente als ihr Kind übergeben. Wir nennen diese Komponentenfabriken, sie können in von Container
geerbten
Klassen implementiert werden.
getComponents(): array
Gibt direkte Nachkommen als Array zurück. Die Schlüssel enthalten die Namen dieser Komponenten. Hinweis: In Version 3.0.x gab die Methode einen Iterator statt eines Arrays zurück. Der erste Parameter gab an, ob durch die Komponenten in der Tiefe iteriert werden sollte, und der zweite Parameter stellte einen Typfilter dar. Diese Parameter sind veraltet.
getComponentTree(): array
Gibt die gesamte Hierarchie der Komponenten, einschließlich aller verschachtelten untergeordneten Komponenten, als indiziertes Array zurück. Die Suche geht zunächst in die Tiefe.
Überwachung der Vorfahren
Das Nette-Komponentenmodell erlaubt eine sehr dynamische Baumarbeit (wir können Komponenten entfernen, verschieben, hinzufügen), so dass es ein Fehler wäre, sich darauf zu verlassen, dass nach dem Erstellen einer Komponente der Elternteil, der Elternteil des Elternteils usw. sofort bekannt sind (im Konstruktor). Normalerweise ist das Elternteil bei der Erstellung der Komponente überhaupt nicht bekannt.
Wie kann man herausfinden, wann eine Komponente zum Präsentationsbaum hinzugefügt wurde? Es reicht nicht aus, die Änderung
des Parents zu verfolgen, denn der Parent des Parents könnte z.B. an den Presenter angehängt worden sein. Die monitor($type, $attached,
$detached) Methode kann hier helfen. Jede Komponente kann eine beliebige Anzahl von Klassen und Schnittstellen überwachen.
Die Verbindung oder Trennung wird durch den Aufruf der Callbacks $attached
bzw. $detached
angekündigt,
wobei das Objekt der überwachten Klasse übergeben wird.
Ein Beispiel: Die Klasse UploadControl
, die das Formularelement zum Hochladen von Dateien in Nette Forms
repräsentiert, muss das Attribut enctype
des Formulars auf den Wert multipart/form-data
setzen. Zum
Zeitpunkt der Erstellung des Objekts muss es jedoch an kein Formular angehängt sein. Wann soll das Formular geändert werden? Die
Lösung ist einfach – wir erstellen eine Anfrage zur Überwachung im Konstruktor:
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 wenn das Formular verfügbar ist, wird der Callback aufgerufen. (Zuvor wurden stattdessen die üblichen Methoden
attached
und detached
verwendet).