Validación

Introducción

Laravel provides several different approaches to validate your application's incoming data. By default, Laravel's base controller class uses a ValidatesRequests trait which provides a convenient method to validate incoming HTTP request with a variety of powerful validation rules.

Validation Quickstart

To learn about Laravel's powerful validation features, let's look at a complete example of validating a form and displaying the error messages back to the user.

Defining The Routes

First, let's assume we have the following routes defined in our app/Http/routes.php file:

// Display a form to create a blog post...
Route::get('post/create', 'PostController@create');

// Store a new blog post...
Route::post('post', 'PostController@store');

Of course, the GET route will display a form for the user to create a new blog post, while the POST route will store the new blog post in the database.

Creating The Controller

Next, let's take a look at a simple controller that handles these routes. We'll leave the store method empty for now:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Show the form the create a new blog post.
     *
     * @return Response
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * Store a new blog post.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // Validate and store the blog post...
    }
}

Writing The Validation Logic

Now we are ready to fill in our store method with the logic to validate the new blog post. If you examine your application's base controller (App\Http\Controllers\Controller) class, you will see that the class uses a ValidatesRequests trait. This trait provides a convenient validate method in all of your controllers.

The validate method accepts an incoming HTTP request and a set of validation rules. If the validation rules pass, your code will keep executing normally; however, if validation fails, an exception will be thrown and the proper error response will automatically be sent back to the user. In the case of a traditional HTTP request, a redirect response will be generated, while a JSON response will be sent for AJAX requests.

To get a better understanding of the validate method, let's jump back into the store method:

/**
 * Store a new blog post.
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $this->validate($request, [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // The blog post is valid, store in database...
}

As you can see, we simply pass the incoming HTTP request and desired validation rules into the validate method. Again, if the validation fails, the proper response will automatically be generated. If the validation passes, our controller will continue executing normally.

Displaying The Validation Errors

So, what if the incoming request parameters do not pass the given validation rules? As mentioned previously, Laravel will automatically redirect the user back to their previous location. In addition, all of the validation errors will automatically be flashed to the session.

Again, notice that we did not have to explicitly bind the error messages to the view in our GET route. Esto es porque Laravel siempre buscará errores en los datos de la sesión, y automáticamente los enlazará a la vista si los ha encontrado. So, it is important to note that an $errors variable will always be available in all of your views on every request, allowing you to conveniently assume the $errors variable is always defined and can be safely used. The $errors variable will be an instance of Illuminate\Support\MessageBag. For more information on working with this object, check out its documentation.

So, in our example, the user will be redirected to our controller's create method when validation fails, allowing us to display the error messages in the view:

<!-- /resources/views/post/create.blade.php -->

<h1>Create Post</h1>

@if (count($errors) > 0)
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<!-- Create Post Form -->

Personalizar el formato de errores flasheados

Si quieres personalizar el formato de los errores de validación que se "flashean" a la sesión cuando la validación falla, reemplaza el método formatValidationErrors en el controlador base. Don't forget to import the Illuminate\Contracts\Validation\Validator class at the top of the file:

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;

abstract class Controller extends BaseController
{
    use DispatchesJobs, ValidatesRequests;

    /**
     * {@inheritdoc}
     */
    protected function formatValidationErrors(Validator $validator)
    {
        return $validator->errors()->all();
    }
}

AJAX Requests & Validation

In this example, we used a traditional form to send data to the application. However, many applications use AJAX requests. When using the validate method during an AJAX request, Laravel will not generate a redirect response. Instead, Laravel generates a JSON response containing all of the validation errors. This JSON response will be sent with a 422 HTTP status code.

Other Validation Approaches

Manually Creating Validators

If you do not want to use the ValidatesRequests trait's validate method, you may create a validator instance manually using the Validator facade. The make method on the facade generates a new validator instance:

<?php

namespace App\Http\Controllers;

use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * Store a new blog post.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // Store the blog post...
    }
}

El primer argumento que se le debe enviar al metodo make es el conjunto de datos a validar. El segundo argumento son las reglas a ser aplicadas al conjunto de datos.

After checking if the request failed to pass validation, you may use the withErrors method to flash the error messages to the session. When using this method, the $errors variable will automatically be shared with your views after redirection, allowing you to easily display them back to the user. The withErrors method accepts a validator, a MessageBag, or a PHP array.

Error bags con nombre

If you have multiple forms on a single page, you may wish to name the MessageBag of errors, allowing you to retrieve the error messages for a specific form. Simplemente pasa un nombre como segundo argumento withErrors:

return redirect('register')
            ->withErrors($validator, 'login');

Puedes entonces acceder la instancia MessageBag con nombre desde la variable $errors:

{{ $errors->login->first('email') }}

Acciones post-validación

