Tabla de Contenidos
Validación de información en Laravel
Siempre en el backend hay que realizar las validaciones para asegurar la consistencia y estabilidad de la información.
Reglas y validación
public function store() { // definimos las reglas $rules = [ "title" => ["required", "max:255"], "description" => ["required", "max:1000"], "price" => ["required", "min:1"], "stock" => ["required", "min:0"], "status" => ["required", "in:available,unavailable"], ]; // validaciones request()->validate($rules); if (request()->status == 'available' && request()->stock == 0) { session()->flash("error", "If available must have stock"); // Volveremos para atrás, pero sin perder los elementos // que enviamos por el formulario return redirect() ->back() ->withInput(request()->all()); } $product = Product::create(request()->all()); return redirect()->route("products.index"); }
Cuando no se cumplan las reglas, Laravel no permitirá los cambios y nos volverá al punto de partida.
Como los errores de validación no se muestra por defecto,
Centralizando validaciones: FormRequest
Una forma más elegante de realizar validaciones.
php artisan make:request ProductRequest
Se creará una carpeta app/Http/Requests/ con un fichero ProductRequest.php:
public function authorize() { return true; // Inicialmente viene a 'false' } // Aquí ponemos las reglas (ya no es necesario hacerlo en los métodos de 'ProductController.php') public function rules() { return [ "title" => ["required", "max:255"], "description" => ["required", "max:1000"], "price" => ["required", "min:1"], "stock" => ["required", "min:0"], "status" => ["required", "in:available,unavailable"], ]; } // Creamos el siguiente método: public function withValidator($validator) { $validator->after(function($validator) { if ($this->status == "available" && $this->stock == 0) { $validator->errors()->add("stock", "If available must have stock") } }); }
Ahora, usando la inyección de dependencias, vamos a ProductController.php:
// code use App\Http\Requests\ProductRequest; // code public function store(ProductRequest $request) { // Creamos el producto solo con los atributos validados. $product = Product::create($request->validated()); return redirect() ->route("products.index") ->withSuccess("The new product with id {$product->id} was created"); } public function update(ProductRequest $request, Product $product) { $product->update($request->validated()); return redirect() ->route("products.index") ->withSuccess("The product with id {$product->id} was edited"); }
Mostrando errores de validación
Laravel maneja una variable global llamada $errors que utiliza para almacenar mensajes de error.
resources/views/layouts/master.blade.php:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Laravel Shop</title> </head> <body> @if (session()->has("error")) <div class="alert alert-danger"> {{ session()->get("error") }} </div> @endif @if (isset($errors) && $errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> </ul> </div> @endif @yield('content') </body> </html>
Reutilizar valores enviados en un formulario inválido
Usamos el helper old() para obtener el valor que indicó el usuario en el formulario antes de obtener el error.
resources/views/products/create.blade.php:
@extends("layout.master")
@section("content")
<h1>Create a product</h1>
<form method="post" action="{{ route("products.store" }}">
<div class="form-row">
<label>Title</label>
<input class="form-control" type="text" name="title" value="{{ old("title") }}" required>
</div>
<div class="form-row">
<label>Description</label>
<input class="form-control" type="text" name="description" value="{{ old("description") }}" required>
</div>
<div class="form-row">
<label>Price</label>
<input class="form-control" type="number" min="1.00" step="0.01" name="price" value="{{ old("price") }}" required>
</div>
<div class="form-row">
<label>Stock</label>
<input class="form-control" type="number" min="0" name="stock" value="{{ old("stock") }}" required>
</div>
<div class="form-row">
<label>Status</label>
<select class="custom-select" name="status" required>
<option value="" selected>Select...</option>
<option {{ old("status") == "available" ? "selected" : "" }} value="available">Available</option>
<option {{ old("status") == "unavailable" ? "selected" : "" }} value="unavailable">Unavailable</option>
</select>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary btn-lg">Create product</button>
</div>
</form>
A partir de ahora, cuando haya un error de validación al enviar el formulario, los elementos que sí pasen la validación, aparecerán en los campos del formulario. Los que no validan, quedarán vacios.
