Forms!
1
Monday, October 14, 13
Symfony Forms
•

Tipos de formularios

2
Monday, October 14, 13
Symfony Forms
•
•

Tipos de formularios
Formatos de datos

3
Monday, October 14, 13
Symfony Forms
•
•
•

Tipos de formularios
Formatos de datos
Creación

4
Monday, October 14, 13
Symfony Forms
•
•
•
•

Tipos de formularios
Formatos de datos
Creación
Renderizado

5
Monday, October 14, 13
Symfony Forms
•
•
•
•
•

Tipos de formularios
Formatos de datos
Creación
Renderizado
Submit

6
Monday, October 14, 13
Symfony Forms
•
•
•
•
•
•

Tipos de formularios
Formatos de datos
Creación
Renderizado
Submit
Eventos

7
Monday, October 14, 13
Objetivo

http://www.flickr.com/photos/edgarjediza/2404477249/
Monday, October 14, 13
Y no...

http://fun.mee.is/wp-content/uploads/funny-sleep-positon-01.jpg
Monday, October 14, 13
Tipos de formularios

10
Monday, October 14, 13
Tipos de formularios
•

Describen el elemento a mostrar

11
Monday, October 14, 13
Tipos de formularios
•
•

Describen el elemento a mostrar
Existen solamente una vez en la aplicación

12
Monday, October 14, 13
Tipos de formularios
•
•
•

Describen el elemento a mostrar
Existen solamente una vez en la aplicación
Existe un tipo base: form

13
Monday, October 14, 13
Tipos de formularios
•
•
•
•

Describen el elemento a mostrar
Existen solamente una vez en la aplicación
Existe un tipo base: form
Se pueden heredar

14
Monday, October 14, 13
Tipos de formularios
•
•
•
•
•

Describen el elemento a mostrar
Existen solamente una vez en la aplicación
Existe un tipo base: form
Se pueden heredar
Inyectar dependencias si y solo si son comunes a todas las
instancias

15
Monday, October 14, 13
Tipos de formularios
•
•
•
•
•

Describen el elemento a mostrar

•

Symfony incorpora muchos campos built-in

Existen solamente una vez en la aplicación
Existe un tipo base: form
Se pueden heredar
Inyectar dependencias si y solo si son comunes a todas las
instancias

16
Monday, October 14, 13
Tipos de formularios
Grupos de campos

Campos texto
text

textarea

integer

money

number

password

percent

collection

email
search

Campos button
button

url

checkbox
datetime

time

choice

entity

country

language

locale

timezone

hidden

birthday
Campos choice

currency
17
Monday, October 14, 13

reset

submit

file

radio

Otros campos

Campos date & time
date

repeated
Tipos de formularios
Tipos de formularios propios
<?php
namespace IsmaAmbrosiMyBundleForm;
use SymfonyComponentFormAbstractType;
class MyFormType extends AbstractType
{
    public function getName()
    {
        return 'my_form';
    }
}