El validador también permite fijar los callbacks que se ejecutarán después de que termine la validación. This allows you to easily perform further validation and even add more error messages to the message collection. Para empezar, usa el método after en una instancia del validador:

$validator = Validator::make(...);

$validator->after(function($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong with this field!');
    }
});

if ($validator->fails()) {
    //
}

Validación Form Requests (solicitudes)

Para los escenarios más complejos de validación, podrás crear una clase "Form Request". Las clases Form Request son clases personalizadas que contienen la lógica de validación. Para crear una clase Form Request usa el comando de artisan make:request:

php artisan make:request StoreBlogPostRequest

La clase generada se colocará en el directorio app/Http/Request. Vamos a añadir unas reglas de validación al método rules:

/**
 * Obtener las reglas de validación que se aplican a la petición.
 *
 * @return array
 */
public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

So, how are the validation rules evaluated? All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic:

/**
 * Guardar el post entrante.
 *
 * @param  StoreBlogPostRequest  $request
 * @return Response
 */
public function store(StoreBlogPostRequest $request)
{
    // The incoming request is valid...
}

Si la validación falla, se generará una respuesta de redirección para enviar al usuario de vuelta a su ubicación anterior. Los errores también pueden ser flasheados a la sesión para que estén disponibles para mostrarlos. Si la solicitud es una petición AJAX, se devolverá una respuesta HTTP con un código de estado 422 al usuario incluyendo una representación JSON de los errores de validación.

Autorizar Form Requests

La clase Form Request además contiene un método authorize. Dentro de este método, puedes comprobar si el usuario autenticado tiene la autoridad para actualizar un recurso determinado. Por ejemplo, si un usuario intenta actualizar un comentario en un post del blog, ¿realmente es el dueño de ese comentario? Por ejemplo:

/**
 * Determinar si el usuario esta autorizado para hacer esta solicitud.
 *
 * @return bool
 */
public function authorize()
{
    $commentId = $this->route('comment');

    return Comment::where('id', $commentId)
                  ->where('user_id', Auth::id())->exists();
}

Ten en cuenta la llamada al método route en el ejemplo anterior. Este método otorga acceso a los parámetros de la URI definidos en la ruta llamada, como el parámetro {comment} en el ejemplo siguiente:

Route::post('comment/{comment}');

Si el método autorize devuelve false, automáticamente se le retornara una respuesta HTTP con un código de estado 403 y su método del controlador no se ejecutará.

Si planeas tener lógica de autorización en otra parte de su aplicación, simplemente devuelve true en el método authorize:

/**
 * Determinar si el usuario esta autorizado para hacer esta petición.
 *
 * @return bool
 */
public function authorize()
{
    return true;
}

Personalizar el formato de errores flasheados

If you wish to customize the format of the validation errors that are flashed to the session when validation fails, override the formatErrors on your base request (App\Http\Requests\Request). Don't forget to import the Illuminate\Contracts\Validation\Validator class at the top of the file:

/**
 * {@inheritdoc}
 */
protected function formatErrors(Validator $validator)
{
    return $validator->errors()->all();
}

Trabajar con los mensajes de error

After calling the errors method on a Validator instance, you will receive an Illuminate\Support\MessageBag instance, which has a variety of convenient methods for working with error messages.

Recuperar el primer mensaje de error para un campo

To retrieve the first error message for a given field, use the first method:

$messages = $validator->errors();

echo $messages->first('email');

Recuperar todos los mensajes de error para un campo

If you wish to simply retrieve an array of all of the messages for a given field, use the get method:

foreach ($messages->get('email') as $message) {
    //
}

Recuperar todos los mensajes de error para todos los campos

To retrieve an array of all messages for all fields, use the all method:

foreach ($messages->all() as $message) {
    //
}

Determinar si existe un mensaje en un campo

if ($messages->has('email')) {
    //
}

Recuperar un mensaje de error con un formato

echo $messages->first('email', '<p>:message</p>');

Recuperar todos los mensajes de error con un formato

foreach ($messages->all('<li>:message</li>') as $message) {
    //
}

Mensajes de error personalizados

If needed, you may use custom error messages for validation instead of the defaults. There are several ways to specify custom messages. First, you may pass the custom messages as the third argument to the Validator::make method:

$messages = [
    'required' => 'The :attribute field is required.',
];

$validator = Validator::make($input, $rules, $messages);

In this example, the :attribute place-holder will be replaced by the actual name of the field under validation. You may also utilize other place-holders in validation messages. Por ejemplo:

$messages = [
    'same'    => 'The :attribute and :other must match.',
    'size'    => 'The :attribute must be exactly :size.',
    'between' => 'The :attribute must be between :min - :max.',
    'in'      => 'The :attribute must be one of the following types: :values',
];

Especificar un mensaje personalizado para un atributo dado

Sometimes you may wish to specify a custom error messages only for a specific field. You may do so using "dot" notation. Specify the rule first, followed by the attribute's name:

