Validations

Validations

Introducción

Laravel ofrece varias formas diferentes de validar los datos entrantes de tu aplicación. Lo más común es usar el método validate disponible en todas las solicitudes HTTP entrantes. Sin embargo, también existen otros enfoques para la validación.

Validation Quickstart

Para aprender sobre las potentes características de validación de Laravel, veamos un ejemplo completo de validación de un formulario y la visualización de los mensajes de error de vuelta al usuario. Al ver esta visión general, podrás obtener una buena comprensión general de cómo validar los datos de solicitud entrantes utilizando Laravel:

Defining the Routes

Primero, asumamos que tenemos las siguientes rutas definidas en nuestro archivo routes/web.php:

use App\Http\Controllers\PostController;
 
Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);

La ruta GET mostrará un formulario para que el usuario cree una nueva entrada de blog, mientras que la ruta POST almacenará la nueva entrada de blog en la base de datos.

Creating the Controller

A continuación, echemos un vistazo a un controlador simple que maneja las solicitudes entrantes a estas rutas. Dejaremos el método store vacío por ahora:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
 
class PostController extends Controller
{
    /**
     * Show the form to create a new blog post.
     */
    public function create(): View
    {
        return view('post.create');
    }
 
    /**
     * Store a new blog post.
     */
    public function store(Request $request): RedirectResponse
    {
        // Validate and store the blog post...
 
        $post = /** ... */
 
        return to_route('post.show', ['post' => $post->id]);
    }
}

Writing the Validation Logic

Ahora estamos listos para llenar nuestro método store con la lógica para validar la nueva entrada del blog. Para hacer esto, utilizaremos el método validate proporcionado por el objeto Illuminate\Http\Request.

Si las reglas de validación pasan, tu código continuará ejecutándose normalmente; sin embargo, si la validación falla, se lanzará una excepción Illuminate\Validation\ValidationException y se enviará automáticamente la respuesta de error adecuada al usuario.

Si la validación falla durante una solicitud HTTP tradicional, se generará una respuesta de redirección a la URL anterior.

Si la solicitud entrante es una solicitud XHR, se devolverá una respuesta JSON que contiene los mensajes de error de validación. Para obtener una mejor comprensión del método validate, volvamos al método store:

/**
 * Store a new blog post.
 */
public function store(Request $request): RedirectResponse
{
    $validated = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);
 
    // The blog post is valid...
 
    return redirect('/posts');
}

Como puedes ver, las reglas de validación se pasan al método validate. No te preocupes: todas las reglas de validación disponibles están documentadas. Nuevamente, si la validación falla, la respuesta adecuada se generará automáticamente. Si la validación pasa, nuestro controlador continuará ejecutándose de manera normal. Alternativamente, las reglas de validación pueden especificarse como arreglos de reglas en lugar de una sola cadena delimitada por |:

$validatedData = $request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

Además, puedes usar el método validateWithBag para validar una solicitud y almacenar cualquier mensaje de error dentro de un named error bag:

$validatedData = $request->validateWithBag('post', [
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

A veces es posible que desees detener la ejecución de las reglas de validación en un atributo después del primer fallo de validación. Para hacerlo, asigna la regla bail al atributo:

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

En este ejemplo, si la regla unique en el atributo title falla, la regla max no será verificada. Las reglas se validarán en el orden en que se asignan.

A Note on Nested Attributes

Si la solicitud HTTP entrante contiene datos de campo “anidados”, puedes especificar estos campos en tus reglas de validación utilizando la sintaxis del “punto”:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'author.name' => 'required',
    'author.description' => 'required',
]);

Por otro lado, si el nombre de tu campo contiene un punto literal, puedes prevenir explícitamente que esto se interprete como sintaxis de “punto” escapando el punto con una barra invertida:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'v1\.0' => 'required',
]);

Displaying the Validation Errors

Entonces, ¿qué sucede si los campos de la solicitud entrante no pasan las reglas de validación dadas? Como se mencionó anteriormente, Laravel redirigirá automáticamente al usuario de vuelta a su ubicación anterior. Además, todos los errores de validación y la entrada de la solicitud se flashearán automáticamente a la sesión.

Una variable $errors se comparte con todas las vistas de tu aplicación mediante el middleware Illuminate\View\Middleware\ShareErrorsFromSession, que es proporcionado por el grupo de middleware web.

Cuando se aplica este middleware, una variable $errors siempre estará disponible en tus vistas, lo que te permite suponer cómodamente que la variable $errors siempre está definida y se puede usar de manera segura.

La variable $errors será una instancia de Illuminate\Support\MessageBag. Para obtener más información sobre cómo trabajar con este objeto, consulta su documentación.

Entonces, en nuestro ejemplo, el usuario será redirigido al método create de nuestro controlador cuando la validación falle, lo que nos permitirá mostrar los mensajes de error en la vista:

<!-- /resources/views/post/create.blade.php -->
 
<h1>Create Post</h1>
 
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
 
<!-- Create Post Form -->

Customizing the Error Messages

Las reglas de validación incorporadas en Laravel tienen cada una un mensaje de error que se encuentra en el archivo lang/en/validation.php de tu aplicación. Si tu aplicación no tiene un directorio lang, puedes indicarle a Laravel que lo cree usando el comando lang:publish Artisan.

Dentro del archivo lang/es/validation encontrarás una entrada de traducción para cada regla de validación. Eres libre de cambiar o modificar estos mensajes en función de las necesidades de tu aplicación.

