05 mappare rotte Laravel tramite Controller

Come abbiamo visto possiamo mappare una rotta, far passare i dati di questa rotta nei parametri della funzione anonima, fare un controllo sui tipi di dato e fare restituire dei risultati. Il problema di questo approccio sta nel fatto che se implementiamo diverse logiche nel routing per numerose rotte, otterremo un codice disordinato che va contro la filosofia del sistema MVC. Infatti in quest’ultimo deve essere il controller a gestire la logica delle richieste. La soluzione ottimale è creare un nuovo controller che gestisca le richieste, siano esse GET, POST, PUT, DELETE.

Andiamo ad inserire una rotta di default per la nostra home ( / )

Route::get('/', );

adesso come secondo parametro del metodo get() invece che una funzione andiamo ad inserire un controller specificandone il nome e lanciando il metodo index() tramite l’operatore chiocciola ( @ )

Route::get('/','HomeController@index');

Creare un controller

andiamo ora a creare il controller chiamato HomeController{} definendo il metodo index().

Esistono 2 modi per creare un controller in laravel:

metodo manuale

aggiungiamo dentro App\Http\Controllers il file HomeController.php e creiamo la classe HomeController{}

class HomeController {
 public function index() {
  return view('welcome');
 }
}

il metodo index() appena creato lancerà la vista predefinita welcome.blade.php. Se apriamo la home del sito, riceveremo l’errore di file/classe non trovate. Dobbiamo quindi inserire nel controller il namespace

namespace App\Http\Controllers;

class HomeController {
 public function index() {
  return view('welcome');
 }
}

e aggiungere il percorso completo del controller anche nella rotta

Route::get('/','App\Http\Controllers\HomeController@index');

Ora tutto funziona, ma specificare sempre tutti i percorsi completi in ogni rotta e inserire i namespace ogni volta nei vari controlli, non è una soluzione ottimale. Laravel permette di dichiarare il namespace all’interno del provider RouteServiceProvider nella variabile protetta $namespace che di default possiamo trovare commentata o impostata a null

protected $namespace = 'App\Http\Controllers';

ora carichiamo la varibile nel middleware web poche righe più in basso

Route::middleware('web')
 ->namespace($this->namespace)
 ->group(base_path('routes/web.php'));

infine possiamo dichiarare direttamente solo il nome del controller nella rotta

Route::get('/','HomeController@index');

alternativa migliore

Da laravel 8 in su esiste un modo più veloce per risolvere il problema del namespace, prima dichiariamo la variabile $namespace a null in RouteServiceProvider

protected $namespace = null;

ora nella rotta, passiamo come secondo parametro un array

Route::get('/',[ \App\Http\Controllers\HomeController::class,'index']);

Nell’array avremo la classe come primo indice ( HomeController::class ) e il metodo da lanciare come secondo dato dell’array ( index() ). In effetti possiamo ancora migliorare specificando all’inizio del file di usare la classe HomeController, in modo da mettere poi nelle rotte la classe e il metodo nell’array senza specificare tutto il percorso

use App\Http\Controllers\HomeController;

Route::get('/',[ HomeController::class,'index']);

metodo console

Dalla riga di comando, possiamo sfruttare il punto di ingresso di laravel artisan per numerose operazioni, con il comando route:list visualizziamo l’elenco delle rotte e la lista dei controller e vedremo aggiunto anche il nostro appena creato precedentemente, insieme al suo namespace.

| Domain | Method | URI | Name | Action | Middleware |
+--------+--------+----------------------+------+----------------------+
|       | GET|HEAD | / | | App\Http\Controllers\HomeController@index | web

a questo punto creiamo il controller con il comando make:controller, visualizziamo prima l’help per guardare le opzioni con il parametro –help.

php artisan make:controller --help

Creiamo un nuovo controller WelcomeController

php artisan make:controller WelcomeController

ecco il contenuto del controller creato da riga di comando

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
//
}

Come si vede viene aggiunto automaticamente il namespace, ci aggiunge l’accesso alla richiesta caricando la classe Request{}, infine crea la classe come estensione della classe predefinita Controller{}.

Vogliamo quindi mappare la prima rotta che avevamo dichiarato

Route::get('/{nome?}/{cognome?}/{eta?}', function($nome='',$cognome='',$eta=0) {
 return 'welcome '.$nome.' '.$cognome. ' '. $eta;
})
  ->where([
   'nome' => '[a-zA-Z]+',
   'cognome' => '[a-zA-Z]+',
   'eta' => '[0-9]{0,3}'
]);

utilizzando il controller WelcomeController e il metodo web() che creiamo

Route::get('/{nome?}/{cognome?}/{eta?}', [WelcomeController::class,'web'])

dobbiamo però dichiarare il controller nel files, lo aggiungiamo usando le dichiarazioni use multipli di php7 avvolgendo i controllers tra parentesi graffe e separandoli da virgola

use App\Http\Controllers\{HomeController, WelcomeController};

aggiungiamo la funzione web() nel nostro WelcomeController

class WelcomeController extends Controller
{
public function web($nome='',$cognome='',$eta=0)
{
return 'welcome ' . $nome . ' ' . $cognome . ' ' . $eta;
}
}

mappare parametri aggiuntivi

http://localhost:8000/pippo/paperino/15

pippo/paperino/15 sono segmenti della rotta, ma io posso far passare parametri GET tipo

http://localhost:8000/pippo/paperino/15&lang=en

per catturare possiamo usufruire della Request che era stata dichiarata dal terminale di default nella creazione del controller

use Illuminate\Http\Request;

a questo punto nella funzione web(), dopo i primi 3 parametri della rotta corrispondenti ai 3 segnaposti (nome, cognome, eta), possiamo aggiungere la Request con un nome a piacere, ma che chiamo $req per comodità

public function web($nome='',$cognome='',$eta=0, Request $req )

laravel a questo punto ci passerà un oggetto di tipo request con cui avremo accesso ai parametri della richiesta tramite il metodo input() fornito dall’oggetto request

$lang = $req->input('lang');

a questo punto basterà fare uno switch per gestire i casi delle opzioni lingua

public function web($nome='',$cognome='',$eta=0, Request $req ) {
 $lang = $req->input('lang');
 switch ($lang) {
  case 'en':
   $messaggio = 'welcome ' . $nome . ' ' . $cognome . ' ' . $eta .' old';
   break;
  case 'it':
   $messaggio = 'benvenuto ' . $nome . ' ' . $cognome . ' ' . $eta. ' anni';
 }
 return $messaggio;
}