Un formulario consiste en un conjunto de campos. Los field types identifican los tipos de campo que tenemos a nuestra disposición. Además de los field types proporcionados por Symfony podremos añadir nuestros propios tipos. En Symfony, además, un formulario puede ser definido como field type, flexibilizando enormemente la construcción de formularios complejos.
Como hemos visto en anteriores capítulos, para añadir campos a un formulario utilizamos el método add()
.
class AuthorType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('surname', 'text', array('required' => false, 'attr' => array('class' => 'surname')))
//...;
}
- El primer parámetro de
add
se refiere al atributo relacionado en la clase subyacente y es obligatorio. - El segundo parámetro indica el field type.
text
es un field type básico que se transformará en un<input type="text" />
durante el renderizado. Este atributo es opcional, y en su defecto, el componente de formularios tratará de adivinar el tipo adecuado en función del valor del atributo. - El tercer parámetro es un array opcional que permite especificar propiedades del campo. Las más comunes,
label
yrequired
, son aplicables a todos los form types.attr
permite especificar atributos que se aplicarán posteriormente a la etiqueta HTML. Cada field type puede tener otras propiedades configurables.
Vamos a crear un formulario para crear recetas. De momento el formulario va a ser muy sencillo y solo va a permitir proporcionar el nombre y la dificultad de la receta. Hemos creado un modelo Difficulties
para tener el código más organizado:
namespace My\RecipesBundle\Model;
class Difficulties
{
const UNKNOWN = 'unknown';
const EASY = 'easy';
const NORMAL = 'normal';
const HARD = 'hard';
public static function toArray()
{
return array(
self::UNKNOWN => self::UNKNOWN,
self::EASY => self::EASY,
self::NORMAL => self::NORMAL,
self::HARD => self::HARD,
);
}
}
Escribimos el formulario utilizando el field type choice
proporcionado por Symfony.
// src/My/RecipesBundle/Form/Type/RecipeType.php
class RecipeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('difficulty', 'choice', array('choices' => Difficulties::toArray()))
->add('save', 'submit');
}
// ...
}
Para aumentar la reusabilidad del código vamos a crear un form type propio para la dificultad.
// src/My/RecipesBundle/Form/Type/DifficultyType.php
namespace My\RecipesBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use My\RecipesBundle\Model\Difficulties;
class DifficultyType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'choices' => Difficulties::toArray()
));
}
public function getParent()
{
return 'choice';
}
public function getName()
{
return 'difficulty';
}
}
Y lo usaremos en el formulario de recetas.
// src/My/RecipesBundle/Form/Type/RecipeType.php
class RecipeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('difficulty', new DifficultyType)
->add('save', 'submit');
}
}
El siguiente paso para ofrecer código extensible, reusable y mantenible es exponer nuestro DifficultyType
en la capa de servicios.
# src/My/RecipesBundle/Resources/config/services.yml
services:
my_recipes.form.type.difficulty:
class: My\RecipesBundle\Form\Type\DifficultyType
tags:
- { name: form.type, alias: difficulty }
A partir de entonces el desplegable estará disponible como cualquier otro field type.
$builder
->add('difficulty', 'difficulty');