$messages = [
    'email.required' => '¡Necesitamos conocer tu dirección de correo electrónico!',
];

Especificar mensajes personalizados en archivos de idioma

In many cases, you may wish to specify your attribute specific custom messages in a language file instead of passing them directly to the Validator. Para ello, añade tus mensajes al array custom en el archivo de idioma resources/lang/xx/validation.php.

'custom' => [
    'email' => [
        'required' => '¡Necesitamos conocer tu dirección de correo electrónico!',
    ],
],

Reglas de validación disponibles

A continuación hay una lista de todas las reglas de validación disponibles y su función:

accepted

El campo a validar debe ser yes, on, 1 o true. Resulta útil para validar la aceptación de "Términos de Servicio".

active_url

El cambo bajo validación debe ser una URL válida acorde con la función PHP checkdnsrr.

after:date

El campo a validar debe contener una fecha posterior a una dada. Las fechas se pasarán a la función de PHP strtotime.

alpha

El campo bajo validación debe contener únicamente caracteres alfabéticos.

alpha_dash

El campo bajo validación puede contener caracteres alfanuméricos, así como guiones altos y bajos.

alpha_num

El campo bajo validación debe contener únicamente caracteres alfanuméricos.

array

El campo a validar debe ser un array PHP.

before:date

El campo bajo validación debe ser una fecha anterior a la fecha dada. Las fechas serán pasadas a la función strtotime de PHP.

between:min,max

El campo a validar debe tener un tamaño entre min y max. Cadenas, caracteres numéricos y archivos son evaluados de la misma manera que la regla size.

boolean

El campo a validar debe contener un valor booleano. Las entradas aceptadas son true, false, 1, ``, "1" y "0".

confirmed

El campo bajo validación debe contener un campo coincidente de foo_confirmation. Por ejemplo, si el campo a validar fuera password, un campo coincidente password_confirmation debería estar presente en la entrada de datos.

date

El campo bajo validación debe ser una fecha válida acorde con la función strtotime de PHP.

date_format:format

The field under validation must match the given format. The format will be evaluated using the PHP date_parse_from_format function.

different:field

El campo a validar debe contener un valor diferente que el campo field.

digits:value

El campo bajo validación debe ser numérico y debe tener una longitud exacta de value..

digits_between:min,max

El campo bajo validación debe contener una longitud de entre min y max..

email

El campo a validar estar correctamente formateado como una dirección e-mail.

exists:table,column

El campo bajo validación debe existir en una tabla de la base de datos dada.

Uso básico de la regla 'exists'

'state' => 'exists:states'

Especificar un nombre de columna personalizado

'state' => 'exists:states,abbreviation'

Puedes además especificar más condiciones que serán añadidas como clausulas "where" a la consulta:

'email' => 'exists:staff,email,account_id,1'

Pasando NULL como valor de la clausula "where" comprobará valores NULL en la base de datos:

'email' => 'exists:staff,email,deleted_at,NULL'

image

El archivo bajo validación debe ser una imagen (jpeg, png, bmp, gif o svg)

in:foo,bar,...

El campo bajo validación debe estar incluido en lista de valores dados.

integer

El campo a validar debe ser un entero.

ip

El campo a validar debe contener una dirección IP.

max:valor

El campo a validar debe ser menor o igual a un máximo valor. Cadenas, caracteres numéricos y archivos son evaluados de la misma manera que la regla size.

mimes:foo,bar,...

El archivo a validar debe ser del tipo MIME que corresponda a alguno de los listados.

Uso básico de la regla MIME

'photo' => 'mimes:jpeg,bmp,png'

min:valor

El campo a validar debe tener un mínimo valor. Cadenas, caracteres numéricos y archivos son evaluados de la misma manera que la regla size.

not_in:foo,bar,...

El campo bajo validación no debe estar incluido en la lista de valores dados.

numeric

El campo a validar debe ser numérico.

regex:pattern

El campo a validar debe coincidir con la expresión regular dada.

Note: Cuando se utiliza una expresión regex, puede ser necesario especificar reglas en un array en lugar de utilizar el delimitador pipe "|", especialmente si la expresión regular contiene un caracter pipe.

required

El campo a validar debe estar presente en la entrada de datos.

required_if:anotherfield,value,...

El campo a validar debe estar presente si el campo anotherfield es coincide con algún value.

required_with:foo,bar,...

El campo debe estar presente sólo si cualquiera de los otros especificados está presente.

required_with_all:foo,bar,...

El campo a validar debe estar presente únicamente si todos los campos especificados están presentes.

required_without:foo,bar,...

El campo a validar debe estar presente sólo cuando cualquiera de los otros especificados no esté presente.

required_without_all:foo,bar,...

El campo a validar debe estar presente sólo cuando todos los otros valores especificados no estén presentes.

