Multiplier: componenti dinamici

Strumento per la creazione dinamica di componenti interattivi

Partiamo da un esempio tipico: abbiamo un elenco di prodotti in un e-shop, e per ognuno vogliamo visualizzare un form per aggiungere il prodotto al carrello. Una delle possibili varianti è racchiudere l'intero elenco in un unico form. Tuttavia, un modo molto più comodo ci viene offerto da Nette\Application\UI\Multiplier.

Multiplier consente di definire comodamente una piccola factory per più componenti. Funziona sul principio dei componenti nidificati – ogni componente che eredita da Nette\ComponentModel\Container può contenere altri componenti.

Vedi il capitolo sul modello a componenti nella documentazione o la presentazione di Honza Tvrdík.

L'essenza di Multiplier è che agisce come genitore, che può creare dinamicamente i propri figli tramite un callback passato nel costruttore. Vedi l'esempio:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function () {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantità:')
			->setRequired();
		$form->addSubmit('send', 'Aggiungi al carrello');
		return $form;
	});
}

Ora possiamo semplicemente far renderizzare un form per ogni prodotto nel template – e ognuno sarà effettivamente un componente unico.

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

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

L'argomento passato nel tag {control} è nel formato che dice:

  1. ottieni il componente shopForm
  2. e da esso ottieni il figlio $item->id

Alla prima chiamata del punto 1. shopForm non esiste ancora, quindi viene chiamata la sua factory createComponentShopForm. Sul componente ottenuto (istanza di Multiplier) viene poi chiamata la factory del form specifico – che è la funzione anonima che abbiamo passato a Multiplier nel costruttore.

Nella successiva iterazione del foreach, il metodo createComponentShopForm non verrà più chiamato (il componente esiste), ma poiché stiamo cercando un suo figlio diverso ($item->id sarà diverso in ogni iterazione), la funzione anonima verrà chiamata di nuovo e ci restituirà un nuovo form.

L'unica cosa che resta da fare è assicurarsi che il form aggiunga al carrello effettivamente il prodotto che deve – attualmente il form è completamente identico per ogni prodotto. Ci aiuta una proprietà di Multiplier (e in generale di ogni factory di componente in Nette Framework), ovvero che ogni factory riceve come primo argomento il nome del componente creato. Nel nostro caso sarà $item->id, che è esattamente l'informazione di cui abbiamo bisogno. Basta quindi modificare leggermente la creazione del form:

protected function createComponentShopForm(): Multiplier
{
	return new Multiplier(function ($itemId) {
		$form = new Nette\Application\UI\Form;
		$form->addInteger('count', 'Quantità:')
			->setRequired();
		$form->addHidden('itemId', $itemId);
		$form->addSubmit('send', 'Aggiungi al carrello');
		return $form;
	});
}
versione: 4.0