Además, puede copiar este archivo a otro directorio de idioma para traducir los mensajes para el idioma de su aplicación. Para obtener más información acerca de la localización de Laravel, echa un vistazo a la documentación completa de localización.

XHR Requests and Validation

En este ejemplo, usamos un formulario tradicional para enviar datos a la aplicación. Sin embargo, muchas aplicaciones reciben solicitudes XHR de un frontend potenciado por JavaScript. Al usar el método validate durante una solicitud XHR, Laravel no generará una respuesta de redirección. En su lugar, Laravel genera una respuesta JSON que contiene todos los errores de validación. Esta respuesta JSON se enviará con un código de estado HTTP 422.

The @error Directive

Puedes usar la directiva @error de Blade para determinar rápidamente si existen mensajes de error de validación para un atributo dado. Dentro de una directiva @error, puedes mostrar la variable $message para mostrar el mensaje de error:

<!-- /resources/views/post/create.blade.php -->
 
<label for="title">Post Title</label>
 
<input
    id="title"
    type="text"
    name="title"
    class="@error('title') is-invalid @enderror"
/>
 
@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

Si estás utilizando named error bag, puedes pasar el nombre de la bag de errores como segundo argumento a la directiva @error:

<input ... class="@error('title', 'post') is-invalid @enderror">

Repopulating Forms

Cuando Laravel genera una respuesta de redirección debido a un error de validación, el framework automáticamente flashea toda la entrada de la solicitud a la sesión. Esto se hace para que puedas acceder a la entrada de manera conveniente durante la siguiente solicitud y volver a llenar el formulario que el usuario intentó enviar.

Para recuperar la entrada pasada del request anterior, invoca el método old en una instancia de Illuminate\Http\Request. El método old extraerá los datos de entrada que se enviaron previamente desde la sesión:

$title = $request->old('title');

Laravel también proporciona un helper global old. Si estás mostrando entrada anterior dentro de una plantilla Blade, es más conveniente usar el helper old para rellenar de nuevo el formulario. Si no existe entrada anterior para el campo dado, se devolverá null:

<input type="text" name="title" value="{{ old('title') }}">

A Note on Optional Fields

Por defecto, Laravel incluye el middleware TrimStrings y ConvertEmptyStringsToNull en la pila de middleware global de tu aplicación. Debido a esto, a menudo necesitarás marcar tus campos de solicitud “opcionales” como nullable si no deseas que el validador considere los valores null como inválidos. Por ejemplo:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
    'publish_at' => 'nullable|date',
]);

En este ejemplo, estamos especificando que el campo publish_at puede ser null o una representación de fecha válida. Si el modificador nullable no se añade a la definición de la regla, el validador consideraría null como una fecha inválida.

Validation Error Response Format

Cuando tu aplicación lanza una excepción Illuminate\Validation\ValidationException y la solicitud HTTP entrante espera una respuesta JSON, Laravel formateará automáticamente los mensajes de error por ti y devolverá una respuesta HTTP 422 Unprocessable Entity.

A continuación, puedes revisar un ejemplo del formato de respuesta JSON para errores de validación. Ten en cuenta que las claves de error anidadas se simplifican en formato de “notación de punto”:

{
    "message": "The team name must be a string. (and 4 more errors)",
    "errors": {
        "team_name": [
            "The team name must be a string.",
            "The team name must be at least 1 characters."
        ],
        "authorization.role": [
            "The selected authorization.role is invalid."
        ],
        "users.0.email": [
            "The users.0.email field is required."
        ],
        "users.2.email": [
            "The users.2.email must be a valid email address."
        ]
    }
}

Form Request Validation

Creating Form Requests

Para escenarios de validación más complejos, es posible que desees crear una “solicitud de formulario”. Las solicitudes de formulario son clases de solicitud personalizadas que encapsulan su propia lógica de validación y autorización. Para crear una clase de solicitud de formulario, puedes usar el comando CLI Artisan make:request:

php artisan make:request StorePostRequest

La clase de solicitud de formulario generada se colocará en el directorio app/Http/Requests. Si este directorio no existe, se creará cuando ejecutes el comando make:request. Cada solicitud de formulario generada por Laravel tiene dos métodos: authorize y rules.

Como puedes suponer, el método authorize es responsable de determinar si el usuario autenticado actualmente puede realizar la acción representada por la solicitud, mientras que el método rules devuelve las reglas de validación que deben aplicarse a los datos de la solicitud:

/**
 * Get the validation rules that apply to the request.
 *
 * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
 */
public function rules(): array
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

ℹ️ Puedes indicar cualquier dependencia que necesites dentro del método rules. Se resolverán automáticamente a través del contenedor de servicios de Laravel.

Entonces, ¿cómo se evalúan las reglas de validación? Todo lo que necesitas hacer es indicar el tipo de la solicitud en el método de tu controlador. La solicitud del formulario entrante se valida antes de que se llame al método del controlador, lo que significa que no necesitas saturar tu controlador con ninguna lógica de validación:

/**
 * Store a new blog post.
 */
public function store(StorePostRequest $request): RedirectResponse
{
    // The incoming request is valid...
 
    // Retrieve the validated input data...
    $validated = $request->validated();
 
    // Retrieve a portion of the validated input data...
    $validated = $request->safe()->only(['name', 'email']);
    $validated = $request->safe()->except(['name', 'email']);
 
    // Store the blog post...
 
    return redirect('/posts');
}

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 se guardarán en la sesión para que estén disponibles para su visualización. Si la solicitud fue una solicitud XHR, 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.

