Introduzione
Come accennato nei tutorial precedenti, il Routing permette di indirizzare le richieste all'interno della tua applicazione a dei controller preposti per gestirle. Ogni percorso è identificato, in Laravel, da un URI (Uniform Resource Identifier).
In questa guida ti spiegheremo le meccaniche del routing e come implementarlo all'interno della tua applicazione web.
Creare Percorsi in Laravel
File predefiniti
Tutti i percorsi in Laravel sono implementati all'interno di files che si trovano nelle sottodirectory dei percorsi. Questi file vengono processati da Laravel per risolvere i collegamenti descritti in essi e creare dei percorsi nella tua applicazione web.
All'interno delle directory della applicazione, troveremo, al percorso app/Http/routes.php il file principale dei percorsi, assieme ad altri files per i percorsi delle api o di altre componenti. Ad esempio , il file web.php conterrà i percorsi delle interfacce web. I middleware assegnati a questo gruppo di files permetteranno funzionalità come il salvataggio degli stati della sessione (quel meccanismo che ti permette di riprendere da dove avevi lasciato quando chiudi e riapri un sito web, invece che dover ricominciare da capo la navigazione) e alcuni meccanismi di protezione dalle richieste CSRF, ossia delle richieste potenzialmente dannose che l'utente malintenzionato o inconsapevole potrebbe inviare nella tua applicazione web.
Nota: è bene sapere che, proprio per questo meccanismo di sicurezza, qualunque form HTML collegato a dei metodi di manipolazione dati come POST, PUT, PATCH, DELETE necessiterà della specifica di un token all'interno dei loro tag per far approvare la loro richiesta dal meccanismo di protezione CSRF. La dichiarazione del token sarà semplicemente @csrf, posta all'interno dei tag form.
All'interno del percorso routes/api.php, inserirai tutti i percorsi collegati alle API disponibili nella tua applicazione web. Essendo questo file appartenente al gruppo delle API, tutti i percorsi specificati all'interno di questo file avranno, come prefisso, la voce /api all'interno dell URI. Ciò permette di risparmiare tempo, non dovendo sempre inserire il prefisso manualmente.
Il routing per le richieste viene creato usando la dichiarazione Route, similmente alla sintassi vista precedentemente per la definizione dei collegamenti tra controller e risorse del model, come visto in precedenza nella guida sui Controller di Laravel.
In questo caso, i percorsi saranno per definire dei metodi che si attiveranno in seguito alle richieste restituendo qualcosa.
Un esempio di sintassi sarebbe il seguente:
use Illuminate\Support\Facades\Route;
Route::get('/greeting', function () {
return 'Hello World';
});
All'interno della tua applicazione web, al percorso https://tuodominio/greeting, troverai una pagina che restituirà la stringa Hello World. E' chiaro che le funzioni potranno non solo essere di visualizzazione di un messaggio, ma anche di operazioni sui dati , richiesta di input da parte dell'utente o metodi CRUD.
Meccanica del Routing
Il routing, sostanzialmente, si compone di 3 passi fondamentali:
- Creare e mandare online l'URL del root della tua applicazione web
- L'URL specificato dovrà essere identico a quello specificato nel metodo del file root.php, così che tutte le funzioni al suo interno possano essere eseguite
- La funzione invocherà il file di template e le Viste (secondo il modello MVC visto nella guida sulla Creazione dei modelli con Laravel. La vista verrà utilizzata prendendo il nome del file che si troverà all'interno del percorso resource/views e sostituirà la pagina di default (quella con estensione ".blade.php")
Metodi a disposizione per i percorsi
La dichiarazione Route ti permette di registrare percorsi associati ai "verbi" del protocollo HTTP. Essi saranno:
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
Potresti avere bisogno di registrare un percorso che abbia una corrispondenza "uno a molti" con i verbi HTTP. Ciò ti sarà possibile grazie al metodo match che ti permetterà di associare più verbi allo stesso metodo. Nel caso, invece, di un percorso che includa tutti i verbi HTTP , potrai invece usare il metodo any. La sintassi sarà simile all'esempio:
Route::match(['get', 'post'], '/', function () {
//
});
Route::any('/', function () {
//
});
Injection delle Dipendenze
Se ci sono delle dipendenze richieste nel tuo percorso, potrai specificarle durante la definizione passandole come parametro alla funzione del metodo. Queste dipendenze, come visto nei tutorial precedenti, vengono gestite e risolte direttamente da Laravel. Per esempio, volendo includere le richieste HTTP nel tuo percorso, potrai seguire la sintassi dell'esempio:
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
// ...
});
Percorsi di Redirect
Nel caso in cui il percorso a una risorsa debba reindirizzare l'utente a un altro URI, potrai definire tale percorso tramite il metodo redirect. La sintassi schematizzata sarà la seguente:
Route::redirect('/startpoint', '/endpoint');
Percorsi collegati a Viste
Se il percorso punta a una Vista, potrai usare direttamente il metodo view: esso funziona come un reindirizzamento, fornendo una scorciatoia a una vista senza aver bisogno di specificare un percorso completo o definire un controller.
Il metodo accetta, come argomenti obbligatori, un URI e un nome della vista richiesta. In esempio:
Route::view('/welcome', 'welcome');
Lista dei percorsi
Come visto in precedenza, è possibile tramite Artisan, visualizzare la lista di tutti i percorsi della tua applicazione web direttamente dal terminale. Per farlo utilizza il comando:
$ php artisan route:list
L'output dovrebbe essere simile al seguente:
Per includere la visualizzazione delle informazioni sui Middlewares, basterà aggiungere l'opzione -v a fine comando.
Puoi anche cercare un percorso specifico tramite l'opzione --path. Essa ti permetterà di cercare tutte le routes che comincino con un certo URI. Ad esempio:
$ php artisan route:list --path=api
Il comando restituirà tutti i percorsi che siano associati alle API. L'output sarà simile:
Puoi anche includere, negli output, un'opzione che permetta di visualizzare tutti i percorsi eccetto quelli provenienti da pacchetti di terze parti o solamente i percorsi provenienti da pacchetti di terze parti. Per farlo, ricorri ai comandi:
$ php artisan route:list --except-vendor
$ php artisan route:list --only-vendor
Parametri dei percorsi
Parametri richiesti
Ci sono dei casi in cui può essere necessario recuperare dei segmenti dell'URI di una risorsa per poter proseguire nel percorso. Per esempio, nel caso in cui tu voglia recuperare la matricola dello studente di cui vuoi visualizzare i voti (seguendo gli esempi del database preso in oggetto nei tutorial di questa serie) dovrai definire una funzione get e passarle quello che nel modello è il badge_number registrato per ogni studente come e utilizzabile come identificatore univoco.
Route::get('/student/{badge_number}', function ($badge_number) {
return 'Student '.$badge_number;
});
Analizzando la sintassi sappiamo che i parametri sono sempre incapsulati in due parentesi graffe e vengono espressi con caratteri alfabetici più gli underscore per gli spazi.
La funzione può essere anche definita facendole accettare più parametri. Nell'esempio vogliamo recuperare un voto di una interrogazione specifica di uno studente (seguendo il modello preso in oggetto durante i tutorial precedenti della serie).
Dovresti quindi passare sia il parametro della matricola dello studente (badge_number) ma anche l'identificativo associato al voto (era stato scelto lo slug).
Il codice sarebbe simile:
Route::get('/students/{student}/grades/{grade}', function ($badge_number, $slug) {
//
});
Anche in questo caso vale la proprietà della Injection, seguendo la sintassi vista in precedenza:
use Illuminate\Http\Request;
Route::get('/student/{badge_number}', function (Request $request, $badge_number) {
return 'Student '.$badge_number;
});
Parametri opzionali
Potrebbe capitarti di voler specificare dei parametri che se presenti andrebbero presi in considerazione ma non obbligatori.
Questa richiesta di un parametro opzionale viene implementata semplicemente aggiungendo il carattere "?" come suffisso del nome del parametro.
Nella funzione, poi, potrai specificare tra gli argomenti a quale valore quel parametro dovrebbe coincidere, in modo tale da poter filtrare la tua ricerca.
Per esempio, potresti voler recuperare le informazioni di uno studente in base eventualmente al nome e non in base solo al numero di matricola. La sintassi sarebbe la seguente:
Route::get('/student/{name?}', function ($name = null) {
return $name;
});
Route::get('/student/{name?}', function ($name = 'Mario') {
return $name;
});
Inserire dei vincoli sui parametri accettati tramite le espressioni regolari
E' possibile che il metodo debba richiedere solo parametri che corrispondano a determinate caratteristiche (abbiano un certo prefisso/suffisso, contengano determinati numeri al loro interno ecc...). Ciò è fattibile inserendo, dopo la dichiarazione di una route, il metodo where(che si comporta come l'applicazione di una query con una sintassi per filtrare i risultati).
Alcuni esempi potrebbero essere i seguenti:
/*Applica il metodo solo agli studenti il cui nome inizi con un carattere alfabetico (maiuscolo o minuscolo, in sostanza accetta solo stringhe di caratteri alfabetici)*/
Route::get('/student/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
/*Applica il metodo solo agli studenti il cui numero di matricola inizi con una cifra
Route::get('/student/{badge_number}', function ($badge_number) {
//
})->where('badge_number', '[0-9]+');
//Dichiarazione unica per gli statements precedenti
Route::get('/student/{bage_number}/{name}', function ($badge_number, $name) {
//
})->where(['badge_number' => '[0-9]+', 'name' => '[a-z]+']);
Il metodo where offre diverse varianti per poter registrare direttamente alcuni vincoli usati frequentemente dagli sviluppatori:
/*Solo studenti che abbiano una stringa numerica come numero di matricola o che abbiano una stringa di caratteri come nome*/
Route::get('/student/{badge_number}/{name}', function ($badge_number, $name) {
//
})->whereNumber('badge_number')->whereAlpha('name');
//Solo gli studenti la cui matricola sia una stringa alfanumerica
Route::get('/student/{badge_number}', function ($badge_number) {
//
})->whereAlphaNumeric('badge_number');
//Solo gli studenti che abbiano un numero di matricola unico
Route::get('/user/{badge_number}', function ($badge_number) {
//
})->whereUuid('badge_number');
//Solo gli studenti che abbiano come parametro della voce "classe" uno di quelli citati (1sto 2nd)
Route::get('/student/{class}', function ($class) {
//
})->whereIn('class', ['1st', '2nd']);
Gruppi di percorsi
Middleware
Per assegnare un middleware a tutti i percorsi di un determinato gruppo, puoi ricorrere al metodo middleware e in seguito puoi definire un gruppo all'interno del quale inserire i percorsi a tua scelta.
La sintassi sarà simile a quella dell'esempio
Route::middleware(['authenticate'])->group(function () {
Route::get('/student/profile', function () {
// Uses authentication middleware (name is abstract)...
});
Route::get('/student/grades', function () {
// same as before...
});
});
Controllers
Se un gruppo di percorsi fa riferimento allo stesso controller, puoi usare il metodo controller per definire il controller preposto al gruppo. Come nel caso precedente, seguirà, prima della dichiarazione di funzione, la voce group. Potrai specificare nel corpo tra le parentesi tutti i percorsi interessati dal gruppo.
La sintassi sarà simile:
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/students/{badge_number}', 'show');
Route::post('/students', 'register');
});
Indirizzare ai sottodomini
Puoi associare anche dei gruppi a uno specifico sottodominio utilizzando il metodo domain e specificando come argomento il dominio in cui definire il gruppo.
La sintassi sarà simile all'esempio:
Route::domain('{account}.myprofile.com')->group(function () {
Route::get('student/{badge_number}', function ($account, $badge_number) {
//
});
});
(Nota: Per rendere effettivi questi percorsi senza malfunzionamenti, ti suggeriamo di definire i gruppi dei sottodomini prima della dichiarazione dei percorsi associati al dominio principale.)
Prefissi
Nei percorsi
Ti è possibile utilizzare il metodo prefix per assegnare a tutti i percorsi del gruppo un prefisso sul loro URI. Per esempio, per assegnare al gruppo il prefisso admin, userai la sintassi:
//La corrispondenza sarà sull' URL /admin/users
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
});
});
Nei nomi di percorsi
Il metodo name ti permette di assegnare un prefisso a tutto il gruppo di percorsi registrati. Il prefisso sarà una stringa che passerai in input nell'argomento del metodo name.
Riprendendo l'esempio precedente, la sintassi sarà la seguente:
Route::name('admin.')->group(function () {
Route::get('/users', function () {
/* Il percorso avrà come nome "admin.users" +...*/
})->name('users');
});
Binding col Model nei percorsi
Un ultimo accenno te lo presentiamo sul Binding. Invece che passare i singoli parametri con l'injection, come per il caso del numero di matricola negli esempi precedenti, potresti direttamente passare tutte le istanze dell'intero modello Student che rispettino i criteri della query.
Per approfondire, visita la sezione dedicata al Route Model Binding nella documentazione di Laravel!
Conclusioni
Al termine di questo tutorial, sarai in grado di definire percorsi per varie entità della tua applicazione web, impostare dei parametri per i percorsi e dei criteri di accettazione o rifiuto dei parametri in input.