Tutorial Laravel 10 - Part #9 - Input Validation

Dalam membuat aplikasi, proses validasi input sangat penting dilakukan agar data yang masuk sesuai dengan yang kita harapkan. Proses validasi di Laravel sangat dimudahkan dengan fitur Validation yang lengkap dan sudah mencakup case-case validasi yang sering dibutuhkan dalam pembuatan aplikasi.

Sebelum kita memulai membahas tentang Input Validation di Laravel, saya asumsikan bahwa Anda telah menginstall project laravel dari awal dan juga telah melakukan konfigurasi database. Jika belum, Anda dapat mengikuti Tutorial Instalasi Laravel 10 yang telah diposting sebelumnya.

Membuat Route

Buka file routes/web.php dan tambahkan routing berikut:

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

Route pertama products/create dengan tipe GET adalah untuk menampilkan form tambah product, sedangan route kedua products dengan tipe POST adalah untuk menghandle ketika form tambah product disubmit.

Membuat Controller

Buat controller ProductController dengan perintah:

php artisan make:controller ProductController

Kemudian tambahkan method create dan store di dalamnya, sehingga menjadi seperti berikut:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class ProductController extends Controller
{

    public function create(): Response
    {
        return response(view('products.create'));
    }

    public function store(Request $request): RedirectResponse
    {

    }
}

Membuat View untuk Form Create Product

Buat file view untuk form create resources/views/products/create.blade.php dengan kode html sederhana seperti berikut:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>My App</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
  </head>
  <body>
    <div id="app">
      <div class="main-wrapper">
        <div class="main-content">
          <div class="container">
            <form method="post" action="{{ route('products.store') }}">
              @csrf
              <div class="card mt-5">
                <div class="card-header">
                  <h3>New Product</h3>
                </div>
                <div class="card-body">
                    @if ($errors->any())
                      <div class="alert alert-danger">
                        <div class="alert-title"><h4>Whoops!</h4></div>
                          There are some problems with your input.
                          <ul>
                            @foreach ($errors->all() as $error)
                              <li>{{ $error }}</li>
                            @endforeach
                          </ul>
                      </div> 
                    @endif

                    @if (session('success'))
                      <div class="alert alert-success">{{ session('success') }}</div>
                    @endif

                    @if (session('error'))
                      <div class="alert alert-danger">{{ session('error') }}</div>
                    @endif
                    <div class="mb-3">
                      <label class="form-label">SKU</label>
                      <input type="text" class="form-control" name="sku" value="{{ old('sku') }}" placeholder="#SKU">
                    </div>
                    <div class="mb-3">
                      <label class="form-label">Name</label>
                      <input type="text" class="form-control" name="name" value="{{ old('name') }}"  placeholder="Name">
                    </div>
                    <div class="mb-3">
                      <label class="form-label">Price</label>
                      <input type="text" class="form-control" name="price" value="{{ old('price') }}"  placeholder="Price">
                    </div>
                    <div class="mb-3">
                      <label class="form-label">Stock</label>
                      <input type="text" class="form-control" name="stock" value="{{ old('stock') }}"  placeholder="Stock">
                    </div>
                </div>
                <div class="card-footer">
                  <button class="btn btn-primary" type="submit">Create</button>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

Block baris kode mulai dari @if ($errors->any()) sampai @endif adalah untuk menampilkan error jika inputan tidak lolos validasi.

Membuat Validasi Input di Controller

Sekarang kita dapat menambahkan validasi pada method store yang ada pada ProductController dengan menggunakan method validate yang ada pada class Illuminate\Http\Request sehingga menjadi seperti berikut:

public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'sku' => ['required', 'unique:products', 'max:100'],
            'name' => ['required', 'max:100'],
            'price' => ['required', 'numeric', 'min:1'],
            'stock' => ['required', 'numeric', 'min:0'],
        ]);

        dd('store');
    }

Alternatif lain, kita juga dapat membuat validator manual dengan Validator Facade seperti berikut:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;

class ProductController extends Controller
{

    public function create(): Response
    {
        return response(view('products.create'));
    }

    public function store(Request $request): RedirectResponse
    {
        $validator = Validator::make($request->all(), [
            'sku' => ['required', 'unique:products', 'max:100'],
            'name' => ['required', 'max:100'],
            'price' => ['required', 'numeric', 'min:1'],
            'stock' => ['required', 'numeric', 'min:0'],
        ]);

        if ($validator->fails()) {
            return redirect('products/create')
                        ->withErrors($validator)
                        ->withInput();
        }
 
        // Retrieve the validated input...
        $validated = $validator->validated();
        dd($validated);
    }
}

Untuk mempelajari validation rule yang lain, kita dapat membuka dokumentasi resminya di sini

Mencoba Validasi Input Product

Jalankan project laravel dengan perintah php artisan serve kemudian buka url http://localhost:8000/products/create. Jika tidak ada kendala, tampilan form dan error validasi kurang lebih akan seperti berikut:

Membuat Validasi Input dengan Form Request

Ketika validasi inputnya masih sederhana, kita bisa menggunakan konsep validasi di controller seperti yang sudah dibahas di atas. Akan tetapi, untuk validasi input yang kompleks, sangat di rekomendasikan menggunakan validasi Form Request. Selain menjaga kode program di controller tetap ramping, kita juga kan lebih mudah untuk maintenance logic validasi dikemudian hari karena dibuat di tempat tersendiri.

Untuk membuat class Form Request jalankan perintah berikut:

php artisan make:request StoreProductRequest

Perintah di atas akan membuat file app/Http/Requests/StoreProductRequest.php. Lakukan modifikasi menjadi seperti berikut:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, mixed>
     */
    public function rules(): array
    {
        return [
            'sku' => ['required', 'unique:products', 'max:100'],
            'name' => ['required', 'max:100'],
            'price' => ['required', 'numeric', 'min:1'],
            'stock' => ['required', 'numeric', 'min:0'],
        ];
    }
}

Selanjutnya kita perlu menginject method store pada ProductController dengan StoreProductRequest yang telah kita buat sehingga menjadi seperti berikut:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\StoreProductRequest;

class ProductController extends Controller
{

    public function create(): Response
    {
        return response(view('products.create'));
    }

    public function store(StoreProductRequest $request): RedirectResponse
    {
        return $request->all();
    }
}

Terlihat lebih clean kan bagian controller? Yeah, selamat mencoba!

Tulis Komentar