Comunidad de diseño web y desarrollo en internet online

Módulo de Usuarios (IV):Validar formulario y guardar datos con Laravel

En este nuevo tutorial veremos cómo validar un formulario y guardar datos con Laravel 4. En los capítulos anteriores ya vimos los siguientes temas:



Además, para hacer este tutorial es necesario que hayan completado: Configurar base de datos y crear tablas con Laravel dado que necesitaremos una tabla users con los campos: email, password, full_name, created_at y updated_at tal como explica dicho tutorial.


Validar los datos enviados en el formulario


Esta es una tarea tan común que todos los frameworks incluyen clases dispuestas a asistir al usuario en la validación de datos. Laravel por supuesto no es la excepción.

Volvamos a la función store donde quedamos anteriormente:

Código :

    public function store()
    {
        return Input::all();
    }


Acá haremos todo el proceso.

Primero que nada, vamos a crear un nuevo usuario (new User)


En Laravel los registros de la base de datos se pueden manejar como objetos gracias al ORM de Laravel: Eloquent.

Sé que es primera vez que les hablo de Eloquent, por lo tanto voy a mantener todo el código muy sencillo y en, digamos, posteriores tutoriales sí les hablaré de temas un poco más avanzados. La idea es que todos puedan seguir este tutorial


Dado que, como les dije, cada registro (fila de la tabla users) es manejado como si fuera un nuevo objeto, y aquí intentamos crear un nuevo usuario, pues:

Código :

$user = new User


Esto funciona sólo porque Laravel viene con un modelo User.php ya predefinido en:

Código :

app/models/User.php


Ve a darle un vistazo y regresa cuando estés listo.

Ok, un gusto tenerte de vuelta.

Lo que haremos a continuación es interactuar con nuestro controlador Admin_UserController y nuestro modelo User para validar y guardar el usuario.

Recuerda que como vimos en otro tutorial, el controlador debe apoyarse en los modelos y otras clases lo más posible, de manera que la programación del controlador sea limpia y la “lógica de negocio” o dicho de otra forma, el “código pesado” esté en nuestro modelo.

Nosotros, en otras palabras, queremos que la acción store de nuestro controlador luzca así:

Código :

   /**
    * Store a newly created resource in storage.
    *
    * @return Response
    */
    public function store()
    {
        // Creamos un nuevo objeto para nuestro nuevo usuario
        $user = new User;
        // Obtenemos la data enviada por el usuario
        $data = Input::all();
        
        // Revisamos si la data es válido
        if ($user->isValid($data))
        {
            // Si la data es valida se la asignamos al usuario
            $user->fill($data);
            // Guardamos el usuario
            $user->save();
            // Y Devolvemos una redirección a la acción show para mostrar el usuario
            return Redirect::route('admin.users.show', array($user->id));
        }
        else
        {
            // En caso de error regresa a la acción create con los datos y los errores encontrados
return Redirect::route('admin.users.create')->withInput()->withErrors($user->errors);
        }
    }


El código se explica solo, de todas formas:
  • Creamos un nuevo usuario (new User).
  • Tomamos los datos enviados por el usuario (Input::all()).
  • Si son válidos se lo asignamos al usuario, guardamos el usuario y redireccionamos a “show”.
  • Si no son válidos redireccionamos a la pantalla anterior pero llevándonos de regreso la data y los errores generados en la validación, para mostrárselos al usuario.


¿Qué nos hace falta acá?

Bueno, básicamente nunca le dijimos a Laravel qué o cómo validar, de hecho la función User::isValid() no existe, si presionamos el botón “Crear usuario” nos va a arrojar lo siguiente:

Código :

Call to undefined method Illuminate\Database\Query\Builder::isValid()


¿Ahora qué?

Vamos al modelo (app/models/User.php) y agregamos lo siguiente:

