Tutorial Laravel 13 #3: struttura MVC, controller e viste Blade
verificato il 7 Settembre 2026 · 6 min
MVC separa i dati (modello), la visualizzazione (vista) e la logica (controller). Crea un controller con php artisan make:controller, restituisci una vista con view('nom', [...]) e mostra i valori in Blade con {{ $variable }}, che fa l'escape dell'HTML in automatico.
MVC divide un’applicazione in tre responsabilità: il modello descrive i dati, la vista li mostra, il controller fa da collegamento tra i due. Questo capitolo costruisce un controller e alcune viste Blade. I modelli arrivano al capitolo 6, quando ci sarà un database da interrogare.
I controller
Un controller riceve una richiesta, raccoglie quello che serve alla pagina e restituisce una vista. Creane uno:
php artisan make:controller IndexControllerINFO Controller [app/Http/Controllers/IndexController.php] created successfully.Il file generato è quasi vuoto. Laravel 13 vi importa Request d’ufficio, anche se questa classe non serve ancora:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class IndexController extends Controller
{
//
}App\Http\Controllers si scrive con i backslash, non con le barre oblique, e mai tutto attaccato in una parola sola. Una riga come namespace AppHttpControllers; non indica il namespace giusto e l’autoload di Composer non troverà la classe. Se copi del codice da un sito che si è mangiato i backslash, è la prima cosa da controllare.
Aggiungi un metodo che restituisce del testo:
<?php
namespace App\Http\Controllers;
class IndexController extends Controller
{
public function index(): string
{
return 'Ceci vient de IndexController';
}
}Poi fai puntare su quel metodo la rotta della home:
<?php
use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;
Route::get('/', [IndexController::class, 'index']);Ricarica http://127.0.0.1:8000: la frase compare. La rotta non contiene più logica, indica soltanto dove trovarla.
Restituire una vista invece di una stringa
use Illuminate\View\View;
public function index(): View
{
return view('welcome');
}La funzione view() prende il nome del file senza estensione: welcome corrisponde a resources/views/welcome.blade.php. Il punto fa da separatore di cartella: view('partials.sidebar') carica resources/views/partials/sidebar.blade.php.
I controller a singola azione
Quando un controller ha una sola cosa da fare, il metodo __invoke evita di darle un nome. Il file esiste già dall’inizio del capitolo: --force lo sovrascrive.
php artisan make:controller IndexController --invokable --forceIl file generato contiene un metodo __invoke(Request $request) vuoto, preceduto da un commento. Sostituitelo con questo:
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function __invoke(): View
{
return view('welcome');
}
}La rotta si semplifica di conseguenza: non serve più indicare il metodo.
Route::get('/', IndexController::class);Questo tutorial usa questa forma per la home, le categorie e i tag, e la forma classica per gli articoli, che avranno due metodi.
Passare dati alla vista
Il secondo argomento di view() è un array. Ogni chiave diventa una variabile nel template:
public function __invoke(): View
{
return view('accueil', [
'nom' => 'Damien',
'articles' => ['Premier article', 'Deuxième article'],
]);
}Nella vista, $nom e $articles sono disponibili.
Le viste Blade
Blade è il motore di template di Laravel. Un file .blade.php è HTML a cui si aggiungono alcune direttive. Viene compilato in PHP una volta sola, poi messo in cache.
Mostrare un valore
<p>Bonjour, {{ $nom }}.</p>Le doppie graffe fanno l’escape del contenuto in automatico: se $nom contiene <script>, il browser mostra il testo invece di eseguirlo. È la protezione predefinita contro le injection di codice.
Quando vuoi mostrare dell’HTML di proposito, per esempio il contenuto di un articolo scritto nel back-office, usa la forma senza escape:
<div>{!! $post->content !!}</div>Usala solo su valori di cui controlli l’origine. Su quello che digita un visitatore è una falla.
Condizioni e cicli
@if (count($articles) === 1)
Un seul article.
@elseif (count($articles) > 1)
{{ count($articles) }} articles.
@else
Aucun article.
@endifIl ciclo @foreach ha una variante utile, @forelse, che gestisce la lista vuota senza una condizione in più:
@forelse ($articles as $article)
<h2>{{ $article }}</h2>
@empty
<p>Aucun article pour le moment.</p>
@endforelseI cicli
@foreach è il più diffuso, ma Blade riprende tutti i cicli di PHP:
@for ($i = 1; $i <= 3; $i++)
Passage numéro {{ $i }}
@endfor
@while ($compteur > 0)
Il reste {{ $compteur-- }}
@endwhileDentro un @foreach, Blade mette a disposizione una variabile $loop che evita di contare a mano:
@foreach ($articles as $article)
{{ $loop->iteration }} sur {{ $loop->count }} :
{{ $article }}
@if ($loop->first) (le premier) @endif
@if ($loop->last) (le dernier) @endif
@endforeachSu una lista di due articoli, questo template produce:
1 sur 2 : A (le premier)
2 sur 2 : B (le dernier)$loop espone anche index (a partire da zero), remaining, even, odd e parent, per risalire al ciclo che lo contiene.
La scelta multipla
@switch($niveau)
@case('debutant')
Pour débuter
@break
@case('avance')
Pour aller plus loin
@break
@default
Niveau non précisé
@endswitchIl @break è obbligatorio alla fine di ogni @case, come in PHP: senza, l’esecuzione prosegue nel caso successivo.
L’ereditarietà dei template
Il vantaggio principale di Blade è scrivere l’ossatura del sito una volta sola. Crea resources/views/layouts/app.blade.php:
<!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/it/">{{ config('app.name') }}</a>
</header>
<main>
@yield('content')
</main>
<footer>
<p>{{ config('app.name') }}</p>
</footer>
</body>
</html>@yield('content') riserva uno spazio. Il secondo argomento di @yield è il valore usato quando la sezione non è definita.
Una pagina concreta estende questo template e riempie gli spazi:
@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
@endsectionPer una sezione breve, @section('title', 'Accueil') sta su una riga. Per un blocco si apre con @section e si chiude con @endsection.
Includere un pezzo riutilizzabile
@include inserisce un’altra vista nel punto voluto, con accesso alle stesse variabili:
@include('partials.sidebar')Questo tutorial se ne serve per la barra laterale e per la lista degli articoli, riutilizzate su cinque pagine.
Componenti o ereditarietà?
Laravel propone un secondo approccio, i componenti Blade, con una sintassi a tag:
<x-layout title="Accueil">
<h1>Bonjour</h1>
</x-layout>I due meccanismi convivono in Laravel 13 e nessuno dei due è deprecato. I componenti si impongono quando i mattoni accettano parametri e si combinano tra loro, @extends resta più diretto per una semplice ossatura di pagina. Questo tutorial si limita a @extends, più leggibile per iniziare. La documentazione di Blade spiega i componenti nel dettaglio.
Una nota sulla cache delle viste
Blade compila ogni vista in PHP dentro storage/framework/views. In sviluppo la ricompilazione è automatica non appena il file cambia. Se una modifica non compare, svuota la cache:
php artisan view:clearIl capitolo successivo installa il pannello di amministrazione che servirà a scrivere gli articoli.