msgbartop
Desarrollador Web, Android y iOS
msgbarbottom

Añadir el atributo placeholder de html5 en un formulario de Twig y Symfony2

La llegada de HTML5 ha puesto a nuestra disposición nuevos elementos y atributos para añadir en nuestras webs. Uno de ellos es el placeholder que, para resumirlo, es el texto que aparece dentro de un campo de texto antes de que escribamos algo. Es muy útil para indicar al usuario que es lo que queremos que introduzca en ese campo. Es algo parecido a los labels, pero dentro del propio input.

Puntualizar que la W3C recomienda siempre utilizar labels junto a los inputs y que el placeholder no reemplaza al label.

¿Cómo añadir el atributo placeholder a un formulario de Twig en Symfony2?

Vamos a partir de un formulario sencillo:

<form action="" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form.username) }}
</form>

Si queremos añadir el atributo placeholder lo haremos de la siguiente manera:

<form action="" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form.username, { 'attr': {'placeholder': 'Escribe tu nombre de usuario' } }) }}
</form>

Si además queremos que el placeholder sea traducible, solo deberemos utilizar el filtro trans de Twig:

<form action="" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form.username, { 'attr': {'placeholder': 'Escribe tu nombre de usuario' | trans } }) }}
</form>

Etiquetas: , , , , , , ,

Desplegable con una relación entre entities en un formulario de Symfony2

En las entidades de Symfony2 es sencillo relacionar un campo con otra tabla con una relación ManyToOne y que este campo solo pueda tomar un valor que esté disponible en la segunda entity. Si creamos un formulario para poder introducir nuevos registros en la base de datos, necesitamos un campo del tipo select para seleccionar uno de los datos de la segunda tabla y relacionarlos.

Deberemos modificar el formulario y añadirle un par de opciones más. En este ejemplo, vamos a relacionar un usuario con su país.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace Acme\MiBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
 
class PerfilType extends AbstractType {
 
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('pais', 'entity',
            array(
                'class' => 'AcmeMiBundle:Pais'
                'label' => 'Pais',
            )
        );
    }
}

Que no se nos olvide añadir el método __toString() a la entity Pais:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace Acme\MiBundle\Entity;
 
use Doctrine\ORM\Mapping as ORM;
 
class Pais
{
 
    [...]
 
    public function __toString()
    {
        return $this->getNombre();
    }
}

Y así de sencillo, ahora en nuestra plantilla aparecerá automáticamente el campo de tipo select a la hora de seleccionar el país del usuario.

Etiquetas: , , , ,

Symfony2: Añadir a un formulario un campo que no está definido en el modelo

He estado desarrollando mi propio bundle para el registro de usuarios en Symfony2 y me he encontrado con el problema de querer añadir campos al formulario de registro que no he definido en el modelo. Uno de estos campos es un checkbox para aceptar los términos de uso de la aplicación. No me interesa guardar este campo en la base de datos por lo que no está definido en el modelo.

Así es como lo he hecho:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class RegisterFormType extends AbstractType
{
 
    public function buildForm(FormBuilder $builder, array $options)
    {
 
        $builder
            ->add('email', 'email')
            ->add('password', 'repeated', array(
                'type' => 'password',
                'invalid_message' => 'Las dos contraseñas deben coincidir',
                'options' => array('label' => 'Contraseña'),
                'required' => false))
	    ->add("accept_tos",
                "checkbox", array(
                    "property_path" => false,
                )
            );
 
 
        $builder
            ->addValidator(new CallbackValidator(function(FormInterface $form){
 
                if (!$form["accept_tos"]->getData())
                {
                    $form->addError(new FormError('Debes aceptar los términos de uso'));
                }
            })
        );
    }
 
}

Como vemos, añadimos un campo checkbox con nombre “accept_tos” y le indicamos la opción “property_path” a false, por lo que no validará este campo con el modelo. Eso sí, debemos añadir un validador para este campo para asegurarnos de que el usuario acepta las condiciones de uso.

Fuente: http://www.richsage.co.uk/2011/07/20/adding-non-entity-fields-to-your-symfony2-forms/

Etiquetas: , , , , , ,

Formulario de registro básico en Symfony 1.4

Es dificil no desarrollar una web sin tener registro de usuarios. Para Symfony 1.4 podemos encontrar gran cantidad de plugins que se encargan de esta función como pueden ser sfGuardPlugin (para Propel) y sfDoctrineGuardPlugin (para Doctrine). Estos plugins son muy completos y útiles, pudiéndolos usar en cualquiera de nuestros proyectos donde necesitemos las operaciones básicas con usuarios (registro, login, etc).

Para este post, la intención es crear un formulario de registro de usuarios sencillo desde cero para Symfony 1.4, sin la complejidad de un plugin ya que muchas veces tienen funcionalidades que no necesitaremos en nuestro proyecto.

Antes de empezar, evidentemente, crearemos un proyecto nuevo y generamos un modulo llamado “user”.

Primero modificamos el archivo schema.yml, añadiendo una tabla user básica y sencilla.

/config/doctrine/schema.yml

1
2
3
4
5
6
7
8
9
User:
  tableName: user
  actAs:
    Timestampable: ~
  columns:
    email:
      type: string(255)
    password:
      type: string(45)

Indicamos que se comporte como Timestampable para que se creen automáticamente los campos created_at y updated_at. No nos olvidemos generar las consultas sql y ejecutarlas en nuestra base de datos.

En el segundo paso, vamos a crear el formulario para el registro del usuario. Creamos un archivo nuevo en /lib/form/ llamado RegisterForm.class.php

