Multiplier: динамічні компоненти
Інструмент для динамічного створення інтерактивних компонентів
Почнемо з типового прикладу: маємо список товарів в інтернет-магазині, причому біля кожного ми хочемо вивести форму для додавання товару в кошик. Одним з можливих варіантів є обгортання всього списку в одну форму. Набагато зручніший спосіб нам пропонує Nette\Application\UI\Multiplier.
Multiplier дозволяє зручно визначити фабрику для кількох компонентів. Він працює за принципом вкладених компонентів – кожен компонент, що успадковує від Nette\ComponentModel\Container, може містити інші компоненти.
Див. розділ про модель компонентів у документації або лекцію від Honza Tvrdík.
Суть Multiplier полягає в тому, що він виступає в ролі батька, який може динамічно створювати своїх нащадків за допомогою callback-функції, переданої в конструкторі. Див. приклад:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Кількість товару:')
->setRequired();
$form->addSubmit('send', 'Додати в кошик');
return $form;
});
}
Тепер ми можемо в шаблоні просто біля кожного товару відобразити форму – і кожна буде дійсно унікальним компонентом.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
Аргумент, переданий у тезі {control}
, має формат, який говорить:
- отримай компонент
shopForm
- і з нього отримай нащадка
$item->id
При першому виклику пункту 1. shopForm
ще не існує, тому
викликається його фабрика createComponentShopForm
. На отриманому
компоненті (екземплярі Multiplier) потім викликається фабрика конкретної
форми – це анонімна функція, яку ми передали Multiplier у конструкторі.
У наступній ітерації foreach метод createComponentShopForm
вже не буде
викликаний (компонент існує), але оскільки ми шукаємо іншого його
нащадка ($item->id
буде різним у кожній ітерації), знову буде
викликана анонімна функція і поверне нам нову форму.
Єдине, що залишається, – це забезпечити, щоб форма додала в кошик
дійсно той товар, який потрібно – наразі форма біля кожного товару
абсолютно однакова. Допоможе нам властивість Multiplier (і загалом кожної
фабрики компонентів у Nette Framework), а саме те, що кожна фабрика як свій
перший аргумент отримує назву створюваного компонента. У нашому
випадку це буде $item->id
, що є саме тим даними, які нам потрібні.
Достатньо лише трохи змінити створення форми:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function ($itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Кількість товару:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Додати в кошик');
return $form;
});
}