same:field

El campo field debe coincidir con el campo bajo validación.

size:value

El campo bajo validación debe tener un tamaño que coincida con value. Para cadenas, value corresponde al número de caracteres. Para datos numéricos, value corresponde a un valor entero. Para archivos, size corresponde al tamaño del archivo en kilobytes.

string

El campo a validar debe ser una cadena.

timezone

El campo a validar debe ser un identificador de zona horaria válido de acuerdo a la función de PHP timezone_identifiers_list.

unique:table,column,except,idColumn

El campo a validar debe ser único en la tabla de la base de datos. Si la opción column no se especifica, se usará el nombre del campo.

Specifying A Custom Column Name:

'email' => 'unique:users,email_address'

Custom Database Connection

A veces, necesitarás establecer una conexión diferente para las consultas realizadas por el Validator. Como se muestra arriba, unique:users utiliza la conexión por defecto para consultar la base de datos. To override this, specify the connection followed by the table name using "dot" syntax:

'email' => 'unique:connection.users,email_address'

Forcing A Unique Rule To Ignore A Given ID:

Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. You only want to throw a validation error if the user provides an e-mail address that is already used by a different user. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter:

'email' => 'unique:users,email_address,'.$user->id

Adding Additional Where Clauses:

Puedes además especificar más condiciones que serán añadidas como clausulas "where" a la consulta:

'email' => 'unique:users,email_address,NULL,id,account_id,1'

En la regla anterior, únicamente las filas con un account_id de 1 se incluirían en la comprobación 'unique'.

url

The field under validation must be a valid URL according to PHP's filter_var function.

Añadir reglas condicionalmente

En algunas situaciones puede ser necesario validar un campo sólo si un campo determinado se encuentra en el conjunto de datos. Para lograr esto rápidamente, añade la regla sometimes a la lista de reglas:

$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

En el ejemplo anterior, el campo email será validado si se encuentra presente en el array $data.

Validación condicional compleja

Sometimes you may wish to add validation rules based on more complex conditional logic. For example, you may wish to require a given field only if another field has a greater value than 100. Or, you may need two fields to have a given value only when another field is present. Agregar estas reglas de validación no tiene por que ser un problema. Primero, creamos una instancia de Validator con las reglas estáticas que nunca cambian:

$v = Validator::make($data, [
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

Supongamos que nuestra aplicación web es para coleccionistas de juegos. Si un coleccionista de juegos se registra en nuestra aplicación y posee más de 100 juegos, queremos saber por qué tiene tantos. Por ejemplo, quizá dirige una tienda de re-venta de juegos, o tal vez sólo es un coleccionista. Para agregar condicionalmente este requisito, podemos utilizar el método sometimes en la instancia Validator.

$v->sometimes('reason', 'required|max:500', function($input) {
    return $input->games >= 100;
});

El primer argumento pasado al método sometimes es el nombre del campo que estamos validando condicionalmente. El segundo argumento son las reglas que queremos añadir. Si el Closure pasado como tercer argumento retorna true, las reglas se añadirán. Este método hace que sea muy sencillo construir validaciones condicionales complejas. Incluso puedes añadir validaciones condicionales para varios campos a la vez:

$v->sometimes(['reason', 'cost'], 'required', function($input) {
    return $input->games >= 100;
});

Note: The $input parameter passed to your Closure will be an instance of Illuminate\Support\Fluent and may be used to access your input and files.

Reglas de validación personalizadas

Laravel ofrece una variedad de útiles reglas de validación; sin embargo, puedes especificar algunas reglas propias. One method of registering custom validation rules is using the extend method on the Validator facade. Let's use this method within a service provider to register a custom validation rule:

<?php

namespace App\Providers;

use Validator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('foo', function($attribute, $value, $parameters) {
            return $value == 'foo';
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

El Closure de validación personalizado recibe tres argumentos: el nombre del atributo ($attribute) a ser validado, el valor ($value) del atributo, y un array de parámetros ($parameters) pasados a la regla.

Puedes también pasar una clase y un método al método extend en vez de un Closure:

Validator::extend('foo', 'FooValidator@validate');

Defining The Error Message

You will also need to define an error message for your custom rule. You can do so either using an inline custom message array or by adding an entry in the validation language file. This message should be placed in the first level of the array, not within the custom array, which is only for attribute-specific error messages:

"foo" => "Your input was invalid!",

"accepted" => "The :attribute must be accepted.",

// The rest of the validation error messages...

Cuando se crea una regla de validación personalizada, a veces necesitarás definir place-holders personalizados para los mensajes de error. You may do so by creating a custom Validator as described above then making a call to the replacer method on the Validator facade. You may do this within the boot method of a service provider:

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Validator::extend(...);

    Validator::replacer('foo', function($message, $attribute, $rule, $parameters) {
        return str_replace(...);
    });
}