/
multiplier.texy
61 lines (46 loc) · 4.53 KB
/
multiplier.texy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Multiplier: Динамические компоненты
***********************************
Инструмент для динамического создания интерактивных компонентов.
Давайте начнем с типичной проблемы: у нас есть список товаров на сайте электронной коммерции, и мы хотим сопроводить каждый товар формой *добавить в корзину*. Один из способов — обернуть весь листинг в одну форму. Более удобным способом является использование [api:Nette\Application\UI\Multiplier].
Multiplier позволяет определить фабрику для нескольких компонентов. Он основан на принципе вложенных компонентов — каждый компонент, наследующий от [api:Nette\ComponentModel\Container], может содержать другие компоненты.
См. [модель компонента|components#Components in Depth] в документации.
Multiplier представляет собой родительский компонент, который может динамически создавать свои дочерние компоненты, используя обратный вызов, переданный в конструкторе. См. пример:
```php
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;
});
}
```
В шаблоне мы можем отобразить форму для каждого товара — и каждая форма действительно будет уникальным компонентом.
```latte
{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`, что именно то, что нам нужно, чтобы различать отдельные товары. Всё, что вам нужно сделать, это изменить код для создания формы:
```php
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;
});
}
```