Capitolo 3 di 9

Tutorial Laravel 13 #3: struttura MVC, controller e viste Blade

verificato il 7 Settembre 2026 · 6 min

Risposta rapida

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.

Alla fine di questo capitolo, saprai creare un controller, fargli restituire una vista Blade e costruire un layout di pagina riutilizzabile.

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:

bash
php artisan make:controller IndexController
code
INFO  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:

app/Http/Controllers/IndexController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
    //
}
I backslash contano

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:

app/Http/Controllers/IndexController.php
<?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:

routes/web.php
<?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

app/Http/Controllers/IndexController.php
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.

bash
php artisan make:controller IndexController --invokable --force

Il file generato contiene un metodo __invoke(Request $request) vuoto, preceduto da un commento. Sostituitelo con questo:

app/Http/Controllers/IndexController.php
<?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.

routes/web.php
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:

app/Http/Controllers/IndexController.php
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

markup
<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:

markup
<div>{!! $post->content !!}</div>

Usala solo su valori di cui controlli l’origine. Su quello che digita un visitatore è una falla.

Condizioni e cicli

markup
@if (count($articles) === 1)
    Un seul article.
@elseif (count($articles) > 1)
    {{ count($articles) }} articles.
@else
    Aucun article.
@endif

Il ciclo @foreach ha una variante utile, @forelse, che gestisce la lista vuota senza una condizione in più:

markup
@forelse ($articles as $article)
    <h2>{{ $article }}</h2>
@empty
    <p>Aucun article pour le moment.</p>
@endforelse

I cicli

@foreach è il più diffuso, ma Blade riprende tutti i cicli di PHP:

markup
@for ($i = 1; $i <= 3; $i++)
    Passage numéro {{ $i }}
@endfor

@while ($compteur > 0)
    Il reste {{ $compteur-- }}
@endwhile

Dentro un @foreach, Blade mette a disposizione una variabile $loop che evita di contare a mano:

markup
@foreach ($articles as $article)
    {{ $loop->iteration }} sur {{ $loop->count }} :
    {{ $article }}
    @if ($loop->first) (le premier) @endif
    @if ($loop->last) (le dernier) @endif
@endforeach

Su una lista di due articoli, questo template produce:

code
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

markup
@switch($niveau)
    @case('debutant')
        Pour débuter
        @break
    @case('avance')
        Pour aller plus loin
        @break
    @default
        Niveau non précisé
@endswitch

Il @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:

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:

resources/views/accueil.blade.php
@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
@endsection

Per 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:

markup
@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:

markup
<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:

bash
php artisan view:clear

Il capitolo successivo installa il pannello di amministrazione che servirà a scrivere gli articoli.

Errori frequenti

I backslash del namespace spariscono Una riga che si legge « namespace AppHttpControllers » invece di « namespace App\Http\Controllers » non indica il namespace giusto, e l'autoload di Composer non trova la classe. È il difetto più frequente nel codice copiato dal web.
{{ }} mostra l'HTML come testo È voluto: le doppie graffe fanno l'escape del contenuto. Per mostrare HTML di proposito usa {!! !!}, e soltanto su una sorgente fidata.
@break dimenticato in uno @switch Come in PHP, senza @break l'esecuzione prosegue nel caso successivo.
Una modifica alla vista non compare Svuota la cache delle viste compilate con php artisan view:clear.
Newsletter

I nuovi test, tutorial e progetti, via e-mail.

Test riproducibili, codice versionato, risultati datati. Mai spam.