Mnożnik: składniki dynamiczne
Narzędzie do dynamicznego tworzenia interaktywnych komponentów
Zacznijmy od typowego przykładu: miejmy listę przedmiotów w sklepie internetowym, a dla każdego przedmiotu chcemy wypisać formularz dodawania przedmiotu do koszyka. Jedną z możliwych opcji jest zawinięcie całego listingu w jeden formularz. Jednak znacznie wygodniejszy sposób oferuje Nette\Application\UI\Multiplier.
Mnożnik pozwala na wygodne zdefiniowanie fabryki dla wielu komponentów. Działa na zasadzie zagnieżdżonych komponentów – każdy komponent dziedziczący po Nette\ComponentModel\Container może zawierać inne komponenty.
Zobacz rozdział o modelu komponentów w dokumentacji lub wykład Honzy Tvrdíka.
Istotą Multiplier jest to, że działa jako rodzic, który może dynamicznie tworzyć swoje dzieci za pomocą wywołania zwrotnego przekazanego w konstruktorze. Zobacz przykład:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}
Teraz możemy po prostu mieć formularz renderowany dla każdego elementu w szablonie – i każdy będzie naprawdę unikalnym komponentem.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Argument przekazywany w znaczniku {control}
ma format mówiący:
- zdobądź komponent
shopForm
- i uzyskać od niej dziecko
$item->id
Przy pierwszym wywołaniu punktu 1., shopForm
jeszcze nie istnieje, więc wywoływana jest jego fabryka
createComponentShopForm
Fabryka danej formy – którą jest anonimowa funkcja, którą przekazaliśmy Multiplierowi
w konstruktorze – jest następnie wywoływana na uzyskanym komponencie (instancji Multiplera).
W kolejnej iteracji foreache metoda createComponentShopForm
nie zostanie już wywołana (komponent istnieje), ale
ponieważ szukamy jego drugiego potomka ($item->id
będzie inny w każdej iteracji), funkcja anonimowa zostanie
ponownie wywołana i zwróci nowy formularz.
Pozostaje tylko zadbać o to, aby formularz faktycznie dodawał do naszego koszyka przedmioty, które posiada – obecnie
formularz jest dokładnie taki sam dla każdego przedmiotu. Cechą Multiplier (i w ogóle każdej fabryki komponentów w Nette
Framework), która nam pomaga jest to, że każda fabryka dostaje jako pierwszy argument nazwę tworzonego komponentu. W naszym
przypadku będzie to $item->id
, czyli dokładnie taka informacja, jakiej potrzebujemy. Musimy więc tylko lekko
zmodyfikować tworzenie formularza:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function ($itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Počet zboží:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Přidat do košíku');
return $form;
});
}