Quando vediamo un nuovo framework, come creare le rotte è una caratteristica fondamentale da cui non si può prescindere. Vediamo ora l’estrema facilità di creare le rotte con Laravel, inizieremo a vedere il modo base di crearle per arrivare sino alle potenzialità più avanzate delle rotte in Laravel.
Contents
La nostra prima rotta personalizzata
Andiamo nella cartella routes che si trova nella root della nostra applicazione, se la nostra versione è recente, dovremmo trovare quattro file .php, apriamo quello web.php e dovremmo già trovare la nostra prima rotta, quella è la rotta che ci mostra la pagina iniziale di Laravel.
Route::get('/', function () { return view('welcome'); });
Possiamo già vedere come funzioni in maniera semplice la dichiarazione di una rotta, come primo parametro del get passiamo il path, come secondo la funzione anonima che verrà eseguita. Ora proviamo ad aggiungere noi una rotta e quindi scriviamo subito sotto la rotta esistente:
Route::get('/ciao', function () { return "ciao mondo"; });
Ecco il classico ciao mondo, quindi dopo aver digitato sul terminale il comando php artisan serve, andiamo a verificare sul nostro browser 127.0.0.1:8000/ciao ed ecco che vedremo magicamente comparire la nostra scritta “ciao mondo”. Come detto prima, il primo parametro del get è una stringa che indica il path, poi si apre una funzione anonima che ritorna il contenuto della pagina.
Chiaramente possiamo anche aggiungere delle variabili e quindi facciamo in modo che la pagina ci saluti con il nostro nome:
Route::get('/ciao', function () { $nome = "Massy"; return "ciao ".$nome; });
Creiamo una view
Quando utilizziamo le rotte normalmente torniamo un json oppure una pagina html, in questo secondo caso avremo tutta la potenza di Blade e delle sue view, ma ora visto che ci stiamo concentrando sulle rotte, useremo una semplice pagina php. Dove sono le view nel nostro framework? Andiamo sotto la cartella resources e apriamo views, qui creiamo un file .php, io gli daro come nome home.php e al suo interno scrivo per ora solamente:
echo "ciao mondo";
La rotta invece la trasformo così:
Route::get('/ciao', function () { return view('home'); });
In questo modo verrà caricato il contenuto della pagina home.php.
Passare variabili alle view
Bene ma se volessimo passare una variabile nome come prima? Complichiamo un po’ le cose e passiamolo dalla rotta:
Route::get('/ciao/{nome}', function ($nome) { return view('home', array( 'nome' => $nome)); });
Ecco che abbiamo aggiunto alla componente fissa della rotta una variabile, {nome} che è un qualsiasi valore che scriviamo nell’indirizzo dopo ciao/ . La variabile l’abbiamo intercettata e la passiamo come parametro alla funzione, a questo punto a view come secondo parametro passiamo un array chiave valore, che contiene le variabili che vogliamo utilizzare all’interno della view. La chiave è a nostra discrezione, sarà quella che dovremmo poi utilizzare nella view, il valore è il $nome che abbiamo passato come parametro alla funzione anonima. Bene adesso la nostra variabile è passata alla view e utilizzarla sarà più semplice di quanto si possa pensare. Torniamo quindi in home.php e andiamo a far stampare il nostro “ciao” seguito dal nome che metteremo sulla barra degli indirizzi:
echo "ciao $nome";
Solo questo? esattamente… Ora se sul nostro browser digitiamo “127.0.0.1:8000/ciao/massimiliano” ecco che la risposta a video sarà “ciao massimiliano”.
Ora andiamo a giocare un po’ con la nostra rotta, facciamo qualche altra semplice modifica, in questo modo:
Route::get('/ciao/{nome?}', function ($nome = "Nessuno") { $nome = ucfirst ( $nome ); return view('home', array( 'nome' => $nome)); });
Abbiamo fatto due piccole cose, una è quella di mettere la prima lettera del nome in maiuscolo, ma questo solo perchè non sopportavo di vederla ancora in minuscolo. La seconda è ben più importante, abbiamo introdotto nel parametro del path della rotta un punto interrogativo vicino alla parentesi graffa di chiusura della parte dinamica della rotta. Il punto interrogativo sta a significare che quella variabile è opzionale, chiaramente a questo punto abbiamo dovuto dare al parametro che viene passato nella funzione anonima seguente, un valore di default. Quindi ora se digiterò 127.0.0.1:8000/ciao sul nostro browser, il nome non verrà passato alla funzione anonima seguente che quindi come valore di default avrà “Nessuno”, il risultato sarà ‘ciao Nessuno’.
Passare più parametri alla rotta
Posso naturalmente anche passare più parametri alla rotta, quindi posso trasformarla in questo modo:
Route::get('/ciao/{nome}/{cognome}', function ($nome, $cognome) { $nome = ucfirst ( $nome ); $cognome = ucfirst ( $cognome ); return view('home', array('nome' => $nome, 'cognome' => $cognome)); });
Il tutto è abbastanza facile, il primo parametro sarà il nome e il secondo il cognome. Mentre la pagina home.php la trasformiamo così :
echo "ciao $nome $cognome";
Se sul nostro browser digitiamo http://127.0.0.1:8000/ciao/massimiliano/salerno avremo come risposta “ciao Massimiliano Salerno”.
Rotte Avanzate
Espressioni regolari
Per le nostre rotte possiamo anche utilizzare delle espressioni regolari che indicano che caratteristiche deve avere la parte variabile della rotta. Andiamo a creare una nuova rotta:
Route::get('salve/{nome}', function ($nome){ return "salve $nome"; })->where('nome', '[a-z]+');
Questa volta per comodità non abbiamo usato una view, tutto è molto simile a quanto visto precedentemente, però c’è dopo il get la chiamata a where, con all’interno la variabile come primo parametro e come secondo l’espressione regolare corrispondente, quindi stiamo dicendo che la variabile nome della rotta deve essere avere solo le lettere minuscole, in questo modo se digitate come indirizzo sul browser http://127.0.0.1:8000/salve/massimiliano vi ritornerà “salve massimiliano”, ma se digitate http://127.0.0.1:8000/salve/Massimiliano, Laravel vi comunicherà che la rotta non esiste.
Continuiamo quindi a giocare passando diversi parametri con diverse espressioni a regolarli, cambiamo quindi così la nostra rotta:
Route::get('salve/{nome}/{cognome}/{eta}', function ($nome, $cognome, $eta){ return "$nome $cognome ha esattamente $eta anni"; })->where('nome', '[a-z]+')->where('cognome', '[a-z,A-Z]+')->where('eta', '[0-9]+');
Allora abbiamo preso 3 parametri dalla rotta e dato 3 parametri alla funzione, e sotto abbiamo ora 3 where. Quindi in questo modo accettiamo che la parte di indirizzo del nome sia esclusivamente minuscolo, la parte del cognome minuscola o maiuscolo, e la parte dell’età deve essere un numero.
Model Binding
Ora facciamo un bel salto avanti e andiamo a parlare anche di Eloquent e di Model. Grazie al Model binding abbiamo la possibilità con Laravel di iniettare un’istanza di un modello Eloquent direttamente in una rotta.
Allora andiamo a creare il controller per gli utenti tramite il seguente comando nel terminale:
php artisan make:controller UserController -r
concentriamoci ora su questa funzione che abbiamo nel controller appena creato:
public function show($id) { // }
Normalmente dovremmo trasformarla così:
public function show($id) { $user = User::find($id); if(!$user) return response()->json('Errore nessun utente con id '. $id); return response()->json(['data' => $user]); }
Creiamo anche la rotta:
Route::get('user/{id}', 'UserController@show');
Una volta creata la rotta, se abbiamo database e utente nella cartella user avremo il nostro json con la risposta in pagina.
Grazie al model binding possiamo fare direttamente così:
public function show(User $user) { return response()->json(['data' => $user]); }
Modifichiamo anche la rotta:
Route::get('user/{user}', 'UserController@show');
Ed ecco la magia, Laravel ha capito che il parametro è un oggetto di tipo Utente e tramite l’id ha eseguito automaticamente la query.
Ok ma se la nostra entità non ha id come chiave primaria? Diamo questo comando dal terminale:
php artisan make:controller PostController -r -m Post
Con questo andiamo a creare il controller e anche il modello, dobbiamo a quel punto creare la migrazione e lo facciamo con il seguente comando da terminale:
php artisan make:migration create_posts_table
Ora andiamo a cambiare la nostra migrazione e andiamo ad inserirvi i seguenti campi:
public function up() { Schema::create('posts', function (Blueprint $table) { $table->string('code', 10)->primary(); $table->string('title'); $table->string('text'); $table->timestamps(); }); }
Abbiamo creato il campo code come primary key. Ora andiamo a generare la tabella e aggiungiamo un dato anche direttamente sul db. Per generare la tabella dovremo lanciare il seguente comando dal terminale:
php artisan migrate
Se il nostro modello non ha come chiave id, dobbiamo specificarlo nel modello, dobbiamo creare una funzione per impostare quale sia la chiave identificativa, aggiungiamo quindi questa funzione nel modello Post:
public function getRouteKeyName() { return 'code'; }
Bene ora non ci rimane che impostare le rotte:
Route::resource('post', 'PostController');
Ora in PostController andiamo a modificare la funzione show in questo modo:
public function show(Post $post) { return response()->json(['data' => $post]); }
A questo punto avremo il dato del nostro post.
Separare le rotte
Potrebbe essere buona norma in un sito molto grande separare le rotte in diversi file, se vediamo dentro routes già troviamo 4 tipi di rotte php (api, channels, console, web). Ora andiamo a crearne un’altra per le nostre rotte, quindi sotto routes andiamo ad aggiungere test.php. andiamo ad aggiungere la nostra unica rotta:
Route::get('test', 'TestController@example');
Chiaramente se ora proviamo ad usare questa rotta non ci riusciremo, perchè Laravel ancora non sa che il file test.php definisce una serie di rotte. Andiamo quindi a comunicarglielo, apriamo la cartella Providers, troveremo il file RouteServiceProvider.php, qui andremo ad aggiungere il seguente codice:
protected function mapTestRoutes() { Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/test.php')); }
In questo modo abbiamo creato una funzione che va a prendere le rotte da routes/test.php, ora bisogna solo richiamarla e lo faremo nella funzione map in questo modo:
public function map() { $this->mapApiRoutes(); $this->mapWebRoutes(); $this->mapTestRoutes(); // }
Ora se andiamo a verificare all’indirizzo http://127.0.0.1:8000/admin/test troveremo la nostra pagina. Chiaramente ci sarà bisogno di andare a creare il controller e possibilmente la view.
Avrete notato come in realtà, con molta probabilità, il path admin lo vorremmo in tutte le rotte che aggiungermo in test.php, andarlo a scrivere per ogni rotta è scomodo e può essere causa di errore, senza considerare che se un giorno decidessimo di cambiarlo dovremmo farlo in tutte le rotte.
Quindi andiamo a modificare in RouteServiceProvider la nostra funzione appena creata in questo modo:
protected function mapTestRoutes() { Route::prefix('admin') ->middleware('web') ->namespace($this->namespace) ->group(base_path('routes/test.php')); }
Molto meglio, gli stiamo dicendo con prefix che tutte le rotte in test.php devono avere come prefisso admin.
di Massimiliano Salerno