Laravel 13-tutorial #3: de MVC-structuur en Blade-views
geverifieerd op 7 september 2026 · 6 min
MVC scheidt de data (model), de weergave (view) en de logica (controller). Maak een controller met php artisan make:controller, geef een view terug met view('nom', [...]) en toon de waarden in Blade met {{ $variable }}, dat de HTML automatisch escapet.
MVC verdeelt een applicatie over drie verantwoordelijkheden: het model beschrijft de data, de view toont ze, de controller legt het verband tussen die twee. In dit hoofdstuk bouw je een controller en Blade-views. De modellen komen in hoofdstuk 6 aan bod, zodra er een database is om te bevragen.
De controllers
Een controller ontvangt een request, verzamelt wat de pagina nodig heeft en geeft een view terug. Maak er een aan:
php artisan make:controller IndexControllerINFO Controller [app/Http/Controllers/IndexController.php] created successfully.Het gegenereerde bestand is bijna leeg. Laravel 13 importeert er standaard Request in, ook al wordt die klasse nog niet gebruikt:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
//
}App\Http\Controllers schrijf je met backslashes, niet met schuine strepen, en nooit aan elkaar geplakt tot één woord. Een regel als namespace AppHttpControllers; wijst niet naar de juiste namespace en de autoloader van Composer vindt de klasse dan niet. Kopieer je code van een site die de backslashes heeft opgeslokt, dan is dat het eerste wat je controleert.
Voeg een methode toe die tekst teruggeeft:
<?php
namespace App\Http\Controllers;
class IndexController extends Controller
{
public function index(): string
{
return 'Ceci vient de IndexController';
}
}Laat de route van de homepage daar vervolgens naar wijzen:
<?php
use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;
Route::get('/', [IndexController::class, 'index']);Herlaad http://127.0.0.1:8000: de zin verschijnt. De route bevat geen logica meer, ze wijst alleen nog aan waar die staat.
Een view teruggeven in plaats van een string
use Illuminate\View\View;
public function index(): View
{
return view('welcome');
}De functie view() krijgt de bestandsnaam zonder extensie mee: welcome staat voor resources/views/welcome.blade.php. Een punt werkt als mapscheiding: view('partials.sidebar') laadt resources/views/partials/sidebar.blade.php.
Controllers met één actie
Wanneer een controller maar één ding te doen heeft, bespaart de methode __invoke je een naam. Het bestand bestaat al sinds het begin van het hoofdstuk: --force overschrijft het.
php artisan make:controller IndexController --invokable --forceHet gegenereerde bestand bevat een lege methode __invoke(Request $request), voorafgegaan door een commentaar. Vervang die door deze:
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function __invoke(): View
{
return view('welcome');
}
}De route wordt navenant korter: de methode hoef je niet meer op te geven.
Route::get('/', IndexController::class);Deze tutorial gebruikt die vorm voor de homepage, de categorieën en de tags, en de klassieke vorm voor de artikelen, die twee methodes krijgen.
Data doorgeven aan de view
Het tweede argument van view() is een array. Elke sleutel wordt een variabele in het template:
public function __invoke(): View
{
return view('accueil', [
'nom' => 'Damien',
'articles' => ['Premier article', 'Deuxième article'],
]);
}In de view zijn $nom en $articles beschikbaar.
De Blade-views
Blade is de template-engine van Laravel. Een .blade.php-bestand is gewoon HTML met een handvol directives erbij. Het wordt één keer naar PHP gecompileerd en daarna gecachet.
Een waarde tonen
<p>Bonjour, {{ $nom }}.</p>Dubbele accolades escapen de inhoud automatisch: bevat $nom de tekst <script>, dan zet de browser die op het scherm in plaats van hem uit te voeren. Dat is de standaardbescherming tegen code-injectie.
Wil je bewust HTML tonen, bijvoorbeeld de inhoud van een artikel dat in de backoffice is geschreven, gebruik dan de niet-geëscapete vorm:
<div>{!! $post->content !!}</div>Zet die alleen in op waarden waarvan je de herkomst kent. Op invoer van een bezoeker is het een lek.
Voorwaarden en lussen
@if (count($articles) === 1)
Un seul article.
@elseif (count($articles) > 1)
{{ count($articles) }} articles.
@else
Aucun article.
@endifDe lus @foreach heeft een handige variant, @forelse, die het geval van de lege lijst afhandelt zonder extra voorwaarde:
@forelse ($articles as $article)
<h2>{{ $article }}</h2>
@empty
<p>Aucun article pour le moment.</p>
@endforelseDe lussen
@foreach zie je het vaakst, maar Blade neemt alle lussen van PHP over:
@for ($i = 1; $i <= 3; $i++)
Passage numéro {{ $i }}
@endfor
@while ($compteur > 0)
Il reste {{ $compteur-- }}
@endwhileBinnen een @foreach geeft Blade je een variabele $loop, waarmee je niet zelf hoeft te tellen:
@foreach ($articles as $article)
{{ $loop->iteration }} sur {{ $loop->count }} :
{{ $article }}
@if ($loop->first) (le premier) @endif
@if ($loop->last) (le dernier) @endif
@endforeachOp een lijst van twee artikelen levert dit template op:
1 sur 2 : A (le premier)
2 sur 2 : B (le dernier)$loop biedt ook index (vanaf nul), remaining, even, odd en parent, om naar de omliggende lus te springen.
De meervoudige keuze
@switch($niveau)
@case('debutant')
Pour débuter
@break
@case('avance')
Pour aller plus loin
@break
@default
Niveau non précisé
@endswitchDe @break is verplicht aan het eind van elke @case, net als in PHP: zonder loopt de uitvoering door in het volgende geval.
Templates overerven
Het grootste voordeel van Blade is dat je het geraamte van de site maar één keer schrijft. Maak resources/views/layouts/app.blade.php aan:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title', config('app.name'))</title>
</head>
<body>
<header>
<a href="https://www.gekkode.com/nl/">{{ config('app.name') }}</a>
</header>
<main>
@yield('content')
</main>
<footer>
<p>{{ config('app.name') }}</p>
</footer>
</body>
</html>@yield('content') reserveert een plek. Het tweede argument van @yield is de standaardwaarde, voor het geval de sectie niet is gedefinieerd.
Een concrete pagina breidt dat template uit en vult de plekken in:
@extends('layouts.app')
@section('title', 'Accueil')
@section('content')
<h1>Bonjour, {{ $nom }}.</h1>
@forelse ($articles as $article)
<h2>{{ $article }}</h2>
@empty
<p>Aucun article pour le moment.</p>
@endforelse
@endsectionVoor een korte sectie past @section('title', 'Accueil') op één regel. Voor een blok open je met @section en sluit je met @endsection.
Een herbruikbaar stuk invoegen
@include zet een andere view op de gewenste plek, met toegang tot dezelfde variabelen:
@include('partials.sidebar')Deze tutorial gebruikt dat voor de zijbalk en de artikellijst, die op vijf pagina’s terugkomen.
Componenten of overerving?
Laravel biedt een tweede aanpak, de Blade-componenten, met een syntaxis in tagvorm:
<x-layout title="Accueil">
<h1>Bonjour</h1>
</x-layout>Beide mechanismen bestaan naast elkaar in Laravel 13 en geen van beide is deprecated. Componenten winnen zodra de bouwstenen parameters krijgen en zich met elkaar laten combineren, @extends blijft directer voor een eenvoudig paginageraamte. Deze tutorial houdt het bij @extends, om te beginnen het leesbaarst. De documentatie van Blade beschrijft de componenten in detail.
Een opmerking over de viewcache
Blade compileert elke view naar PHP in storage/framework/views. Tijdens ontwikkeling gebeurt die hercompilatie automatisch zodra het bestand verandert. Verschijnt een wijziging niet, leeg dan de cache:
php artisan view:clearHet volgende hoofdstuk installeert het adminpaneel waarmee je de artikelen gaat schrijven.