válido para Symfony 1.3 y 1.4
En esencia, un formulario web es una colección de campos que se muestran y se
vuelven a enviar al servidor. Igualmente, el objeto sfForm es básicamente
un array de campos de formulario. sfForm gestiona el proceso completo,
pero los campos individuales son los responsables de mostrarse y validarse.
En Symfony, cada campo de formulario se define mediante dos objetos diferentes:
Un widget que muestra el código XHTML del campo de formulario
Un validador que limpia y valida los datos enviados en ese campo
En Symfony, un widget se define como cualquier objeto cuya única tarea consiste en generar código XHTML. Aunque normalmente se utilizan en los formularios, se puede crear un objeto de tipo widget para generar cualquier tipo de código.
Recuerda que un objeto sfForm es básicamente un array de campos de
formulario. De forma más precisa, sfForm incluye un array de widgets y un
array de validadores para todos los campos del formularios. Estos dos arrays,
llamados widgetSchema y validatorSchema son propiedades de la clase sfForm.
Para añadir un nuevo campo al formulario, simplemente se añade el widget del
campo en el array widgetSchema y el validador del campo en el array
validatorSchema. El siguiente código por ejemplo añade un campo email en
el formulario:
public function configure() { $this->widgetSchema['email'] = new sfWidgetFormInputText(); $this->validatorSchema['email'] = new sfValidatorEmail(); }
Los arrays widgetSchema y validatorSchema en realidad son clases llamadas
sfWidgetFormSchema y sfValidatorSchema que implementan la interfaz
ArrayAccess.
Como la clase ProductForm hereda de sfForm, también incluye todos sus
widgets y validadores en los arrays widgetSchema y validatorSchema. A
continuación se muestra cómo se organiza cada array en el objeto ProductForm
final.
widgetSchema => array ( [id] => sfWidgetFormInputHidden, [name] => sfWidgetFormInputText, [price] => sfWidgetFormInputText, [newPhotos] => array( [0] => array( [id] => sfWidgetFormInputHidden, [filename] => sfWidgetFormInputFile, [caption] => sfWidgetFormInputText, ), [1] => array( [id] => sfWidgetFormInputHidden, [filename] => sfWidgetFormInputFile, [caption] => sfWidgetFormInputText, ), ), ) validatorSchema => array ( [id] => sfValidatorDoctrineChoice, [name] => sfValidatorString, [price] => sfValidatorNumber, [newPhotos] => array( [0] => array( [id] => sfValidatorDoctrineChoice, [filename] => sfValidatorFile, [caption] => sfValidatorString, ), [1] => array( [id] => sfValidatorDoctrineChoice, [filename] => sfValidatorFile, [caption] => sfValidatorString, ), ), )
Al igual que widgetSchema y validatorSchema son realmente objetos que se
comportan como arrays, los arrays anteriores definidos mediante las claves
newPhotos, 0 y 1 son objetos sfWidgetSchema y sfValidatorSchema.
Como era de esperar, los campos básicos (id, name y price) se representan
en el primer nivel de cada array. En los formularios que no embeben otros
formularios, tanto widgetSchema como validatorSchema solamente tienen un
nivel, que representa los campos básicos del formulario. Los widgets y validadores
de cualquier formulario embebido se representan como subarrays de widgetSchema
y validatorSchema. A continuación se explica el método que se encarga de este
proceso.
Como un formulario está compuesto por un array de widgets y otro de validadores,
embeber un formulario en otro consiste fundamentalmente en añadir los arrays de
widgets y validadores de un formulario dentro de los arrays de widgets y
validadores del formulario principal. Este proceso lo realiza completamente el
método sfForm::embedForm(). El resultado siempre es la creación de unos arrays
widgetSchema y validatorSchema multidimensionales, tal y como se mostró
anteriormente.
A continuación se explica la configuración de ProductPhotoCollectionForm, que
asocia objetos ProductPhotoForm individuales consigo mismo. Este formulario
intermedio actúa como un formulario contenedor y facilita la organización de
todos los formularios. En primer lugar, veamos el siguiente código extraído de
ProductPhotoCollectionForm::configure():
$form = new ProductPhotoForm($productPhoto); $this->embedForm($i, $form);
El propio formulario ProductPhotoCollectionForm comienza como un nuevo objeto
de tipo sfForm. Por tanto, sus arrays widgetSchema y validatorSchema están
vacíos.
widgetSchema => array() validatorSchema => array()
Por su parte, cada formulario ProductPhotoForm ya contiene tres campos
(id, filename y caption) y sus correspondientes tres elementos en los
arrays widgetSchema y validatorSchema.
widgetSchema => array ( [id] => sfWidgetFormInputHidden, [filename] => sfWidgetFormInputFile, [caption] => sfWidgetFormInputText, ) validatorSchema => array ( [id] => sfValidatorDoctrineChoice, [filename] => sfValidatorFile, [caption] => sfValidatorString, )
El método sfForm::embedForm() simplemente añade los arrays widgetSchema
y validatorSchema de cada ProductPhotoForm dentro de los arrays widgetSchema
y validatorSchema del objeto ProductPhotoCollectionForm vacío.
Al finalizar, los arrays widgetSchema y validatorSchema del formulario
contenedor (ProductPhotoCollectionForm) son arrays multidimensionales que
contienen los widgets y validadores de los dos formularios ProductPhotoForm.
widgetSchema => array ( [0] => array ( [id] => sfWidgetFormInputHidden, [filename] => sfWidgetFormInputFile, [caption] => sfWidgetFormInputText, ), [1] => array ( [id] => sfWidgetFormInputHidden, [filename] => sfWidgetFormInputFile, [caption] => sfWidgetFormInputText, ), ) validatorSchema => array ( [0] => array ( [id] => sfValidatorDoctrineChoice, [filename] => sfValidatorFile, [caption] => sfValidatorString, ), [1] => array ( [id] => sfValidatorDoctrineChoice, [filename] => sfValidatorFile, [caption] => sfValidatorString, ), )
En el último paso de este proceso, el formulario contenedor resultante
(ProductPhotoCollectionForm) se embebe directamente en ProductForm. Esto
se realiza dentro del método ProductForm::configure(), que aprovecha todo el
trabajo realizado dentro de ProductPhotoCollectionForm:
$form = new ProductPhotoCollectionForm(null, array( 'product' => $this->getObject(), 'size' => 2, )); $this->embedForm('newPhotos', $form);
El código anterior produce la estructura definitiva de los arrays widgetSchema
y validatorSchema que se mostró anteriormente. En realidad, el método embedForm()
es similar a combinar manualmente los arrays widgetSchema y validatorSchema:
$this->widgetSchema['newPhotos'] = $form->getWidgetSchema(); $this->validatorSchema['newPhotos'] = $form->getValidatorSchema();
válido para Symfony 1.3 y 1.4