Más con Symfony

6.10. Embebiendo fácilmente formularios relacionados con Doctrine

Otra de las novedades de Symfony 1.3 es la función sfFormDoctrine::embedRelation(), que permite al programador embeber automáticamente una relación uno-a-muchos en un formulario. Imagina que además de permitir al usuario subir dos nuevas fotos, se le permite modificar cualquier objeto ProductPhoto relacionado con este producto.

El siguiente código utiliza el método embedRelation() para añadir un objeto ProductPhotoForm adicional por cada objeto ProductPhoto existente:

// lib/form/doctrine/ProductForm.class.php
public function configure()
{
  // ...

  $this->embedRelation('Photos');
}

Internamente el método sfFormDoctrine::embedRelation() hace casi lo mismo que añadimos anteriormente para embeber los dos nuevos objetos ProductPhotoForm. Si ya existen dos ProductPhoto relacionadas, los arrays widgetSchema y validatorSchema resultantes del formulario tendrían el siguiente aspecto:

widgetSchema    => array
(
  [id]          => sfWidgetFormInputHidden,
  [name]        => sfWidgetFormInputText,
  [price]       => sfWidgetFormInputText,
  [newPhotos]   => array(...)
  [Photos]      => array(
    [0]           => array(
      [id]          => sfWidgetFormInputHidden,
      [caption]     => sfWidgetFormInputText,
    ),
    [1]           => array(
      [id]          => sfWidgetFormInputHidden,
      [caption]     => sfWidgetFormInputText,
    ),
  ),
)

validatorSchema => array
(
  [id]          => sfValidatorDoctrineChoice,
  [name]        => sfValidatorString,
  [price]       => sfValidatorNumber,
  [newPhotos]   => array(...)
  [Photos]      => array(
    [0]           => array(
      [id]          => sfValidatorDoctrineChoice,
      [caption]     => sfValidatorString,
    ),
    [1]           => array(
      [id]          => sfValidatorDoctrineChoice,
      [caption]     => sfValidatorString,
    ),
  ),
)
Formulario de producto con dos fotos existentes

Figura 6.4 Formulario de producto con dos fotos existentes

El siguiente paso consiste en añadir en la vista el código necesario para mostrar los nuevos formularios de tipo Photo embebidos:

// apps/frontend/module/product/templates/_form.php
<?php foreach ($form['Photos'] as $photo): ?>
  <?php echo $photo['caption']->renderRow() ?>
  <?php echo $photo['filename']->renderRow(array('width' => 100)) ?>
<?php endforeach; ?>

El código anterior es exactamente el mismo que se utilizó anteriormente para embeber los nuevos formularios de fotos.

El último paso consiste en convertir el campo para subir archivos en un campo que permita al usuario ver la foto actual y modificarla por una nueva (sfWidgetFormInputFileEditable):

public function configure()
{
  $this->useFields(array('filename', 'caption'));

  $this->setValidator('filename', new sfValidatorFile(array(
    'mime_types' => 'web_images',
    'path' => sfConfig::get('sf_upload_dir').'/products',
    'required' => false,
  )));

  $this->setWidget('filename', new sfWidgetFormInputFileEditable(array(
    'file_src'    => '/uploads/products/'.$this->getObject()->filename,
    'edit_mode'   => !$this->isNew(),
    'is_image'    => true,
    'with_delete' => false,
  )));

  $this->validatorSchema['caption']->setOption('required', false);
}