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.
🎯 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 veldkorting=100dat 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 navalidate()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:
@csrfvergeten, of de sessie is verlopen. - Fouten verschijnen niet: je toont
$errorsniet, of je stuurt zelf eenreturn view(...)in plaats van de automatische redirect. MethodNotAllowedHttpException(405): het formulier isPOST, de routeGET.
Oefenen
- Bouw het formulier en
toevoegenmet$request->validate(); toon de bon uit de sessie op/kassa/bon. - Verplaats de validatie naar
BonRegelRequestmet Nederlandse meldingen en accepteer een komma. - Maak
POST /kassa/bon/leegdie de bon leegmaakt, met een knop en@csrf. - Voeg een regel toe die het product
testweigert (Rule::notIn(['test'])) en controleer het metcurlzonder 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
@csrfin elk formulier;validate()geeft alleen gevalideerde velden en stuurt bij fouten automatisch terug.@error,$messageenold()tonen fouten en oude invoer;with()geeft een flash-bericht.- Form Requests bundelen regels, meldingen en voorbewerking.
- Volgende les: configuratie,
.enven artisan.
📝 Quiz: Formulieren en validatie
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.