18
Monday, October 14, 13
Tipos de formularios
Tipos de formularios propios
<?php
namespace IsmaAmbrosiMyBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
class MyFormType extends AbstractType
{
    /**
     * Construye el formulario
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        # Agrega un campo text para ingresar el nombre
        $builder->add('name', 'text');
    }
    public function getName(){...}
}

Monday, October 14, 13
Tipos de formularios
Tipos de formularios propios asociados a una entidad
<?php
namespace IsmaAmbrosiMyBundleForm;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class MyFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
        $builder->add('last_name');
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array('data_class' => 'IsmaAmbrosiMyBundleEntityUser'));
    }
    public function getName(){...}
}

Monday, October 14, 13
Tipos de formularios
Tipos de formularios propios asociados a una entidad
<?php

<?php

namespace IsmaAmbrosiMyBundleForm;

namespace IsmaAmbrosiMyBundleEntity;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

use DoctrineORMMapping as ORM;

/**
class MyFormType extends AbstractType
 * @ORMEntity
{
 */
    public function buildForm(FormBuilderInterface $builder, array $options)
class User
    {
{
        $builder->add('name');
    /**
        $builder->add('last_name');
    }
     * @ORMColumn(type="string", length=100)
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    private $name;
    {
        $resolver->setDefaults(array('data_class' => 'IsmaAmbrosiMyBundleEntityUser'));
    /**
    }
    public function getName(){...}
}

Monday, October 14, 13

     * @ORMColumn(type="string", length=100)
     */
    private $lastName;
}
Tipos de formularios
Tipos de formularios propios

¡Se pueden crear como servicios!

Monday, October 14, 13
Tipos de formularios
Tipos de formularios propios como servicios

•

Monday, October 14, 13

Puedo inyectar dependencias
Tipos de formularios
Tipos de formularios propios como servicios

•
•

Monday, October 14, 13

Puedo inyectar dependencias
Puedo configurar un logger exclusivo
Tipos de formularios
Tipos de formularios propios como servicios

•
•
•

Monday, October 14, 13

Puedo inyectar dependencias
Puedo configurar un logger exclusivo
Puedo testear mi aplicacion sin depender de ellos
Tipos de formularios
Tipos de formularios propios como servicios

•
•
•
•

Monday, October 14, 13

Puedo inyectar dependencias
Puedo configurar un logger exclusivo
Puedo testear mi aplicacion sin depender de ellos
Y más...
Instancias de Formularios
•
•
•

Existen una o más veces en la aplicación
Los datos pueden cambiar luego de su creación
Son creados a partir del tipo de formulario

27
Monday, October 14, 13
Formatos de datos

28
Monday, October 14, 13
Formatos de datos

• Formato del modelo (model format)
• Formato de la vista (view format)
• Formato normalizado (normalized format)
29
Monday, October 14, 13
Formatos de datos
Model format

Formato que existe en nuestro modelo.
Ej: Tal cual querémos que sea persistido por nuestro ORM

30
Monday, October 14, 13
Formatos de datos
View format

Tal cual va a ser mostrado al usuario en los elementos de nuestra vista.

Ej: Un objeto DateTime se transforma en un array("year" => 2013, "month" => 10, "day" => 12)

31
Monday, October 14, 13
Formatos de datos
Normalized format

Formato intermedio entre la vista y el modelo.

Se recomienda que este formato guarde cuanta información sea posible.

32
Monday, October 14, 13
Formatos de datos
Al crear el formulario

Model data

Normalized
data

33
Monday, October 14, 13

View data
Formatos de datos
Al crear el formulario

Model data

Normalized
data

34
Monday, October 14, 13

View data
Formatos de datos
Submit

Model data

Normalized
data

35
Monday, October 14, 13

View data
Formatos de datos
Submit

new User

Model data

Normalized
data

36
Monday, October 14, 13

View data

$_POST
Creación

37
Monday, October 14, 13
Creación
<?php
namespace IsmaAmbrosiMyBundleController;
use IsmaAmbrosiMyBundleFormMyFormType;
use SymfonyBundleFrameworkBundleControllerController;
class DefaultController extends Controller
{
    public function indexAction()
    {
        $form = $this->createForm(new MyFormType(), $data, $options);
        # MyFormType definido como servicio
        $form = $this->createForm('my_form_type', $data, $options);
    }
}

38
Monday, October 14, 13
Creación
public function indexAction()
{
    $form = $this->createForm(new MyFormType(), $data, $options);
    # MyFormType definido como servicio
    $form = $this->createForm('my_form_type', $data, $options);
}

public function indexAction()
{
    $form = $this->get('form.factory')->create(new MyFormType(), $data, $options);
    # MyFormType definido como servicio
    $form = $this->get('form.factory')->create('my_form_type', $data, $options);
}

39
Monday, October 14, 13
Renderizado

40
Monday, October 14, 13
Renderizado
Creamos la vista del formulario para enviarla al template
<?php
namespace IsmaAmbrosiMyBundleController;
use IsmaAmbrosiMyBundleFormMyFormType;
use SymfonyBundleFrameworkBundleControllerController;
class DefaultController extends Controller
{
    public function indexAction()
    {
        $form = $this->createForm(new MyFormType(), $data, $options);
        return $this->render('IsmaAmbrosiMyBundle:Default:index.html.twig', array(
            'form' => $form->createView()
        ));
    }
}
41
Monday, October 14, 13
Renderizado
Mostrando el formulario dentro de un tag form
<form action="/post" method="post">
{{ form_widget(form) }}
<button type="submit">Submit</button>
</form>

42
Monday, October 14, 13
Renderizado
Mostrando cada elemento del formulario
<form action="/post" method="post">
{{ form_row(form.name) }}
{{ form_row(form.last_name) }}
{{ form_rest(form) }}
<button type="submit">Submit</button>
</form>

43
Monday, October 14, 13
Renderizado
Mostrando cada elemento del formulario
<form action="/post" method="post">
{{ form_row(form.name) }}
{{ form_row(form.last_name) }}
{{ form_rest(form) }}
<button type="submit">Submit</button>
</form>

44
Monday, October 14, 13

Muestra los elementos
restantes
Renderizado
Utilizando las funciones de Symfony
{{ form_start(form) }}
{{ form_errors(form) }}
<div>
{{ form_label(form.name) }}
{{ form_errors(form.name) }}
{{ form_widget(form.name) }}
</div>
<div>
{{ form_label(form.last_name) }}
{{ form_errors(form.last_name) }}
{{ form_widget(form.last_name) }}
</div>
<button type="submit">Submit</button>
{{ form_end(form) }}

45
Monday, October 14, 13
Renderizado
Utilizando las funciones de Symfony
{{ form_start(form) }}
{{ form_errors(form) }}
public function indexAction()
<div>
{
{{ form_label(form.name) }}
    $form = $this->createForm(new MyFormType(), $data, array(
{{ form_errors(form.name) }}
        'action' => '/post', # URL donde el formulario va a ser enviado
{{ form_widget(form.name) }}
        'method' => 'POST' # PUT, DELETE, PATCH, GET
</div>
    ));
<div>
    return $this->render('IsmaAmbrosiMyBundle:Default:index.html.twig', array(
{{ form_label(form.last_name) }}
'form' => $form->createView()
{{ form_errors(form.last_name) }}
));
{{ form_widget(form.last_name) }}
}
</div>
<button type="submit">Submit</button>
{{ form_end(form) }}

46
Monday, October 14, 13
Renderizado
Utilizando templates php
<form action="/post" method="post">
<?php echo $view['form']->row($form['name']) ?>
    <?php echo $view['form']->row($form['last_name']) ?>
<button type="submit">Submit</button>
</form>

47
Monday, October 14, 13
Submit

48
Monday, October 14, 13
Submit
Submit

49
Monday, October 14, 13
Submit
Submit

Bind

50
Monday, October 14, 13
Submit
Submit

Bind

Validación

51
Monday, October 14, 13
Submit
Éxito

Submit

Bind

Validación

Error

52
Monday, October 14, 13
Submit
Éxito

Submit

Bind

Validación

Persistencia del modelo
Mensaje de éxito
Status 2xx

Error
Mensaje de error
Status 400
53
Monday, October 14, 13
Submit
¿Código?

54
Monday, October 14, 13
Submit
    public function postAction(Request $request)
    {
        $form = $this->createForm(new MyFormType(), $data, $options);
        $form->handleRequest($request);
        if (!$form->isValid()) {
            throw new BadRequestHttpException('Error');
        }
        # Persistir entidades
        # Mensajes
        # etc.
        return new Response('Success');
    }

55
Monday, October 14, 13
Submit
submit
bind

error

