Multiplier: Динамічні компоненти

Інструмент для динамічного створення інтерактивних компонентів.

Давайте почнемо з типової проблеми: у нас є список товарів на сайті електронної комерції, і ми хочемо супроводити кожен товар формою додати до кошика. Один зі способів – обернути весь лістинг в одну форму. Більш зручним способом є використання Nette\Application\UI\Multiplier.

Multiplier дозволяє визначити фабрику для декількох компонентів. Він заснований на принципі вкладених компонентів – кожен компонент, що успадковує від Nette\ComponentModel\Container, може містити інші компоненти.

Див. модель компонента в документації.

Multiplier являє собою батьківський компонент, який може динамічно створювати свої дочірні компоненти, використовуючи зворотний виклик, переданий у конструкторі. Див. приклад:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function () {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('amount', 'Amount:')
			->setRequired();
		$form->addSubmit('send', 'Add to cart');
		return $form;
	});
}

У шаблоні ми можемо відобразити форму для кожного товару – і кожна форма дійсно буде унікальним компонентом.

{foreach $items as $item}
	<h2>{$item->title}</h2>
	{$item->description}

	{control "shopForm-$item->id"}
{/foreach}

Аргумент, переданий у тег {control}, свідчить:

  1. отримати компонент shopForm
  2. повернути своєму нащадку $item->id

При першому виклику 1. компонент shopForm ще не існує, тому для його створення викликається метод createComponentShopForm. Потім викликається анонімна функція, передана як параметр у Multiplier, і створюється форма.

У наступних ітераціях foreach метод createComponentShopForm більше не викликається, оскільки компонент уже існує. Але оскільки ми посилаємося на іншого нащадка ($item->id варіюється між ітераціями), анонімна функція викликається знову і створюється нова форма.

Останнє, що потрібно зробити, це переконатися, що форма справді додає правильний товар до кошика, тому що в поточному стані всі форми рівні, і ми не можемо розрізнити, до яких продуктів вони належать. Для цього ми можемо використовувати властивість класу Multiplier (і взагалі будь-якого методу фабрики компонентів у фреймворку Nette), що кожен метод фабрики компонентів отримує ім'я створеного компонента як перший аргумент. У нашому випадку це буде $item->id, що саме те, що нам потрібно, щоб розрізняти окремі товари. Все, що вам потрібно зробити, це змінити код для створення форми:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('amount', 'Количество:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Добавить в корзину');
		return $form;
	});
}
версію: 4.0