Beetje Coderen

Les 2 · Module 1 · Laravel-basis

Routes en controllers

Verplaats de logica van de kassa uit routes/web.php naar controllers: routeparameters, benoemde routes, resource-controllers en route-groepen.

⏱ 75 minuten leestijd + oefenen

Illustratie: een browservenster stuurt via pijlen verzoeken naar een server, routes die naar controllers leiden

🎯 Na deze les kun je

  • een controller maken met artisan en routes eraan koppelen
  • benoemde routes gebruiken met route()
  • een resource-controller voor CRUD-routes aanmaken
  • routes groeperen met prefix en name

In les 1 stond je code direct in routes/web.php. Met drie routes gaat dat, met dertig niet: het routebestand wordt een rommelbak. Laravel scheidt daarom welke URL (de route) van wat er gebeurt (de controller). Een controller is een gewone PHP-klasse met een methode per actie.

Je eerste controller

php artisan make:controller KassaController
// app/Http/Controllers/KassaController.php
namespace App\Http\Controllers;

class KassaController extends Controller
{
    public function totaal(int $bedrag)
    {
        $btw = round($bedrag * 0.21, 2);
        return view('kassa.totaal', compact('bedrag', 'btw'));
    }
}
// routes/web.php
use App\Http\Controllers\KassaController;

Route::get('/totaal/{bedrag}', [KassaController::class, 'totaal'])
    ->whereNumber('bedrag')
    ->name('kassa.totaal');

view('kassa.totaal') zoekt resources/views/kassa/totaal.blade.php: de punt is een map. compact('bedrag', 'btw') maakt ['bedrag' => $bedrag, 'btw' => $btw].

Benoemde routes

Met ->name('kassa.totaal') geef je de route een naam. Links maak je dan met route():

<a href="{{ route('kassa.totaal', ['bedrag' => 50]) }}">Totaal van 50</a>

Verander je later de URL in /kassa/totaal/{bedrag}, dan blijven alle links werken.

Voorspel eerst: wat geeft route('kassa.totaal', ['bedrag' => 50, 'fooi' => 10])?

Uitkomst

http://127.0.0.1:8000/totaal/50?fooi=10. Parameters die in de route staan gaan in het pad, de rest wordt een query-string. Vergeet je bedrag, dan krijg je een UrlGenerationException: Missing required parameter.

Optionele parameters en de request

Route::get('/fooi/{bedrag}/{procent?}', [KassaController::class, 'fooi'])->whereNumber(['bedrag', 'procent']);

public function fooi(Request $request, int $bedrag, int $procent = 10)
{
    $afronden = $request->boolean('afronden');       // ?afronden=1
    $fooi = $bedrag * $procent / 100;
    return view('kassa.fooi', ['fooi' => $afronden ? ceil($fooi) : $fooi]);
}

Laravel geeft je methode automatisch een Request-object als je er een type voor zet (use Illuminate\Http\Request;). Dat heet dependency injection; in les 4 zie je hoe dat werkt.

Resource-controllers

Voor producten wil je de standaard CRUD-acties. Eén commando maakt een controller met zeven methodes:

php artisan make:controller ProductController --resource
Route::resource('producten', ProductController::class)->parameters(['producten' => 'product']);
Methode URL Actie Naam
GET /producten index producten.index
GET /producten/create create producten.create
POST /producten store producten.store
GET /producten/{product} show producten.show
GET /producten/{product}/edit edit producten.edit
PUT/PATCH /producten/{product} update producten.update
DELETE /producten/{product} destroy producten.destroy

->parameters(...) is nodig omdat Laravel van "producten" geen Engels enkelvoud kan maken.

Route-groepen

Route::prefix('kassa')->name('kassa.')->controller(KassaController::class)->group(function () {
    Route::get('/', 'index')->name('index');              // /kassa  → kassa.index
    Route::get('/bon', 'bon')->name('bon');               // /kassa/bon → kassa.bon
    Route::post('/bon/regels', 'toevoegen')->name('toevoegen');
});

Typische fouten

  • Target class [KassaController] does not exist: de use-regel bovenaan web.php ontbreekt.
  • Route [kassa.totaal] not defined: tikfout in de naam, of de route staat in een groep met een name-prefix.
  • /producten/create toont een product "create": je hebt een eigen /producten/{product}-route boven de resource gezet. Volgorde telt.

Oefenen

  1. Verplaats /totaal, /over en /korting uit les 1 naar KassaController en geef ze namen.
  2. Maak een menu in een view met route()-links naar alle drie.
  3. Maak ProductController als resource en laat index voorlopig een vaste array met drie producten tonen.
  4. Zet de kassa-routes in een groep met prefix kassa en naam-prefix kassa..
Modelantwoord oefening 1
Route::controller(KassaController::class)->group(function () {
    Route::get('/totaal/{bedrag}', 'totaal')->whereNumber('bedrag')->name('kassa.totaal');
    Route::get('/korting/{bedrag}/{procent}', 'korting')->whereNumber(['bedrag', 'procent'])->name('kassa.korting');
});
Route::view('/over', 'over')->name('over');
Modelantwoord oefening 2
<nav>
  <a href="{{ route('over') }}">Over</a>
  <a href="{{ route('kassa.totaal', 100) }}">Totaal</a>
  <a href="{{ route('kassa.korting', [80, 25]) }}">Korting</a>
</nav>

Bij één parameter mag je hem los meegeven; bij meer een array in de volgorde van de route.

Modelantwoord oefening 3
public function index()
{
    $producten = [['naam' => 'koffie', 'prijs' => 2.80], ['naam' => 'thee', 'prijs' => 2.50], ['naam' => 'appeltaart', 'prijs' => 4.25]];
    return view('producten.index', compact('producten'));
}

In les 8 komt deze lijst uit de database.

Modelantwoord oefening 4

php artisan route:list --path=kassa toont alleen de routes onder /kassa, met namen als kassa.bon.

Lokaal oefenen

Geen live lab. Gebruik php artisan route:list en curl -i om elke route te controleren.

Samenvatting

  • Routes zeggen welke URL; controllers zeggen wat er gebeurt.
  • Geef routes een naam en link met route().
  • Route::resource maakt in één regel de zeven CRUD-routes; groepen houden web.php overzichtelijk.
  • Volgende les: Blade-templates en componenten.

📝 Quiz: Routes en controllers

5 vragen · 70% nodig om te slagen

1. Waar zoekt view('kassa.totaal')?
2. Waarom geef je routes een naam?
3. Welke methode van een resource-controller verwerkt het formulier voor een nieuw product?
4. Wat geeft route('kassa.totaal', ['bedrag'=>50,'fooi'=>10])?
5. Waarom ->parameters(['producten'=>'product']) bij Route::resource('producten', …)?