ℹ️ ¿Necesitas añadir validación de solicitudes de formulario en tiempo real a tu frontend Laravel impulsado con Inertia? Echa un vistazo a Laravel Precognition.

Performing Additional Validation

A veces necesitas realizar validaciones adicionales después de que tu validación inicial se haya completado. Puedes lograr esto utilizando el método after de la solicitud del formulario.

El método after debería devolver un array de llamadas o funciones anónimas que se invocarán una vez que la validación esté completa. Las llamadas dadas recibirán una instancia de Illuminate\Validation\Validator, lo que te permitirá agregar mensajes de error adicionales si es necesario:

use Illuminate\Validation\Validator;
 
/**
 * Get the "after" validation callables for the request.
 */
public function after(): array
{
    return [
        function (Validator $validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add(
                    'field',
                    'Something is wrong with this field!'
                );
            }
        }
    ];
}

Como se mencionó, el array devuelto por el método after también puede contener clases invocables. El método __invoke de estas clases recibirá una instancia de Illuminate\Validation\Validator:

use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
use Illuminate\Validation\Validator;
 
/**
 * Get the "after" validation callables for the request.
 */
public function after(): array
{
    return [
        new ValidateUserStatus,
        new ValidateShippingTime,
        function (Validator $validator) {
            //
        }
    ];
}

Stopping on the First Validation Failure

Al agregar una propiedad stopOnFirstFailure a tu clase de solicitud, puedes informar al validador que debe dejar de validar todos los atributos una vez que haya ocurrido un solo fallo de validación:

/**
 * Indicates if the validator should stop on the first rule failure.
 *
 * @var bool
 */
protected $stopOnFirstFailure = true;

Customizing the Redirect Location

Como se discutió anteriormente, se generará una respuesta de redirección para enviar al usuario de vuelta a su ubicación anterior cuando falle la validación de la solicitud del formulario. Sin embargo, puedes personalizar este comportamiento. Para hacerlo, define una propiedad $redirect en tu solicitud de formulario:

/**
 * The URI that users should be redirected to if validation fails.
 *
 * @var string
 */
protected $redirect = '/dashboard';

O, si deseas redirigir a los usuarios a una ruta nombrada, puedes definir una propiedad $redirectRoute en su lugar:

/**
 * The route that users should be redirected to if validation fails.
 *
 * @var string
 */
protected $redirectRoute = 'dashboard';

Authorizing Form Requests

La clase de solicitud del formulario también contiene un método authorize. Dentro de este método, puedes determinar si el usuario autenticado tiene realmente la autoridad para actualizar un recurso dado. Por ejemplo, puedes determinar si un usuario realmente posee un comentario de blog que está intentando actualizar. Lo más probable es que interactúes con tus puertas y políticas de autorización dentro de este método:

use App\Models\Comment;
 
/**
 * Determine if the user is authorized to make this request.
 */
public function authorize(): bool
{
    $comment = Comment::find($this->route('comment'));
 
    return $comment && $this->user()->can('update', $comment);
}

Dado que todas las solicitudes de formularios extienden la clase de solicitud base de Laravel, podemos usar el método user para acceder al usuario autenticado actualmente. Además, nota la llamada al método route en el ejemplo anterior. Este método te otorga acceso a los parámetros URI definidos en la ruta que se está llamando, como el parámetro {comment} en el ejemplo a continuación:

return $this->user()->can('update', $this->comment);

Por lo tanto, si tu aplicación está aprovechando el enlace de modelo de ruta, tu código puede ser aún más conciso accediendo al modelo resuelto como una propiedad de la solicitud:

return $this->user()->can('update', $this->comment);

Si el método authorize devuelve false, se devolverá automáticamente una respuesta HTTP con un código de estado 403 y tu método del controlador no se ejecutará. Si planeas manejar la lógica de autorización para la solicitud en otra parte de tu aplicación, puedes eliminar el método authorize por completo, o simplemente devolver true:

/**
 * Determine if the user is authorized to make this request.
 */
public function authorize(): bool
{
    return true;
}

ℹ️ Puedes indicar cualquier dependencia que necesites dentro de la firma del método authorize. Se resolverán automáticamente a través del contenedor de servicios de Laravel.

Customizing the Error Messages

Puedes personalizar los mensajes de error utilizados por la solicitud de formulario sobrescribiendo el método messages. Este método debe devolver un array de pares atributo / regla y sus mensajes de error correspondientes:

/**
 * Get the error messages for the defined validation rules.
 *
 * @return array<string, string>
 */
public function messages(): array
{
    return [
        'title.required' => 'A title is required',
        'body.required' => 'A message is required',
    ];
}

Customizing the Validation Attributes

Muchos de los mensajes de error de reglas de validación integradas de Laravel contienen un marcador de posición :attribute. Si deseas que el marcador de posición :attribute de tu mensaje de validación sea reemplazado por un nombre de atributo personalizado, puedes especificar los nombres personalizados sobrescribiendo el método attributes. Este método debe devolver un array de pares atributo / nombre:

/**
 * Get custom attributes for validator errors.
 *
 * @return array<string, string>
 */
public function attributes(): array
{
    return [
        'email' => 'email address',
    ];
}

Preparing Input for Validation

