Multiplier: dynamische Komponenten
Ein Werkzeug für die dynamische Erstellung interaktiver Komponenten.
Beginnen wir mit einem typischen Beispiel: Stellen Sie sich eine Produktliste in einem E-Shop vor, bei der Sie zu jedem Artikel ein Formular “In den Warenkorb legen” ausgeben möchten. Eine mögliche Variante ist, die gesamte Auflistung in ein einziges Formular zu packen. Einen viel bequemeren Weg bietet jedoch Nette\Application\UI\Multiplier.
Der Multiplier erlaubt es, bequem eine Factory für mehrere Komponenten zu definieren. Er funktioniert nach dem Prinzip verschachtelter Komponenten – jede Komponente, die von Nette\ComponentModel\Container erbt, kann weitere Komponenten enthalten.
Siehe das Kapitel über das Komponentenmodell in der Dokumentation.
Das Wesen des Multipliers ist, dass er als Elternteil auftritt, der seine Kinder mithilfe eines im Konstruktor übergebenen Callbacks dynamisch erzeugen kann. Siehe das Beispiel:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Anzahl:')
->setRequired();
$form->addSubmit('send', 'In den Warenkorb');
return $form;
});
}
Nun können wir im Template ganz einfach zu jedem Produkt das Formular ausgeben lassen – und jedes davon wird wirklich eine eigenständige Komponente sein.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Das im Tag {control} übergebene Argument hat ein Format, das bedeutet:
- Hole die Komponente
shopForm. - Hole aus ihr das Kind mit dem Namen
$item->id.
Beim ersten Aufruf von Punkt 1 existiert die Komponente shopForm noch nicht, daher wird ihre Factory
createComponentShopForm aufgerufen. Auf der so erhaltenen Komponente (einer Instanz des Multipliers) wird dann die
Factory des konkreten Formulars aufgerufen – das ist die anonyme Funktion, die wir dem Konstruktor des Multipliers
übergeben haben.
In der nächsten Iteration der foreach-Schleife wird die Methode createComponentShopForm nicht erneut aufgerufen
(die Komponente existiert bereits). Da wir jedoch ein anderes Kind suchen (denn $item->id ist in jeder Iteration
anders), wird die anonyme Funktion erneut aufgerufen und liefert ein neues Formular zurück.
Es bleibt nur noch sicherzustellen, dass das Formular auch wirklich das richtige Produkt in den Warenkorb legt – derzeit ist
das Formular bei jedem Produkt identisch. Dabei hilft uns eine Eigenschaft des Multipliers (und generell jeder Komponenten-Factory
im Nette Framework): Jede Factory erhält als erstes Argument den Namen der erzeugten Komponente. Die Factory des Multipliers
erhält darüber hinaus als zweites Argument die Instanz des Multipliers selbst. In unserem Fall ist das erste Argument
$item->id, also genau die Information, die wir brauchen. Es genügt daher, die Erstellung des Formulars leicht
anzupassen:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function (string $itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('amount', 'Anzahl:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'In den Warenkorb');
return $form;
});
}