devdev / in the loop
PHP PHP

Guida a Laravel 10
Le routes

Nel capitolo precedente abbiamo accennato al fatto che nella directory routes possiamo (e dobbiamo) definire le routes del nostro progetto e che esse svolgono il fondamentare ruolo di gestire le richieste via URL (quindi richieste HTTP) del nostro progetto. È bene specificare che Laravel non gestisce nessuna riscrittura degli URL (url rewriting), ma semplicemente intercetta tutte le richieste HTTP e le indirizza alla pagina public/index.php, che a sua volta avvia il framework e controlla se c’è qualche route specificata per l’URL richiesto.

In altre parole, chiamando https://miodominio.com/user/1, la richiesta viene gestita se nei file routes/web.php c’è una route definita per accogliere la richiesta verso /user/1 e rispondere di conseguenza. La risposta può essere, naturalmente una risposta in JSON (nel caso di una API), o una “normale” pagina web con CSS e JS annessi, magari utilizzando il template engine Blade.

 

Partiamo quindi dal caso più semplice, rispondiamo all’url /benvenuto con un con messaggio estremamente simpatico:

// routes/web.php
// ...
// aggiungiamo questa route in coda

Route::get('/benvenuto', function () {
    return 'Benvenut* in Laravel!';
});

Dato che in questo esempio non merita spiegazioni, passiamo ad un esempio leggermente più complesso, quello che abbiamo già utilizzato in precedenza:

Route::get('/user/{id}', function ($id) {
    return "Hai chiesto l'ID utente ".$id;
});

Abbiamo ottenuto l’ID utente da un segmento dell’URL. Possiamo farlo naturalmente con diversi segmenti:

Route::get('/articoli/{categoria}/prodotto/{id}', function ($categoria, $prodotto_id) {
    // $categoria e $prodotto_id assumeranno i valori dei segmenti corrispondenti
});

E se alcuni parametri fossero opzionali? Possiamo dire a Laravel che uno o più segmenti sono opzionali utilizzando il punto interrogativo ? in questo modo:

Route::get('/articoli/{categoria?}', function ($categoria = null) {
    // 
});

Funzionerà così sia l’URL /articoli/ che /articoli/ferramenta, ma nel primo caso, essendo assente il parametro, otterremo il valore di default di $categoria, cioè null.

Possiamo vincolare il formato che i nostri parametri possono assumere utilizzando le espressioni regolari. Ad esempio, ci aspettiamo che l’ID di una news sia sempre un numero, e non una stringa. Potremmo quindi fare il routing dell’URL /news/1 in questo modo:

Route::get('/news/{id}', function ($categoria = null) {
    // 
})->where('id', '[0-9]+');

Abbiamo invocato il metodo where() che accetta come parametri il nome del segmento e l’espressione regolare. In questo caso abbiamo utilizzato [0-9]+, ma se ad esempio ci aspettassimo una stringa (come nel caso del routing /articoli/ferramenta utilizzato in precedenza), dovremmo usare l’espressione regolare [A-Za-Z]+:

Route::get('/articoli/{categoria}', function ($categoria) {
    // 
})->where('id', '[A-Za-Z]+');

Se i parametri, fossero due (o più), dovremmo passare un’array al metodo where(), in questo modo:

Route::get('/news/{id}/{titolo}', function ($id, $titolo) {
    //
})->where(['id' => '[0-9]+', 'name' => '[A-Za-z]+']);

Cosa succede se questa route non “prende” l’URL interessato, perché ad esempio chiamiamo l’URL /news/sport/formula1 e non /news/99/formula1? Semplicemente questa ruote non funzionerà, dovremmo crearne una adatta a gestire le richieste “sbagliate” ed i typo.

Vediamo poi come dare un nome alle route, perché questo nome ci potrà servire in seguito per identificarla velocemente.

Route::get('/news/formula1', function () {
    //
})->name('formula1_news');

I gruppi di route sono utili quando una serie di route hanno un prefisso comune e si potranno quindi raggruppare molto semplicemente, in questo modo:

Route::prefix('news')->group(function () {
    Route::get('/formula1', function () {
        // URL /news/formula1
    });
    Route::get('/motoGP', function () {
        // URL /news/motoGP
    });
});

Naturalmente, tutti i metodi HTTP sono contemplati, quindi tutti gli esempi che abbiamo visto funzioneranno con GET (come appunto negli esempi), ma anche con POST, PUT, DELETE, PATCH e OPTIONS. Eccoli elencati:

Route::get(..);
Route::post(..);
Route::put(..);
Route::patch(..);
Route::delete(..);
Route::options(..);

E se avessimo bisogno di fare il match per più di un metodo HTTP? Ad esempio rispondere alle richieste sia POST che GET verso l’indirizzo /supermega? Possiamo farlo utilizzando il metodo match(), passandogli un array con i metodi:

Route::match(['get', 'post'], '/supermega', function () {
//
});

Vediamo come gestire le routes che portano verso Model mancanti o inesistenti, come ad esempio richiedere un’articolo che non esiste nel database. Nel nostro esempio, porteremo l’utente alla route alla quale abbiamo assegnato il nome “non_trovata”.

use App\Http\Controllers\ArticoloController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

Route::get('/articolo/{articolo}', [ArticoloController::class, 'show'])->missing(function (Request $request) {
    return redirect()->route('non_trovata');
});

Vediamo, infine, come aggiungere una route di Fallback “acchiappatutto”, che intercetti tutte le richieste che non sono state matchate dalle altre route. Di solito è quella che mostra la pagina di 404. Attenzione: dobbiamo sempre scriverla per ultima, altrimenti bloccherà le altre route!

Route::fallback(function () {
    //
});

 

Una volta che abbiamo compreso e preso familiarità con le route di Laravel, possiamo passare a quello che ritengo il “Capitolo 2 delle routes”, ovvero quello che riguarda il Model binding, per sfruttare davvero a fondo le capacità di questo framework e snellire non di poco il nostro lavoro. Prosegui verso Routing e model binding con Laravel.

Capitolo successivo → Routes e Model binding
if (weekend) {
    relax();
}
la nostra newsletter, ogni tanto.