Si necesitas preparar o sanear cualquier dato de la solicitud antes de aplicar tus reglas de validación, puedes usar el método prepareForValidation:

use Illuminate\Support\Str;
 
/**
 * Prepare the data for validation.
 */
protected function prepareForValidation(): void
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

Del mismo modo, si necesitas normalizar cualquier dato de solicitud después de que la validación esté completa, puedes usar el método passedValidation:

/**
 * Handle a passed validation attempt.
 */
protected function passedValidation(): void
{
    $this->replace(['name' => 'Taylor']);
}

Manually Creating Validators

Si no deseas usar el método validate en la solicitud, puedes crear una instancia de validador manualmente utilizando la facade Validator. El método make en la facade genera una nueva instancia de validador:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
 
class PostController extends Controller
{
    /**
     * Store a new blog post.
     */
    public function store(Request $request): RedirectResponse
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);
 
        if ($validator->fails()) {
            return redirect('/post/create')
                        ->withErrors($validator)
                        ->withInput();
        }
 
        // Retrieve the validated input...
        $validated = $validator->validated();
 
        // Retrieve a portion of the validated input...
        $validated = $validator->safe()->only(['name', 'email']);
        $validated = $validator->safe()->except(['name', 'email']);
 
        // Store the blog post...
 
        return redirect('/posts');
    }
}

El primer argumento pasado al método make es los datos bajo validación. El segundo argumento es un array de las reglas de validación que se deben aplicar a los datos.

Después de determinar si la validación de la solicitud ha fallado, puedes usar el método withErrors para almacenar los mensajes de error en la sesión. Al usar este método, la variable $errors se compartirá automáticamente con tus vistas después de la redirección, lo que te permitirá mostrarlas fácilmente al usuario. El método withErrors acepta un validador, un MessageBag o un array de PHP.

Detenerse en el Primer Error de Validación

El método stopOnFirstFailure informará al validador que debe dejar de validar todos los atributos una vez que haya ocurrido un solo fallo de validación:

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

Automatic Redirection

Si deseas crear una instancia de validador de forma manual pero aún aprovechar la redirección automática que ofrece el método validate de la solicitud HTTP, puedes llamar al método validate en una instancia de validador existente. Si la validación falla, el usuario será redirigido automáticamente o, en el caso de una solicitud XHR, se devolverá una respuesta JSON:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validate();

Puedes usar el método validateWithBag para almacenar los mensajes de error en un bolsa de errores nombrada si la validación falla:

Validator::make($request->all(), [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
])->validateWithBag('post');

Named Error Bags

Si tienes múltiples formularios en una sola página, es posible que desees nombrar el MessageBag que contiene los errores de validación, lo que te permitirá recuperar los mensajes de error para un formulario específico. Para lograr esto, pasa un nombre como segundo argumento a withErrors:

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

Entonces puedes acceder a la instancia MessageBag nombrada desde la variable $errors:

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

Customizing the Error Messages

Si es necesario, puedes proporcionar mensajes de error personalizados que una instancia de validador debería usar en lugar de los mensajes de error predeterminados proporcionados por Laravel. Hay varias formas de especificar mensajes personalizados. Primero, puedes pasar los mensajes personalizados como el tercer argumento al método Validator::make:

$validator = Validator::make($input, $rules, $messages = [
    'required' => 'The :attribute field is required.',
]);

En este ejemplo, el marcador de posición :attribute será reemplazado por el nombre real del campo que se está validando. También puedes utilizar otros marcadores de posición en los mensajes de validación. Por ejemplo:

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

Specifying a Custom Message for a Given Attribute

A veces es posible que desees especificar un mensaje de error personalizado solo para un atributo específico. Puedes hacerlo utilizando la notación “punto”. Especifica el nombre del atributo primero, seguido de la regla:

$messages = [
    'email.required' => 'We need to know your email address!',
];

Specifying Custom Attribute Values

Muchos de los mensajes de error incorporados de Laravel incluyen un marcador de posición :attribute que se reemplaza con el nombre del campo o atributo bajo validación. Para personalizar los valores utilizados para reemplazar estos marcadores de posición para campos específicos, puedes pasar un array de atributos personalizados como cuarto argumento al método Validator::make:

$validator = Validator::make($input, $rules, $messages, [
    'email' => 'email address',
]);

Performing Additional Validation

A veces necesitas realizar validaciones adicionales después de que tu validación inicial esté completa. Puedes lograr esto utilizando el método after del validador. El método after acepta una función anónima o un array de funciones invocables que se llamarán después de que la validación esté completa. Los callable dados recibirán una instancia de Illuminate\Validation\Validator, lo que te permitirá generar mensajes de error adicionales si es necesario:

use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make(/* ... */);
 
$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add(
            'field', 'Something is wrong with this field!'
        );
    }
});
 
if ($validator->fails()) {
    // ...
}

Como se mencionó, el método after también acepta un array de callable, lo cual es particularmente conveniente si tu lógica de “validación posterior” está encapsulada en clases invocables, que recibirán una instancia de Illuminate\Validation\Validator a través de su método __invoke:

use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
 
$validator->after([
    new ValidateUserStatus,
    new ValidateShippingTime,
    function ($validator) {
        // ...
    },
]);

Working With Validated Input

Después de validar los datos de solicitud entrantes utilizando una solicitud de formulario o una instancia de validador creada manualmente, es posible que desees recuperar los datos de solicitud entrantes que realmente fueron validados. Esto se puede lograr de varias maneras. Primero, puedes llamar al método validated en una solicitud de formulario o en una instancia de validador. Este método devuelve un array de los datos que fueron validados:

$validated = $request->validated();
 
$validated = $validator->validated();

Alternativamente, puedes llamar al método safe en una instancia de solicitud de formulario o validador. Este método devuelve una instancia de Illuminate\Support\ValidatedInput. Este objeto expone métodos onlyexcept y all para recuperar un subconjunto de los datos validados o el array completo de datos validados:

$validated = $request->safe()->only(['name', 'email']);
 
$validated = $request->safe()->except(['name', 'email']);
 
$validated = $request->safe()->all();

Además, la instancia Illuminate\Support\ValidatedInput se puede iterar y acceder como un array:

// Validated data may be iterated...
foreach ($request->safe() as $key => $value) {
    // ...
}
 
// Validated data may be accessed as an array...
$validated = $request->safe();
 
$email = $validated['email'];

Si deseas añadir campos adicionales a los datos validados, puedes llamar al método merge:

$validated = $request->safe()->merge(['name' => 'Taylor Otwell']);

Si deseas recuperar los datos validados como una instancia de colección, puedes llamar al método collect:

$collection = $request->safe()->collect();

Working With Error Messages

Después de llamar al método errors en una instancia de Validator, recibirás una instancia de Illuminate\Support\MessageBag, que tiene una variedad de métodos convenientes para trabajar con mensajes de error. La variable $errors que se pone automáticamente a disposición de todas las vistas también es una instancia de la clase MessageBag.

Retrieving the First Error Message for a Field

Para recuperar el primer mensaje de error para un campo dado, utiliza el método first:

$errors = $validator->errors();
 
echo $errors->first('email');

Retrieving All Error Messages for a Field

Si necesitas recuperar un array con todos los mensajes para un campo dado, utiliza el método get:

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

Si estás validando un campo de formulario de array, puedes recuperar todos los mensajes para cada uno de los elementos del array usando el carácter *:

foreach ($errors->get('attachments.*') as $message) {
    // ...
}

Retrieving All Error Messages for All Fields

Para recuperar un array de todos los mensajes para todos los campos, utiliza el método all:

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

Determining if Messages Exist for a Field

El método has se puede utilizar para determinar si existen mensajes de error para un campo dado:

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

Specifying Custom Messages in Language Files

Las reglas de validación integradas de Laravel tienen cada una un mensaje de error que se encuentra en el archivo lang/en/validation.php de tu aplicación. Si tu aplicación no tiene un directorio lang, puedes instruir a Laravel para que lo cree utilizando el comando Artisan lang:publish.

Dentro del archivo lang/en/validation.php, encontrarás una entrada de traducción para cada regla de validación. Puedes cambiar o modificar estos mensajes según las necesidades de tu aplicación.

Además, puedes copiar este archivo a otro directorio de idioma para traducir los mensajes para el idioma de tu aplicación. Para obtener más información sobre la localización de Laravel, consulta la documentación completa de localización.

Custom Messages for Specific Attributes

Puedes personalizar los mensajes de error utilizados para combinaciones específicas de atributo y regla dentro de los archivos de idioma de validación de tu aplicación. Para hacerlo, añade tus personalizaciones de mensajes al array custom del archivo de idioma lang/xx/validation.php de tu aplicación:

'custom' => [
    'email' => [
        'required' => 'We need to know your email address!',
        'max' => 'Your email address is too long!'
    ],
],

Specifying Attributes in Language Files

Muchos de los mensajes de error integrados de Laravel incluyen un marcador de posición :attribute que se reemplaza con el nombre del campo o atributo bajo validación. Si deseas que la porción :attribute de tu mensaje de validación sea reemplazada por un valor personalizado, puedes especificar el nombre del atributo personalizado en el array attributes de tu archivo de idioma lang/xx/validation.php:

'attributes' => [
    'email' => 'email address',
],

Specifying Values in Language Files

Algunos de los mensajes de error de las reglas de validación integradas de Laravel contienen un marcador de posición :value que se reemplaza con el valor actual del atributo de la solicitud. Sin embargo, es posible que ocasionalmente necesites que la parte :value de tu mensaje de validación se reemplace con una representación personalizada del valor. Por ejemplo, considera la siguiente regla que especifica que se requiere un número de tarjeta de crédito si el payment_type tiene un valor de cc:

Validator::make($request->all(), [
    'credit_card_number' => 'required_if:payment_type,cc'
]);

Si esta regla de validación falla, producirá el siguiente mensaje de error:

The credit card number field is required when payment type is cc.

En lugar de mostrar cc como el valor del tipo de pago, puedes especificar una representación de valor más amigable para el usuario en tu archivo de idioma lang/xx/validation.php definiendo un array values:

The credit card number field is required when payment type is cc.

❗ Por defecto, el esqueleto de la aplicación Laravel no incluye el directorio lang. Si deseas personalizar los archivos de idioma de Laravel, puedes publicarlos mediante el comando Artisan lang:publish. Después de definir este valor, la regla de validación producirá el siguiente mensaje de error:

Después de definir este valor, la regla de validación producirá el siguiente mensaje de error:

**The credit card number field is required when payment type is credit card.**

Available Validation Rules

La lista de todas las validaciones aquí

Conditionally Adding Rules

Skipping Validation When Fields Have Certain Values

Es posible que desees no validar ocasionalmente un campo dado si otro campo tiene un valor dado. Puedes lograr esto usando la regla de validación exclude_if. En este ejemplo, los campos appointment_date y doctor_name no serán validados si el campo has_appointment tiene un valor de false:

use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_if:has_appointment,false|required|date',
    'doctor_name' => 'exclude_if:has_appointment,false|required|string',
]);

Alternativamente, puedes usar la regla exclude_unless para no validar un campo dado a menos que otro campo tenga un valor dado:

$validator = Validator::make($data, [
    'has_appointment' => 'required|boolean',
    'appointment_date' => 'exclude_unless:has_appointment,true|required|date',
    'doctor_name' => 'exclude_unless:has_appointment,true|required|string',
]);

Validando Cuando Está Presente

En algunas situaciones, es posible que desees realizar comprobaciones de validación en un campo solo si ese campo está presente en los datos que se están validando. Para lograr esto rápidamente, añade la regla sometimes a tu lista de reglas:

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

En el ejemplo anterior, el campo email solo se validará si está presente en el array $data.

ℹ️ Si estás intentando validar un campo que siempre debe estar presente pero puede estar vacío, consulta esta nota sobre campos opcionales.

Complex Conditional Validation

A veces es posible que desees agregar reglas de validación basadas en una lógica condicional más compleja. Por ejemplo, es posible que desees requerir un campo dado solo si otro campo tiene un valor mayor que 100. O, es posible que necesites que dos campos tengan un valor dado solo cuando otro campo esté presente. Agregar estas reglas de validación no tiene por qué ser un dolor. Primero, crea una instancia de Validator con tus reglas estáticas que nunca cambian:

use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make($request->all(), [
    '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 que explique por qué posee tantos juegos. Por ejemplo, quizás dirige una tienda de reventa de juegos, o tal vez simplemente disfruta coleccionando juegos. Para añadir este requisito de manera condicional, podemos usar el método sometimes en la instancia de Validator.

use Illuminate\Support\Fluent;
 
$validator->sometimes('reason', 'required|max:500', function (Fluent $input) {
    return $input->games >= 100;
});

El primer argumento pasado al método sometimes es el nombre del campo que estamos validando de forma condicional. El segundo argumento es una lista de las reglas que queremos agregar. Si la función anónima pasada como el tercer argumento devuelve true, se agregarán las reglas. Este método facilita la construcción de validaciones condicionales complejas. Incluso puedes agregar validaciones condicionales para varios campos a la vez:

use Illuminate\Support\Fluent;
 
$validator->sometimes('reason', 'required|max:500', function (Fluent $input) {
    return $input->games >= 100;
});

ℹ️ El parámetro $input pasado a tu función anónima será una instancia de Illuminate\Support\Fluent y se puede usar para acceder a tu entrada y archivos bajo validación.

Complex Conditional Array Validation

A veces es posible que desees validar un campo en función de otro campo en el mismo array anidado cuyo índice no conoces. En estas situaciones, puedes permitir que tu función anónima reciba un segundo argumento, que será el elemento individual actual en el array que se está validando:

$input = [
    'channels' => [
        [
            'type' => 'email',
            'address' => 'abigail@example.com',
        ],
        [
            'type' => 'url',
            'address' => 'https://example.com',
        ],
    ],
];
 
$validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) {
    return $item->type === 'email';
});
 
$validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) {
    return $item->type !== 'email';
});

Al igual que el parámetro $input pasado a la función anónima, el parámetro $item es una instancia de Illuminate\Support\Fluent cuando los datos del atributo son un array; de lo contrario, es una cadena.

Validating Arrays

Como se discutió en la documentación de la regla de validación array, la regla array acepta una lista de claves de array permitidas. Si se presentan claves adicionales dentro del array, la validación fallará:

use Illuminate\Support\Facades\Validator;
 
$input = [
    'user' => [
        'name' => 'Taylor Otwell',
        'username' => 'taylorotwell',
        'admin' => true,
    ],
];
 
Validator::make($input, [
    'user' => 'array:name,username',
]);

En general, siempre debes especificar las claves del array que se permiten dentro de tu array. De lo contrario, los métodos validate y validated del validador devolverán todos los datos validados, incluyendo el array y todas sus claves, incluso si esas claves no fueron validadas por otras reglas de validación de arrays anidados.

Validating Nested Array Input

Validar campos de entrada de formulario basados en arrays anidados no tiene por qué ser complicado. Puedes usar “notación de punto” para validar atributos dentro de un array. Por ejemplo, si la solicitud HTTP entrante contiene un campo photos[profile], puedes validarlo así:

use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

También puedes validar cada elemento de un array. Por ejemplo, para validar que cada correo electrónico en un campo de entrada de array dado sea único, puedes hacer lo siguiente:

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

Asimismo, puedes usar el carácter * al especificar mensajes de validación personalizados en tus archivos de idioma, facilitando el uso de un solo mensaje de validación para campos basados en arrays:

'custom' => [
    'person.*.email' => [
        'unique' => 'Each person must have a unique email address',
    ]
],

Accessing Nested Array Data

A veces es posible que necesites acceder al valor de un elemento de array anidado dado al asignar reglas de validación al atributo. Puedes lograr esto utilizando el método Rule::forEach. El método forEach acepta una función anónima que se invocará en cada iteración del atributo de array bajo validación y recibirá el valor del atributo y el nombre del atributo explícito y completamente expandido. La función anónima debe devolver un array de reglas para asignar al elemento del array:

use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
 
$validator = Validator::make($request->all(), [
    'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
        return [
            Rule::exists(Company::class, 'id'),
            new HasPermission('manage-company', $value),
        ];
    }),
]);

Error Message Indexes and Positions

Al validar arrays, es posible que desees hacer referencia al índice o posición de un elemento particular que no pasó la validación dentro del mensaje de error que muestra tu aplicación. Para lograr esto, puedes incluir los marcadores de posición :index (comienza desde 0) y :position (comienza desde 1) dentro de tu mensaje de validación personalizado:

use Illuminate\Support\Facades\Validator;
 
$input = [
    'photos' => [
        [
            'name' => 'BeachVacation.jpg',
            'description' => 'A photo of my beach vacation!',
        ],
        [
            'name' => 'GrandCanyon.jpg',
            'description' => '',
        ],
    ],
];
 
Validator::validate($input, [
    'photos.*.description' => 'required',
], [
    'photos.*.description.required' => 'Please describe photo #:position.',
]);

Dado el ejemplo anterior, la validación fallará y al usuario se le presentará el siguiente error: “Por favor describe la foto #2.” Si es necesario, puedes hacer referencia a índices y posiciones más profundamente anidados a través de second-indexsecond-positionthird-indexthird-position, etc.

'photos.*.attributes.*.string' => 'Invalid attribute for photo #:second-position.',

Validating Files

Laravel ofrece una variedad de reglas de validación que se pueden usar para validar archivos subidos, como mimesimagemin y max. Si bien puedes especificar estas reglas individualmente al validar archivos, Laravel también ofrece un constructor de reglas de validación de archivos fluido que te puede resultar conveniente:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;
 
Validator::validate($input, [
    'attachment' => [
        'required',
        File::types(['mp3', 'wav'])
            ->min(1024)
            ->max(12 * 1024),
    ],
]);

Si tu aplicación acepta imágenes subidas por tus usuarios, puedes usar el método constructor image de la regla File para indicar que el archivo subido debe ser una imagen. Además, se puede usar la regla dimensions para limitar las dimensiones de la imagen:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;
 
Validator::validate($input, [
    'photo' => [
        'required',
        File::image()
            ->min(1024)
            ->max(12 * 1024)
            ->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
    ],
]);

ℹ️ Más información sobre la validación de dimensiones de imagen se puede encontrar en la documentación de la regla de dimensiones.

Tamaños de archivos

Para mayor comodidad, los tamaños de archivo mínimos y máximos pueden especificarse como una cadena con un sufijo que indique las unidades de tamaño de archivo. Se admiten los sufijos kbmbgb y tb:

File::image()
    ->min('1kb')
    ->max('10mb')

File Types

Aunque solo necesitas especificar las extensiones al invocar el método types, este método en realidad valida el tipo MIME del archivo leyendo el contenido del archivo y adivinando su tipo MIME. Se puede encontrar una lista completa de tipos MIME y sus correspondientes extensiones en la siguiente ubicación: https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

Validating Passwords

Para asegurar que las contraseñas tengan un nivel de complejidad adecuado, puedes usar el objeto de regla Password de Laravel:

use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
 
$validator = Validator::make($request->all(), [
    'password' => ['required', 'confirmed', Password::min(8)],
]);

El objeto de regla Password te permite personalizar fácilmente los requisitos de complejidad de la contraseña para tu aplicación, como especificar que las contraseñas requieren al menos una letra, un número, un símbolo o caracteres con mayúsculas y minúsculas:

// Require at least 8 characters...
Password::min(8)
 
// Require at least one letter...
Password::min(8)->letters()
 
// Require at least one uppercase and one lowercase letter...
Password::min(8)->mixedCase()
 
// Require at least one number...
Password::min(8)->numbers()
 
// Require at least one symbol...
Password::min(8)->symbols()

Además, puedes asegurarte de que una contraseña no ha sido comprometida en una filtración de datos de contraseñas públicas utilizando el método uncompromised:

Password::min(8)->uncompromised()

Internamente, el objeto de regla Password utiliza el modelo de k-Anonimato para determinar si una contraseña ha sido filtrada a través del servicio haveibeenpwned.com sin sacrificar la privacidad o seguridad del usuario. Por defecto, si una contraseña aparece al menos una vez en una filtración de datos, se considerará comprometida. Puedes personalizar este umbral utilizando el primer argumento del método uncompromised:

// Ensure the password appears less than 3 times in the same data leak...
Password::min(8)->uncompromised(3);

Por supuesto, puedes encadenar todos los métodos en los ejemplos anteriores:

Password::min(8)
    ->letters()
    ->mixedCase()
    ->numbers()
    ->symbols()
    ->uncompromised()

Defining Default Password Rules

Puede que te resulte conveniente especificar las reglas de validación predeterminadas para las contraseñas en una sola ubicación de tu aplicación. Puedes lograr esto fácilmente utilizando el método Password::defaults, que acepta una función anónima. La función anónima dada al método defaults debe devolver la configuración predeterminada de la regla de Contraseña. Típicamente, la regla defaults debe ser llamada dentro del método boot de uno de los proveedores de servicios de tu aplicación:

use Illuminate\Validation\Rules\Password;
 
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Password::defaults(function () {
        $rule = Password::min(8);
 
        return $this->app->isProduction()
                    ? $rule->mixedCase()->uncompromised()
                    : $rule;
    });
}