/lib/form/RegisterForm.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
class RegisterForm extends BaseForm
{
    public function configure()
    {
        parent::configure();
 
        $this->setWidgets(array(
	    'email'     => new sfWidgetFormInput(),
	    'password'  => new sfWidgetFormInputPassword(),
            'password2' => new sfWidgetFormInputPassword(),
	));
 
	$this->setValidators(array(
            'email'        => new sfValidatorEmail(array('required'=>true), array('required'=> "El email es obligatorio")),
            'password'  => new sfValidatorString(array('required'=>true), array('required'=> "La contraseña es obligatoria")),
            'password2' => new sfValidatorString(array('required'=>true), array('required'=> "La contraseña es obligatoria")),
	));
 
	$this->widgetSchema->setNameFormat('register[%s]');
        $this->widgetSchema->setFormFormatterName('list');
 
        $this->validatorSchema->setPostValidator(new sfValidatorAnd(array(
            new sfValidatorSchemaCompare('password2', sfValidatorSchemaCompare::EQUAL, 'password', array('throw_global_error' => true), array('invalid' => "Las dos contraseñas no coinciden")),
            new sfValidatorDoctrineUnique(array('model' => 'User', 'column' => array('email')), array('invalid'=> "Este email ya está en uso"))
        )));
    }
}

Los formularios pueden darnos muchos quebraderos de cabeza al principio ya que es algo dificil de entender a la primera, por lo que voy a explicarlo un poco más en detalle.

1
2
3
4
5
$this->setWidgets(array(
    'email'     => new sfWidgetFormInput(),
    'password'  => new sfWidgetFormInputPassword(),
    'password2' => new sfWidgetFormInputPassword(),
));

Indicamos que para el campo email queremos un input normal. Como se puede apreciar, le decimos que para los campos contraseña queremos un campo input password.

1
2
3
4
5
$this->setValidators(array(
    'email'        => new sfValidatorEmail(array('required'=>true), array('required'=> "El email es obligatorio")),
    'password'  => new sfValidatorString(array('required'=>true), array('required'=> "La contraseña es obligatoria")),
    'password2' => new sfValidatorString(array('required'=>true), array('required'=> "La contraseña es obligatoria")),
));

Ahora los validadores. El campo email, evidentemente, debe ser un email. El validador sfValidatorEmail se encarga de comprobar que sea un formato de email válido.
Los campos password son obligatorios y no pueden estar vacíos. Podríamos decirle que tienen que tener una longitud mínima y máxima con las opciones max_length y min_length.

1
2
3
4
$this->validatorSchema->setPostValidator(new sfValidatorAnd(array(
    new sfValidatorSchemaCompare('password2', sfValidatorSchemaCompare::EQUAL, 'password', array('throw_global_error' => true), array('invalid' => "Las dos contraseñas no coinciden")),
    new sfValidatorDoctrineUnique(array('model' => 'User', 'column' => array('email')), array('invalid'=> "Este email ya está en uso"))
)));

Vamos a añadir unos validadores un poco más complejos. En el primero, comprobamos que los dos campos de contraseña deben ser iguales. Para ello utilizamos el validador sfValidatorSchemaCompare. Es típico hacer esta comprobación en todos los formularios de registro de usuarios.
En el segundo caso, comprobamos que el email introducido por el usuario no esté ya introducido en la base de datos y, por tanto, en uso por otro usuario. Utilizamos el validador sfValidatorDoctrineUnique.

Ya tenemos el formulario preparado para su uso. Editamos el archivo actions.class.php de nuestro módulo “user” y añadimos la acción “Register”:

/apps/frontend/modules/user/actions/actions.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
class userActions extends sfActions
{
  public function executeRegister(sfWebRequest $request)
  {
 
    $this->redirectIf($this->getUser()->isAuthenticated(), "@homepage");
 
    $this->form = new RegisterForm();
 
    if($request->isMethod("post")){
 
       $this->form->bind($request->getParameter("register"));
       if($this->form->isValid()){
 
           $user = new User();
           $user->email = $this->form->getValue("email");
           $user->password = md5($this->form->getValue("password")); // podriamos utilizar otro sistema para encriptar la contraseña
           $user->save();
 
           $url = $this->getUser()->getAttribute("referer",false)?:"@homepage";
           $this->getUser()->setAttribute("referer",false);
           $this->redirect($url);
       }
    }
  }
}

En la línea 7 le indicamos que si el usuario ya está logueado le redirija a la homepage.

Hemos utilizado el algoritmo md5 para encriptar la contraseña antes de guardarla en la base de datos. Podríamos utilizar otro algoritmo como sha1 o uno propio. Es totalmente recomendable encriptar las contraseñas y no guardarlas en texto plano en nuestra base de datos por motivos de seguridad.

Por último, creamos la plantilla donde se mostrará el formulario de registro.

/apps/frontend/modules/user/templates/registerSuccess.php

1
2
3
4
<form action="<?php echo url_for("@user_register"); ?>" method="post">
  <?php echo $form; ?>
  <input type="submit" value="Registrarse" />
</form>

Debemos añadir la siguiente ruta en el archivo routing.yml:

user_register:
  url:   /register
  param: { module: user, action: register }

Y eso es todo, ya hemos creado un sistema muy básico de registro de usuarios en Symfony 1.4. A partir de aquí se puede expandir e incluir las funcionalidades que queramos.
En un próximo post, realizaremos el login y el logout.

Cualquier duda o si hay que explicar algo mejor, en los comentarios :)

Etiquetas: , ,