    public function postAction(Request $request)
    {
        $form = $this->createForm(new MyFormType(), $data, $options);
        $form->handleRequest($request);
        if (!$form->isValid()) {
            throw new BadRequestHttpException('Error');
        }
        # Persistir entidades
        # Mensajes
        # etc.

éxito

        return new Response('Success');
    }

56
Monday, October 14, 13

validación
Submit
public function postAction(Request $request)
{
    $form = $this->createForm(new MyFormType());
    $form->handleRequest($request);
    if (!$form->isValid()) {
        $this->render('IsmaAmbrosiMyBundle:Default:index.html.twig', array(
            'form' => $form->createView()
        ));
    }
    $manager = $this->getDoctrine()->getManager();
    $manager->persist($form->getData());
    $manager->flush();
    return $this->redirect('/');
}

57
Monday, October 14, 13
Submit
Internamente crea
public function postAction(Request $request)
la instancia de User
{
    $form = $this->createForm(new MyFormType());
    $form->handleRequest($request);
    if (!$form->isValid()) {
        $this->render('IsmaAmbrosiMyBundle:Default:index.html.twig', array(
            'form' => $form->createView()
        ));
    }
    $manager = $this->getDoctrine()->getManager();
    $manager->persist($form->getData());
    $manager->flush();
    return $this->redirect('/');
}

58
Monday, October 14, 13

Obtiene la entidad
Eventos

59
Monday, October 14, 13
Eventos
•
•

Permiten construir el formulario basandose en los datos

•

Permiten configurar el modelo en base a los datos recibidos

Permiten construir el formulario basandose en el estado de la
aplicación

60
Monday, October 14, 13
Eventos
Eventos lanzados por el EventDispatcher

•
•
•
•
•

PRE_SET_DATA (form.pre_set_data)
POST_SET_DATA (form.post_set_data)
PRE_SUBMIT (form.submit)
SUBMIT (form.bind)
POST_SUBMIT (form.post_bind)

61
Monday, October 14, 13
Eventos
PRE_SET_DATA

•

Permite modificar los datos asignados al formulario desde
nuestro modelo.

•
•

Permite modificar el formulario en base a los datos del modelo
Permite modificar el formulario en base al estado de mi
aplicación

62
Monday, October 14, 13
Eventos
PRE_BIND

Nos permite acceder y modificar los datos tal cual
fueron enviados por el navegador en el submit.

63
Monday, October 14, 13
Eventos
BIND

Nos permite modificar los datos en su estado
normalizado.

64
Monday, October 14, 13
Eventos
POST_BIND

Nos permite acceder a los datos de la vista y modificar
los datos que ya fueron asignados al modelo.

65
Monday, October 14, 13
Eventos
Al crear el formulario

Model data

Normalized
data

POST_SET_DATA

PRE_SET_DATA

66
Monday, October 14, 13

View data
Eventos
Submit

Model data

POST_BIND

Normalized
data

BIND

67
Monday, October 14, 13

View data

PRE_BIND
Resumen

68
Monday, October 14, 13
Resumen
Vista
1. Creamos el formulario basado en un tipo
2. Creamos la vista para ese formulario
3. Mostramos el template

69
Monday, October 14, 13
Resumen
Submit
1. Creamos el formulario basado en un tipo
2. Enlazamos el $request
3. Validamos
1. Error
1. Mostramos el formulario indicando errores
2. Retornamos STATUS 400
2. Éxito
1. Persistimos entidades
2. Mensaje de éxito (Ej: Redirección a un listado)

70
Monday, October 14, 13
¿Preguntas?

71
Monday, October 14, 13
¡Gracias!

72
Monday, October 14, 13

Symfony forms