Código :

    public $errors;
    
    public function isValid($data)
    {
        $rules = array(
            'email'     => 'required|email|unique:users'',
            'full_name' => 'required|min:4|max:40',
            'password'  => 'required|min:8|confirmed'
        );
        
        $validator = Validator::make($data, $rules);
        
        if ($validator->passes())
        {
            return true;
        }
        
        $this->errors = $validator->errors();
        
        return false;
    }


Primero definimos una propiedad dentro del modelo User que servirá para almacenar los errores (en caso de que haya alguno), la coloqué pública para simplificar el ejemplo:

Código :

public $errors;


Lo segundo es definir el método isValid, que acepta como parámetro la data enviada por el usuario. Dentro fíjense que defino un array con las reglas de validación “rules”.

Este array $rules es procesado por la clase de validación de Laravel (Validator) cuyo método Validator::make acepta, como primer parámetro un array de datos ($data) y como segundo parámetro un array de reglas ($rules).

Fíjense que las claves de ambos arrays coinciden y se refieren a los nombres de los campos (en nuestro ejemplo: email, full_name y password):

Entonces llamamos al método:

Código :

$validator = Validator::make($data, $rules)


Así se crea un nuevo objeto almacenado en $validator que contiene toda la data y las reglas de validación. Ahora todo lo que hace falta es ejecutar la validación:

Código :

$validator->passes() //devuelve TRUE si la validación pasa


Código :

$validator->fails() //Método pesimista, devuelve TRUE si la validación falla


Si la validación pasa, retornamos TRUE en nuestro método isValid, si falla entonces almacenamos en la propiedad $errors los errores para decirle al usuario qué salió mal:

Código :

$this->errors = $validator->errors();


Y retornamos FALSE.

Prácticamente siempre que necesitemos validar algo con Laravel, usaremos este método, lo que cambia son las reglas que tenemos que definir.

Como pueden ver en el ejemplo anterior, las reglas se definen escribiendo un array asociativo, donde la llave (key) es el nombre del campo, y el valor es las reglas asignadas a ese campo separadas con barra | y si la regla necesita un parámetro adicional se define con : y si son varios parámetros es separan por coma, así:

Código :

'nombre_de_campo' => 'regla1|regla2|regla_con_parametros:parametro1,parametro2'


Reglas de validación de Laravel


Según usamos en el ejemplo:
  • required sirve para indicar que un campo es obligatorio.
  • email indica que el campo es de tipo email.
  • min:value exige que el campo tenga un mínimo de “value” caracteres.
  • max al contrario del anterior, delimita el máximo posible.
  • confirmed útil para confirmar email o contraseña, exige que haya un campo con el mismo nombre pero con el sufijo “_confirmation” y que ambos tengan el mismo valor (ej: password y password_confirmation).
  • unique:table exige que el campo sea único en la tabla “table” (útil para campos como username e e-mail).


Más adelante veremos más sobre la regla “unique”


Si quieren ver todas las reglas de validación de Laravel vean la documentación oficial

Penúltimo paso:

Indicarle a Laravel qué campos se pueden llenar por “asignación masiva”


Volviendo al controlador, cuando hacemos:

Código :

$user->fill($data)


Estamos haciendo algo llamado en Laravel “Massive assignment” (asignación masiva), es decir llenar todas las propiedades del modelo a través de un array de datos. Esto puede traer varios problemas, por ello Laravel nos permite indicarle al modelo qué campos son “llenables” (fillable) a través de métodos como User::fill:

En el modelo (app/models/User.php) agreguen esta otra propiedad:

Código :

protected $fillable = array('email', 'full_name', 'password');


Ahora aunque algún aprendiz de hacker intente enviar campos adicionales no conseguirá romper la funcionalidad dado que sólo esos 3 campos son tomados en cuenta, más aún, tampoco se intentará grabar el campo oculto “_token” ni el campo “password_confirmation” que no hace falta en la tabla “users”.

Y ahora un último paso:

Si llenamos nuestro formulario de forma inválida, digamos, escribieron “pepito” en el campo email, la aplicación es redireccionada de vuelta al formulario (ruta admin.users.create) pero no se muestran los errores ni nada, esto está muy mal…

