Tabla de Contenidos
Trabajando con formularios en Laravel
Crear formulario
Si queremos crear un formulario que nos permita añadir un producto, vamos al controlador y nos centramos en el método create:
public function create() { return view("products.create"); }
Crearemos una vista 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" required>
</div>
<div class="form-row">
<label>Description</label>
<input class="form-control" type="text" name="description" required>
</div>
<div class="form-row">
<label>Price</label>
<input class="form-control" type="number" min="1.00" step="0.01" name="price" required>
</div>
<div class="form-row">
<label>Stock</label>
<input class="form-control" type="number" min="0" name="stock" required>
</div>
<div class="form-row">
<label>Status</label>
<select class="custom-select" name="status" required>
<option value="" selected>Select...</option>
<option value="available">Available</option>
<option value="unavailable">Unavailable</option>
</select>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary btn-lg">Create product</button>
</div>
</form>
Recordemos que tenemos estas rutas en routes/web.php para este caso:
Route::get("products/create", "ProductController@create")->name("products.create"); Route::post("products", "ProductController@store")->name("products.store");
Por tanto, cuando se envíe el formulario, se llamará al método store del ProductController mediante POST:
public function store() { dd("Estamos en store"); }
Esto no nos funcionará porque, por defecto, Laravel tiene protección contra CSRF (Cross-site request forgery). Se asegura que las peticiones que se hagan a nuestra web, vengan realmente de nuestra web.
Para solucionarlo, en nuestros formularios debemos añadir un token CSRF:
@extends("layout.master")
@section("content")
<h1>Create a product</h1>
<form method="post" action="{{ route("products.store" }}">
@csrf
Esa instrucción de Blade incluye un campo HTML oculto en el formulario:
<form method="post" action=""> <input type="hidden" name="_token" value="123h4jkl123khxvbnasd12"
Datos provenientes de formularios
Vamos a crear (almacenar) un producto a partir de la información recibida desde un formulario:
public function store() { $product = Product::create([ 'title' => request()->title, 'description' => request()->description, 'price' => request()->price, 'stock' => request()->stock, 'status' => request()->status, ]); return $product; }
Veremos un string JSON con el producto creado a través del formulario.
Versión abreviada cogiendo todo lo que llegue de un formulario:
public function store() { $product = Product::create(request()->all()); return $product; }
Los atributos que se asignarán a nuestro modelo a partir del formulario serán los que hayamos indicado en el array de $fillable.
Editando desde un formulario
Los métodos que modificaremos en nuestro ProductController serán edit y update. Uno mostrará el formulario de edición del producto y el otro hará efectiva la actualización.
public function edit($product) { return view("products.edit")->with([ "product" => Product::findOrFail($product), ]); } public function update($product) { }
Recordemos las rutas:
Route::get("products/{$product}/edit", "ProductController@edit")->name("products.edit"); Route::match(["put", "patch"], "products/{$product}", "ProductController@update")->name("products.update");
Para el formulario de edición, creamos la vista resources/views/products/edit.blade.php:
@extends("layout.master")
@section("content")
<h1>Edit a product</h1>
<form method="post" action="{{ route("products.update", ["product" => $product->id]) }}">
@csrf
@method("PUT")
<div class="form-row">
<label>Title</label>
<input class="form-control" type="text" name="title" value="{{ $product->title }}" required>
</div>
<div class="form-row">
<label>Description</label>
<input class="form-control" type="text" name="description" value="{{ $product->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="{{ $product->price }} required>
</div>
<div class="form-row">
<label>Stock</label>
<input class="form-control" type="number" min="0" name="stock" value="{{ $product->stock }} required>
</div>
<div class="form-row">
<label>Status</label>
<select class="custom-select" name="status" required>
<option {{ $product->status == "available" ? "selected" : "" }} value="available">Available</option>
<option {{ $product->status == "unavailable" ? "selected" : "" }} value="unavailable">Unavailable</option>
</select>
</div>
<div class="form-row">
<button type="submit" class="btn btn-primary btn-lg">Edit product</button>
</div>
</form>
Los navegadores solo procesan GET y POST, así que para forzar un tipo de petición, usamos @method que añadirá una etiqueta input oculta con el valor que le pasemos.
Para realizar la actualización del producto, en el controlador:
public function update($product) { $product = Product::findOrFail($product); $product->update(request()->all()); return $product; }
Eliminar de la base de datos
En Laravel tenemos que usar un formulario también para eliminar productos. En nuestro controlador, modificaremos el método destroy:
public function destroy($product) { $product = Product::findOrFail($product); $product->delete(); }
Recordemos que debe existir una ruta:
Route::delete("products/{product}", "ProductController@destroy")->name("products.destroy");
Finalmente, para dar la opción de eliminar un producto, basta con crear un enlace, pero debe ser usando el método DELETE:
<form method="post" action="{{ route("products.destroy", ["product" => product->id]) }}"> @csrf @method("DELETE") <button type="submit" class="btn btn-link">Delete</button> </form>
