Curso de Laravel
Validación de formularios en Laravel
Por Víctor Peña · Publicado el
Hola, ¿cómo están? Cerramos el módulo de la aplicación web con la validación de formularios.
Es la frontera entre tu sistema y todo lo que no controlas, así que conviene tratarla con seriedad.
¡Empecemos!
Validar en el controlador
La forma más directa:
public function store(Request $request)
{
$datos = $request->validate([
'cedula' => 'required|string|max:20|unique:pacientes',
'nombre' => 'required|string|max:100',
'apellido' => 'required|string|max:100',
'fecha_nacimiento' => 'required|date|before:today',
'correo' => 'nullable|email|max:255',
'telefono' => 'nullable|string|max:20',
]);
Paciente::create($datos);
return redirect()->route('pacientes.index')
->with('exito', 'Paciente registrado');
}
Aquí ocurren tres cosas que conviene entender:
Si la validación falla, Laravel detiene la ejecución, redirige al formulario anterior con los errores y con los datos que el usuario escribió. No tienes que hacer nada.
Si pasa, validate() devuelve solo los campos validados. Eso es importante: si alguien añade un campo rol a la petición, no llega al create().
Los datos devueltos son seguros para asignación masiva, porque son exactamente los que declaraste.
Por eso conviene usar $datos y no $request->all().
Las reglas más usadas
'required' // obligatorio
'nullable' // puede venir vacío
'string'
'integer'
'numeric'
'boolean'
'array'
'email'
'url'
'date'
'image'
'file'
'max:100' // longitud o valor máximo
'min:3'
'between:1,10'
'size:8'
'unique:pacientes' // no existe en esa tabla
'unique:pacientes,cedula'
'exists:doctores,id' // sí existe
'confirmed' // debe coincidir con campo_confirmation
'same:otro_campo'
'different:otro_campo'
'in:programada,atendida,cancelada'
'not_in:admin'
'before:today'
'after:2026-01-01'
'after_or_equal:fecha_inicio'
'regex:/^[0-9]{7,8}$/'
Se pueden escribir como texto separado por barras o como arreglo, que es más legible cuando son muchas:
'cedula' => ['required', 'string', 'max:20', 'unique:pacientes'],
Y para ver todas las disponibles, la documentación oficial de validación es de las mejores páginas del framework.
Form Requests: sacar la validación del controlador
Cuando las reglas crecen, el controlador se llena. La solución del framework es una clase aparte:
php artisan make:request GuardarPacienteRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class GuardarPacienteRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'cedula' => ['required', 'string', 'max:20', 'unique:pacientes'],
'nombre' => ['required', 'string', 'max:100'],
'apellido' => ['required', 'string', 'max:100'],
'fecha_nacimiento' => ['required', 'date', 'before:today'],
'correo' => ['nullable', 'email', 'max:255'],
];
}
public function messages(): array
{
return [
'cedula.unique' => 'Ya existe un paciente con esa cédula.',
'fecha_nacimiento.before' => 'La fecha de nacimiento no puede ser futura.',
];
}
public function attributes(): array
{
return [
'fecha_nacimiento' => 'fecha de nacimiento',
];
}
}
Y el controlador queda así:
public function store(GuardarPacienteRequest $request)
{
Paciente::create($request->validated());
return redirect()->route('pacientes.index')
->with('exito', 'Paciente registrado');
}
Dos líneas. La validación se ejecuta antes de entrar al método, así que si llegas ahí es porque los datos son correctos.
Esto es lo que mencionábamos en la lección de controladores sobre mantenerlos delgados.
El método authorize
Ese método decide quién puede hacer la petición:
public function authorize(): bool
{
return $this->user()->esAdmin();
}
Si devuelve false, Laravel responde con un 403 antes de validar nada. Lo veremos a fondo en la lección de autorización.
Mostrar los errores en Blade
Un resumen general:
@if ($errors->any())
<div class="alerta-error">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
O por campo, que es lo recomendable porque el usuario ve el error junto al campo que debe corregir:
<input type="text" name="cedula" value="{{ old('cedula') }}"
class="@error('cedula') campo-error @enderror">
@error('cedula')
<span class="mensaje-error">{{ $message }}</span>
@enderror
old('cedula') es imprescindible. Sin él, el formulario se vacía al fallar la validación y el usuario tiene que reescribirlo todo. Es de las cosas que más molestan de un sistema mal hecho.
Si construiste el componente de campo de la lección anterior, todo esto ya está resuelto dentro y no lo repites nunca más.
Traducir los mensajes
Por defecto los mensajes vienen en inglés. Para tenerlos en español:
php artisan lang:publish
Eso crea lang/en/validation.php. Copia la carpeta a lang/es/, traduce los mensajes y cambia el idioma en config/app.php:
'locale' => 'es',
Lo desarrollamos en la lección de traducir mensajes.
Validación en la actualización
Aquí hay un detalle que hace fallar a mucha gente.
La regla unique falla al editar, porque el propio registro ya tiene esa cédula. Hay que excluirlo:
use Illuminate\Validation\Rule;
public function rules(): array
{
return [
'cedula' => [
'required',
'max:20',
Rule::unique('pacientes')->ignore($this->paciente),
],
];
}
Ese $this->paciente es el modelo que llega por la vinculación de rutas.
Lo habitual es tener dos Form Requests, GuardarPacienteRequest y ActualizarPacienteRequest, precisamente por esta diferencia.
Validación condicional
Cuando una regla depende de otro campo:
public function rules(): array
{
return [
'tipo_pago' => ['required', 'in:efectivo,tarjeta'],
'numero_tarjeta' => ['required_if:tipo_pago,tarjeta', 'digits:16'],
'observaciones' => ['required_without:diagnostico'],
];
}
Y para casos más complejos:
public function withValidator($validator): void
{
$validator->sometimes('descuento', 'max:20', function ($datos) {
return $datos->total < 1000;
});
}
Validar arreglos
Para formularios con varios elementos, como las líneas de una factura:
'items' => ['required', 'array', 'min:1'],
'items.*.producto_id' => ['required', 'exists:productos,id'],
'items.*.cantidad' => ['required', 'integer', 'min:1'],
El * aplica la regla a cada elemento del arreglo.
Reglas personalizadas
Cuando necesitas una validación propia:
php artisan make:rule CedulaBoliviana
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! preg_match('/^\d{6,8}(-[A-Z]{2})?$/', $value)) {
$fail('El campo :attribute no tiene un formato de cédula válido.');
}
}
'cedula' => ['required', new CedulaBoliviana],
Para casos simples también sirve una función anónima directamente en las reglas.
Validar en una API
Cuando la petición espera JSON, Laravel devuelve los errores en JSON con código 422 automáticamente:
{
"message": "The given data was invalid.",
"errors": {
"cedula": ["El campo cédula es obligatorio."]
}
}
No hay que cambiar nada: el mismo Form Request sirve para web y para API.
La regla que no cambia
Como advertimos en el curso de PHP: la validación del navegador no cuenta.
Los atributos required, type="email" y pattern mejoran la experiencia del usuario, pero cualquiera puede saltárselos enviando la petición desde otra herramienta.
Toda validación del cliente debe repetirse en el servidor. La del navegador es comodidad; la de Laravel es seguridad.
Errores comunes
- Usar
$request->all()en lugar de los datos validados. - Olvidar
old()y vaciar el formulario al fallar. uniquesin excluir el registro al actualizar.- Validar a mano con
ifen lugar de usar las reglas. - Confiar en la validación del navegador.
- Reglas larguísimas en el controlador en vez de un Form Request.
Para cerrar
La validación es lo que impide que datos incorrectos entren a tu sistema, y Laravel la resuelve con muy poco código.
Los dos hábitos: Form Request en cuanto pases de cuatro reglas, y usar siempre validated() en lugar de all().
Con esto cerramos el módulo. En la siguiente lección juntamos rutas, controladores, Blade y validación en un CRUD completo.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp