Multiplier: componentes dinámicos
Herramienta para la creación dinámica de componentes interactivos
Partamos de un ejemplo típico: tenemos una lista de productos en una tienda online, y para cada uno queremos mostrar un formulario para añadir el producto al carrito. Una de las posibles variantes es envolver todo el listado en un único formulario. Sin embargo, un método mucho más cómodo nos lo ofrece Nette\Application\UI\Multiplier.
Multiplier permite definir cómodamente una pequeña fábrica para múltiples componentes. Funciona según el principio de componentes anidados: cada componente que hereda de Nette\ComponentModel\Container puede contener otros componentes.
Vea el capítulo sobre el modelo de componentes en la documentación o la charla de Honza Tvrdík.
La esencia de Multiplier es que actúa como un padre que puede crear dinámicamente sus hijos mediante un callback pasado en el constructor. Vea el ejemplo:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function () {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Cantidad de productos:')
->setRequired();
$form->addSubmit('send', 'Añadir al carrito');
return $form;
});
}
Ahora podemos simplemente, en la plantilla, renderizar un formulario para cada producto, y cada uno será realmente un componente único.
{foreach $items as $item}
<h2>{$item->title}</h2>
{$item->description}
{control "shopForm-$item->id"}
{/foreach}
El argumento pasado en la etiqueta {control}
tiene un formato que indica:
- obtén el componente
shopForm
- y de él obtén el hijo
$item->id
En la primera llamada al punto 1., shopForm
aún no existe, por lo que se llama a su fábrica
createComponentShopForm
. Sobre el componente obtenido (instancia de Multiplier) se llama entonces a la fábrica del
formulario específico, que es la función anónima que pasamos a Multiplier en el constructor.
En la siguiente iteración del foreach
, el método createComponentShopForm
ya no será llamado (el
componente existe), pero como buscamos a su otro hijo ($item->id
será diferente en cada iteración), se volverá
a llamar a la función anónima y nos devolverá un nuevo formulario.
Lo único que queda es asegurar que el formulario añada al carrito realmente el producto que debe; actualmente, el formulario
es completamente idéntico para cada producto. Nos ayudará una propiedad de Multiplier (y en general de cada fábrica de
componentes en Nette Framework), y es que cada fábrica recibe como primer argumento el nombre del componente que se está
creando. En nuestro caso, será $item->id
, que es exactamente el dato que necesitamos. Basta con modificar
ligeramente la creación del formulario:
protected function createComponentShopForm(): Multiplier
{
return new Multiplier(function ($itemId) {
$form = new Nette\Application\UI\Form;
$form->addInteger('count', 'Cantidad de productos:')
->setRequired();
$form->addHidden('itemId', $itemId);
$form->addSubmit('send', 'Añadir al carrito');
return $form;
});
}