Hay muchas, muchas aplicaciones “funcionando” en producción que no muestran ningún error si algo sale mal, nunca le hagan esto a los pobres usuarios…


Cómo mostrar los errores de una validación fallida:


Laravel parece ser un poco pesimista, porque siempre, en nuestras vistas, se encuentra definida una variable llamada $errors con un objeto de tipo MessageBag que tiene algunos métodos bastante básicos, uno de ellos es any() que revisa si de verdad hay algún error, otro es all() que devuelve el array con todos los posibles errores.

Agreguemos esto a la vista app/views/admin/users/form.blade.php justo debajo del título:

Código :

  @if ($errors->any())
    <div class="alert alert-danger">
      <button type="button" class="close" data-dismiss="alert">&times;</button>
      <strong>Por favor corrige los siguentes errores:</strong>
      <ul>
      @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
      @endforeach
      </ul>
    </div>
  @endif


Ahora intenten re-enviar el formulario nuevamente con el email “pepito” y verán una lista de mensajes en rojo diciéndote qué salió mal:



¡Excelente!

Para colocar los mensajes de error en español hay que hacer 3 pasos:

  1. Cambiar en app/config/app.php la variable “locale” a “es” (actualmente tiene en).
  2. Ir al directorio app/lang/ copiar la carpeta en/ y pegarla en el mismo directorio, renombrándola a es/
  3. Abrir la carpeta app/lang/es recién duplicada y traducir todos los mensajes a español.


Es posible que estos mensajes ya estén disponibles si buscan en Google, por ahora esto se escapa un poco del alcance de nuestro tutorial.


Mantener los valores especificados por el usuario


El problema con esto es que aunque ya estamos mostrando la data no estamos devolviendo los valores al usuario, aunque sea un error, el campo email debería decir “pepito” y no estar en blanco, de forma que el usuario pueda completar pepito@gmail.com sin tener que reescribir todo de nuevo, por ejemplo.

Esto se puede resolver de forma muy simple con Laravel:

Modifiquemos nuestro método create de manera que quede así:

Código :

   public function create()
   {
        // Creamos un nuevo objeto User para ser usado por el helper Form::model
        $user = new User;
      return View::make('admin/users/form')->with('user', $user);
   }


Básicamente lo mismo que teníamos antes, sólo que instanciamos un nuevo objeto User.

En nuestro form app/views/admin/users/form.blade.php vamos a cambiar Form::open por otro helper llamado Form::model, que es muy parecido, sólo que como primer parámetro acepta un modelo, y lo demás queda igual:

Código :

{{-- Reemplazamos Form::open por Form::model: --}}
{{ Form::model($user, array('route' => 'admin.users.store', 'method' => 'POST'), array('role' => 'form')) }}


¡Listo! Ahora prueben registrarse con email pepito por última vez, verán que no sólo se muestran los errores sino que Laravel ahora rebota los datos nuevamente al formulario.

¡Excelente!

Por último veamos un gráfico de lo que sucede entre el usuario y el servidor cuando el usuario pone “pepito” u otro email o campo no-válido:



Esto nos ilustra las diferentes redirecciones que se llevan a cabo de manera casi transparente.

Ahora si escriben todos los datos de forma válida, verán cómo Laravel los redirecciona a la vista “show” que por ahora sólo muestra algo así:

Código :

Aqui mostramos la info del usuario: 1


Y este sería el gráfico si todo va bien:



En próximos tutoriales por supuesto mejoraremos esto, también mostraremos la lista de los usuarios que vayamos agregando.

Si van a PHPMyAdmin observarán que un nuevo registro fue agregado a la tabla “users” de la base de datos pruebalaravel:



No es recomendable guardar las claves como texto plano


Espero que les haya gustado y hayan aprendido bastante con este tutorial. Dudas y preguntas en los comentarios.

Nos vemos la próxima semana.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate