Beetje Coderen

Les 5 · Module 1 · Laravel-basis

Formulieren en validatie

Verwerk formulieren veilig in de kassa: CSRF-tokens, valideren met regels, foutmeldingen per veld, old()-waarden, Form Requests en flash-berichten na opslaan.

⏱ 90 minuten leestijd + oefenen

Illustratie: een formulier naast een groen schild met vinkje, gecontroleerde invoer

🎯 Na deze les kun je

  • een formulier met @csrf naar een POST-route sturen
  • invoer valideren met $request->validate en regels
  • foutmeldingen en oude waarden tonen met @error en old()
  • validatie verplaatsen naar een Form Request

De kassa moet producten op een bon kunnen zetten via een formulier. Dat betekent: invoer van gebruikers, en dus nooit vertrouwen. Laravel maakt het juiste patroon kort: valideren in één regel, bij een fout automatisch terug naar het formulier met de meldingen, en bij succes doorsturen met een bericht.

Het formulier

<x-layout titel="Product toevoegen">
  <form method="POST" action="{{ route('kassa.toevoegen') }}">
    @csrf
    <x-veld naam="product" label="Product" />
    <x-veld naam="prijs" label="Prijs" inputmode="decimal" />
    <x-veld naam="aantal" label="Aantal" type="number" />
    <button>Toevoegen</button>
  </form>
</x-layout>

@csrf zet een verborgen veld _token in het formulier. Zonder dat token weigert Laravel elke POST, PUT of DELETE met 419 Page Expired. Dat beschermt tegen CSRF: een andere site kan het token niet lezen.

Valideren

public function toevoegen(Request $request)
{
    $data = $request->validate([
        'product' => ['required', 'string', 'max:40'],
        'prijs'   => ['required', 'decimal:0,2', 'min:0', 'max:999'],
        'aantal'  => ['nullable', 'integer', 'between:1,99'],
    ]);

    $bon = $request->session()->get('bon', []);
    $bon[] = ['naam' => $data['product'], 'prijs' => (float) $data['prijs'], 'aantal' => $data['aantal'] ?? 1];
    $request->session()->put('bon', $bon);

    return redirect()->route('kassa.bon')->with('status', "{$data['product']} staat op de bon.");
}
  • validate() geeft alleen de gevalideerde velden terug. Een extra veld korting=100 dat iemand meestuurt, zit er niet in.
  • Faalt een regel, dan gooit Laravel een ValidationException: de gebruiker gaat terug naar het formulier, met de fouten en de oude invoer in de sessie. Je code na validate() draait dan niet.
  • Na succes: redirect (Post/Redirect/Get) met een flash-bericht via with().

De bon staat voorlopig in de sessie; in les 9 komt hij in de database.

Voorspel eerst: je stuurt prijs=2,80. Slaagt de regel decimal:0,2?

Uitkomst

Nee: decimal verwacht een punt. Je krijgt de melding "The prijs field must have 0-2 decimal places." Oplossing: vervang de komma vóór het valideren (zie de Form Request hieronder), of vertel de gebruiker een punt te gebruiken. Nederlandse meldingen krijg je met php artisan lang:publish en een vertaalpakket, of door eigen meldingen mee te geven.

Fouten en oude waarden tonen

In de component veld uit les 3 zat dit al:

<input name="{{ $naam }}" value="{{ old($naam) }}">
@error($naam)<span class="fout">{{ $message }}</span>@enderror

En het flash-bericht in de layout:

@if (session('status'))
  <p class="melding">{{ session('status') }}</p>
@endif

Form Requests

Groeit de validatie, verplaats hem dan naar een eigen klasse:

php artisan make:request BonRegelRequest
class BonRegelRequest extends FormRequest
{
    public function authorize(): bool { return true; }       // les 11

    protected function prepareForValidation(): void
    {
        $this->merge(['prijs' => str_replace(',', '.', (string) $this->input('prijs'))]);
    }

    public function rules(): array
    {
        return [
            'product' => ['required', 'string', 'max:40'],
            'prijs'   => ['required', 'decimal:0,2', 'min:0'],
            'aantal'  => ['nullable', 'integer', 'between:1,99'],
        ];
    }

    public function messages(): array
    {
        return ['product.required' => 'Vul een product in.', 'prijs.decimal' => 'Gebruik een bedrag zoals 2,80.'];
    }
}
public function toevoegen(BonRegelRequest $request)
{
    $data = $request->validated();
    ...
}

De container (les 4) maakt de request en valideert hem voordat je methode start.

Typische fouten

  • 419 Page Expired: @csrf vergeten, of de sessie is verlopen.
  • Fouten verschijnen niet: je toont $errors niet, of je stuurt zelf een return view(...) in plaats van de automatische redirect.
  • MethodNotAllowedHttpException (405): het formulier is POST, de route GET.

Oefenen

  1. Bouw het formulier en toevoegen met $request->validate(); toon de bon uit de sessie op /kassa/bon.
  2. Verplaats de validatie naar BonRegelRequest met Nederlandse meldingen en accepteer een komma.
  3. Maak POST /kassa/bon/leeg die de bon leegmaakt, met een knop en @csrf.
  4. Voeg een regel toe die het product test weigert (Rule::notIn(['test'])) en controleer het met curl zonder token: wat krijg je?
Modelantwoord oefening 1
public function bon(Request $request)
{
    $bon = collect($request->session()->get('bon', []));
    $totaal = $bon->sum(fn ($r) => $r['prijs'] * $r['aantal']);
    return view('kassa.bon', compact('bon', 'totaal'));
}

collect() maakt een Laravel-collection: een array met handige methodes zoals sum, map en isEmpty.

Modelantwoord oefening 2

Zie de Form Request hierboven. Test met 2,80 (geldig), 2,805 (te veel decimalen) en leeg (verplicht).

Modelantwoord oefening 3
Route::post('/bon/leeg', function (Request $request) {
    $request->session()->forget('bon');
    return redirect()->route('kassa.bon')->with('status', 'De bon is leeg.');
})->name('leeg');
Modelantwoord oefening 4
'product' => ['required', 'string', 'max:40', Rule::notIn(['test'])],

curl -i -X POST -d "product=koffie" http://127.0.0.1:8000/kassa/bon/regels geeft 419: zonder CSRF-token komt het verzoek niet eens bij de validatie. Validatie test je dus in de browser of in een feature-test (les 16).

Lokaal oefenen

Geen live lab. Zet novalidate op je formulier om de servervalidatie in de browser te zien.

Samenvatting

  • @csrf in elk formulier; validate() geeft alleen gevalideerde velden en stuurt bij fouten automatisch terug.
  • @error, $message en old() tonen fouten en oude invoer; with() geeft een flash-bericht.
  • Form Requests bundelen regels, meldingen en voorbewerking.
  • Volgende les: configuratie, .env en artisan.

📝 Quiz: Formulieren en validatie

5 vragen · 70% nodig om te slagen

1. Wat gebeurt er bij een POST zonder @csrf?
2. Wat geeft $request->validate([...]) terug?
3. Wat gebeurt er als een validatieregel faalt?
4. Waarvoor dient prepareForValidation in een Form Request?
5. Waarmee toon je de vorige invoer in een veld na een fout?

Dit was de laatste gratis les

Je hebt les 1–5 van Webapps met Laravel gratis gevolgd. Wil je verder? Met één aankoop (€ 49,00, eenmalig) krijg je de overige 15 lessen, de live labs en het certificaat. Geen abonnement.

Cursus kopen en verdergaan