Entonces, cuando desees aplicar las reglas predeterminadas a una contraseña particular que está siendo validada, puedes invocar el método defaults sin argumentos:

'password' => ['required', Password::defaults()],

Ocasionalmente, es posible que desees agregar reglas de validación adicionales a tus reglas de validación de contraseña predeterminadas. Puedes usar el método rules para lograr esto:

use App\Rules\ZxcvbnRule;
 
Password::defaults(function () {
    $rule = Password::min(8)->rules([new ZxcvbnRule]);
 
    // ...
});

Custom Validation Rules

Using Rule Objects

Laravel ofrece una variedad de reglas de validación útiles; sin embargo, es posible que desees especificar algunas de las tuyas. Un método para registrar reglas de validación personalizadas es utilizando objetos de regla. Para generar un nuevo objeto de regla, puedes usar el comando Artisan make:rule. Usemos este comando para generar una regla que verifique que una cadena esté en mayúsculas. Laravel colocará la nueva regla en el directorio app/Rules. Si este directorio no existe, Laravel lo creará cuando ejecutes el comando Artisan para crear tu regla:

php artisan make:rule Uppercase

Una vez que se haya creado la regla, estamos listos para definir su comportamiento. Un objeto de regla contiene un único método: validate. Este método recibe el nombre del atributo, su valor y un callback que debe invocarse en caso de fallo con el mensaje de error de validación:

<?php
 
namespace App\Rules;
 
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
 
class Uppercase implements ValidationRule
{
    /**
     * Run the validation rule.
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (strtoupper($value) !== $value) {
            $fail('The :attribute must be uppercase.');
        }
    }
}

Una vez que se ha definido la regla, puedes adjuntarla a un validador pasando una instancia del objeto de regla junto con tus otras reglas de validación:

use App\Rules\Uppercase;
 
$request->validate([
    'name' => ['required', 'string', new Uppercase],
]);

Traduciendo Mensajes de Validación

En lugar de proporcionar un mensaje de error literal a la función anónima $fail, también puedes proporcionar una clave de cadena de traducción e instruir a Laravel para que traduzca el mensaje de error:

if (strtoupper($value) !== $value) {
    $fail('validation.uppercase')->translate();
}

Si es necesario, puedes proporcionar reemplazos de marcador de posición y el idioma preferido como el primer y segundo argumento al método translate:

$fail('validation.location')->translate([
    'value' => $this->value,
], 'fr')

Accessing Additional Data

Si la clase de regla de validación personalizada necesita acceder a todos los otros datos que están siendo validados, tu clase de regla puede implementar la interfaz Illuminate\Contracts\Validation\DataAwareRule. Esta interfaz requiere que tu clase defina un método setData. Este método será invocado automáticamente por Laravel (antes de que se realice la validación) con todos los datos bajo validación:

<?php
 
namespace App\Rules;
 
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
 
class Uppercase implements DataAwareRule, ValidationRule
{
    /**
     * All of the data under validation.
     *
     * @var array<string, mixed>
     */
    protected $data = [];
 
    // ...
 
    /**
     * Set the data under validation.
     *
     * @param  array<string, mixed>  $data
     */
    public function setData(array $data): static
    {
        $this->data = $data;
 
        return $this;
    }
}

O, si tu regla de validación requiere acceso a la instancia del validador que está realizando la validación, puedes implementar la interfaz ValidatorAwareRule:

<?php
 
namespace App\Rules;
 
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Validation\Validator;
 
class Uppercase implements ValidationRule, ValidatorAwareRule
{
    /**
     * The validator instance.
     *
     * @var \Illuminate\Validation\Validator
     */
    protected $validator;
 
    // ...
 
    /**
     * Set the current validator.
     */
    public function setValidator(Validator $validator): static
    {
        $this->validator = $validator;
 
        return $this;
    }
}

Using Closures

Si solo necesitas la funcionalidad de una regla personalizada una vez en toda tu aplicación, puedes usar una función anónima en lugar de un objeto de regla. La función anónima recibe el nombre del atributo, el valor del atributo y un callback $fail que debe ser llamado si la validación falla:

use Illuminate\Support\Facades\Validator;
use Closure;
 
$validator = Validator::make($request->all(), [
    'title' => [
        'required',
        'max:255',
        function (string $attribute, mixed $value, Closure $fail) {
            if ($value === 'foo') {
                $fail("The {$attribute} is invalid.");
            }
        },
    ],
]);

Implicit Rules

Por defecto, cuando un atributo que se está validando no está presente o contiene una cadena vacía, las reglas de validación normales, incluidas las reglas personalizadas, no se ejecutan. Por ejemplo, la regla unique no se aplicará a una cadena vacía:

use Illuminate\Support\Facades\Validator;
 
$rules = ['name' => 'unique:users,name'];
 
$input = ['name' => ''];
 
Validator::make($input, $rules)->passes(); // true

Para que una regla personalizada se ejecute incluso cuando un atributo está vacío, la regla debe implicar que el atributo es obligatorio. Para generar rápidamente un nuevo objeto de regla implícita, puedes usar el comando Artisan make:rule con la opción --implicit:

php artisan make:rule Uppercase --implicit

❗ Una regla “implícita” solo implica que el atributo es obligatorio. Si realmente invalida un atributo faltante o vacío depende de ti. Es decir solo tiene la regla “required”.