Laravel si potrebbe definire in poche parole, come una boccata d'aria fresca.
Lasciatemi partire dalla mia esperienza personale. Negli ultimi due anni, sia per lavoro che per hobby, ho lavorato molto con PHP ed i suoi framework. Ne ho visti alcuni, rimanendo legato essenzialmente a CodeIgniter. Quando ho scoperto Laravel, però, le cose sono cambiate del tutto. Ho deciso così di proporre questa piccola “miniserie” di articoli dedicati, per spiegarvi meglio cosa intendevo con quel “le cose sono cambiate del tutto”. Basta parlare però, veniamo subito al punto.
Che cos'è Laravel
Laravel è un framework PHP, ovviamente orientato alla programmazione ad oggetti ed al pattern architetturale MVC (che se non conoscete consiglio caldamente di studiarvi) e all'eliminazione di uno dei nostri peggiori nemici, lo spaghetti code. Presenta, inoltre, un comodo sistema di bundles per “pacchettizzare” i nostri software (parliamo quindi di HMVC), in modo tale da creare applicazioni sempre più sofisticate e al tempo stesso facilmente manutenibili.
La sua storia comincia nel 2011, quando Taylor Otwell decide di “rendere lo sviluppo web più facile e divertente, perché è quello che amo fare”. Da allora di strada ne è stata fatta, nonostante siano passati solo poco meno di due anni.
Attualmente, infatti, il progetto è arrivato alla versione 3 (in realtà esiste anche una versione 4, ma è ancora nella fase alpha, dunque non verrà considerata in questa sede) e ha sicuramente tante buone carte da giocare. Anzi, ottime carte come un sistema di authentication facile da usare, un ORM già pronto (Eloquent) oppure un command line tool integrato (Artisan).
Se vogliamo provarlo basta scaricare l'ultima versione disponibile all'indirizzo http://laravel.com/. Il tasto da premere è Download arancione in alto a destra.
Ci verrà chiesto di scaricare un archivio zip: accettiamo ed estraiamone i file mettendoli in una cartella del nostro webserver. Adesso… non rimane da fare più niente perché l'installazione di Laravel è già conclusa!
In base alle funzionalità che usate potrebbero esserci altri parametri da impostare (la connessione al database, per esempio) ma per cominciare a fare i primi passi è più che sufficiente ciò che avete fatto.
Navighiamo con il browser nel percorso che abbiamo scelto con seguito da un “public”, ad esempio http://localhost:8080/laravel/public/, ed ecco il risultato.
Facile, vero? Continuate a leggere, nella prossima pagina osserveremo la struttura dei file ed analizzeremo meglio la sintassi usata tramite qualche esempio pratico.
Routes o Controller
Scegliere è importante! Soprattutto per chi viene da realtà diverse e sta conoscendo una nuova tecnologia. Per la gestione della logica di una qualsiasi applicazione, Laravel tiene in gran considerazione questo concetto.
Quando ci troviamo a decidere come il nostro progetto dovrà “comportarsi”, ecco cosa possiamo fare:
- Utilizzare le Routes, collegando una specifica richiesta ad un set di istruzioni ben precise;
- Utilizzare i Controller¸ come nella migliore tradizione MVC (chi ha già utilizzato altri framework sa bene di cosa sto parlando);
Ovviamente, in entrambi i casi avremo pro e contro.
L'uso delle Routes può essere consigliato in caso di siti non troppo complessi, o magari per effettuare delle prove senza dover scrivere troppo codice. I Controller, invece, sono particolarmente adatti quando la nostra applicazione comincia ad essere complessa e abbiamo bisogno di un certo ordine. Vediamo insieme qualche esempio di entrambe queste soluzioni.
Le Routes
Per quanto riguarda le Routes, tutte le istruzioni dovranno essere definite nel file application/routes.php. Se state aprendo il file per la prima volta, molto probabilmente vi troverete davanti del codice come il seguente:
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Simply tell Laravel the HTTP verbs and URIs it should respond to. It is a | breeze to setup your application using Laravel's RESTful routing and it | is perfectly suited for building large applications and simple APIs. | | Let's respond to a simple GET request to http://example.com/hello: | | Route::get('hello', function() | { | return 'Hello World!'; | }); | | You can even respond to more than one URI: | | Route::post(array('hello', 'world'), function() | { | return 'Hello World!'; | }); | | It's easy to allow URI wildcards using (:num) or (:any): | | Route::put('hello/(:any)', function($name) | { | return "Welcome, $name."; | }); | */ Route::get('/', function() { return View::make('home.index'); }); /* |-------------------------------------------------------------------------- | Application 404 & 500 Error Handlers |-------------------------------------------------------------------------- | | To centralize and simplify 404 handling, Laravel uses an awesome event | system to retrieve the response. Feel free to modify this function to | your tastes and the needs of your application. | | Similarly, we use an event to handle the display of 500 level errors | within the application. These errors are fired when there is an | uncaught exception thrown in the application. The exception object | that is captured during execution is then passed to the 500 listener. | */ Event::listen('404', function() { return Response::error('404'); }); Event::listen('500', function($exception) { return Response::error('500'); }); /* |-------------------------------------------------------------------------- | Route Filters |-------------------------------------------------------------------------- | | Filters provide a convenient method for attaching functionality to your | routes. The built-in before and after filters are called before and | after every request to your application, and you may even create | other filters that can be attached to individual routes. | | Let's walk through an example... | | First, define a filter: | | Route::filter('filter', function() | { | return 'Filtered!'; | }); | | Next, attach the filter to a route: | | Route::get('/', array('before' => 'filter', function() | { | return 'Hello World!'; | })); | */ Route::filter('before', function() { // Do stuff before every request to your application... }); Route::filter('after', function($response) { // Do stuff after every request to your application... }); Route::filter('csrf', function() { if (Request::forged()) return Response::error('500'); }); Route::filter('auth', function() { if (Auth::guest()) return Redirect::to('login'); });
Osserviamo la prima istruzione:
Route::get('/', function()
{
return View::make('home.index');
});
Più che sulle istruzioni all'interno del blocco, concentriamoci sul blocco stesso.
Quello che stiamo facendo, al momento, è utilizzare la classe “Route” (che consente di gestire tutto ciò che riguarda le Routes), richiamando il metodo statico get()
. Questo metodo ha due argomenti in input:
- Una stringa, che corrisponde poi all'indirizzo da mappare;
- Una closure da eseguire quando viene richiamato quell'indirizzo;
In questo caso specifico, con la stringa "/" stiamo indicando a Laravel che deve eseguire le istruzioni dentro la closure quando l'utente si trova sulla pagina principale dell'applicazione.
Volendo fare un esempio chiarificatore, supponiamo di avere delle istruzioni per visualizzare la pagina “login” ad un utente. Se lavorassimo su un sito su dominio (che chiameremo, ad esempio, www.nomeoriginale.it) la pagina di login si troverà in corrispondenza dell'indirizzo www.nomeoriginale.it/login. Ecco cosa dovremo scrivere nel file routes.php.
Route::get('login', function(){
// istruzioni per la schermata di login
});
Come già detto in precedenza, le Routes sono molto utili nel caso di piccole applicazioni. Cosa succede, però, quando c'è bisogno di strutturare le cose in maniera diversa? Immaginate di avere un software piuttosto complesso, che magari ha un centinaio di pagine diverse in svariate “sezioni”. L'utilizzo delle Routes comincerebbe ad essere un po'… pesante, vero?
I Controller
È il momento di dare un'occhiata ai Controller. Li troviamo nella cartella application/controllers
del nostro progetto. Non perdiamoci troppo nella teoria e passiamo subito alla pratica: ecco un esempio di codice pronto:
class User_Controller extends Base_Controller
{
public function action_index() {
// pagina del profilo
}
public function action_login() {
// pagina di login
}
public function action_logout() {
// procedura di logout
}
}
Attenzione:
Per usare un controller bisogna prima dichiararlo nel file routes.php, tramite il metodo statico
controller()
. Nel nostro caso, ad esempio, dobbiamo
scrivere:
Route::controller('user');
Avendo molti Controller, inoltre, si possono dichiarare tutti insieme senza dover ripetere più volte la stessa istruzione. Basta, infatti:
Route::controller(Controller::detect());
Dopo questa doverosa premessa possiamo avvicinarci al codice.
La prima cosa che notiamo è sicuramente la nomenclatura. Il nome di un singolo controller va specificato infatti nella formula
NOME_Controller extends
.
Base_ControllerBase_Controller
è la classe dalla quale partire per realizzare tutti gli altri controller.
Non è l'unica cosa che balza all'occhio: in corrispondenza di ogni metodo, infatti, c'è il prefisso
action_
.
Non è messo li per caso, ovviamente: tramite questo prefisso indicheremo i metodi che devono essere collegati ad un URL ben definito.
Ad esempio, se volessimo raggiungere la pagina di login che abbiamo indicato
(action_login
), l'indirizzo preciso sarà: www.nomeoriginale.it/user/login.
Non usando il prefisso action_
, semplicemente, il metodo sarà sì utilizzabile, ma non
sarà richiamabile da URL.
Nel codice che abbiamo davanti c'è anche il metodo action_index
. Si tratta del metodo “principale”
del controller, richiamato quando non specifichiamo altro nell'URL se non il
nome del controller stesso. Dunque, per richiamare il metodo action_index
l'URL da usare sarà www.nomeoriginale.it/user.
Prima di continuare una nota importante:
avere a disposizione una classe Base_Controller
di partenza è un elemento a nostro indubbio vantaggio. Nel caso di modifiche pesanti, infatti, ogni
cambiamento a questa classe si ripercuote sull'intero sistema.
Adesso che abbiamo visto i Controller e le Routes abbiamo un'idea chiara su come gestire la logica della nostra applicazione. Dobbiamo però separare la
presentazione da tutto questo: come fare? Passiamo ad osservare le Views.
Le Views
Chiunque abbia già avuto a che fare con un qualsiasi framework avrà sicuramente presente il concetto di View: le View sono lo strumento che vi permette di separare la logica dell'applicazione dalla sua presentazione, evitando quell'orribile fenomeno conosciuto come Spaghetti Code.
Per vedere il tutto subito all'opera, creiamo un nuovo file nella cartella application/views, chiamandolo first_view.php. Scriviamo al suo interno questo semplice codice HTML:
<html>
<head>
<title>Benvenuto!</title>
</head>
<body>
<h1>Benvenuto!</h1>
<p>Ciao, e benvenuto nel controller User!</p>
</body>
</html>
Passiamo quindi al nostro controller User, visto poco fa. All'interno del metodo action_index
inseriamo questa semplice istruzione:
return View::make('first_view');
Avviamo la nostra applicazione, richiamando l'url user, ed il risultato sarà la pagina HTML che abbiamo creato poco fa.
Cos'è successo? Abbiamo appena collegato una View ad un Controller. Il metodo make()
della classe View ritorna la view che abbiamo creato nel file first_view.php. Semplice, vero?
Vediamo adesso come collegare dei dati ad una View. Cambiamo leggermente il codice di action_index
:
public function action_index(){
$view = View::make('first_view');
$view->firstName = 'Francesco';
return $view;
}
Passiamo adesso alla view “first_view.php”, modificando il codice del tag <p> come segue:
<p>Ciao <?php echo $firstName; ?>, e benvenuto nel controller User!</p>
Osserviamo adesso l'output della pagina: abbiamo appena utilizzato una view collegandoci dei dati elaborati dinamicamente nel controller.
Non ci sono dei limiti alle variabili che possono essere collegate: basta specificare un nome in fase di assegnazione e richiamare il campo come variabile all'interno della view. Proprio come nell'esempio, in cui $view->firstName
diventa $firstName
.
Allo stesso modo non ci sono limiti alla “tipologia” di variabile che possiamo collegare ad una view: qui abbiamo usato una semplice stringa per fare un esempio veloce, ma potremmo collegarci i risultati di una query o i risultati di una chiamata ad altri metodi, di altri controller, librerie e così via.
I Filtri
Nelle applicazioni molto grandi capita molto spesso di avere delle funzionalità che è bene “condividere” in tutto il sistema. Proviamo ad immaginare:
abbiamo creato un bel CMS potente, performante, che permette di gestire di tutto e di più del nostro nuovo sito.
Il nostro backend presenta molte funzionalità: precisamente una quarantina di pagine diverse. Ognuna di queste, ovviamente, deve fare un controllo per
vedere se l'amministratore è loggato oppure no.
Abbiamo sistemato tutto nel nostro controller Backend, in
backend.php. La domanda sorge spontanea: “non dovrò mica fare questo controllo in ogni singolo
metodo, vero?”
Assolutamente no: sia per quanto riguarda le Routes che i Controller, Laravel offre un sistema di filtri per personalizzare ancora di più
il codice che stai scrivendo (alleggerendo il tuo lavoro in modo non indifferente). Vediamo di cosa si tratta.
Cominciamo dai Filtri per le Routes. Nel file routes.php possiamo già vederne qualche esempio.
Route::filter('auth', function() {
if (Auth::guest()) return Redirect::to('login');
});
Cosa è successo?
Abbiamo dichiarato un nuovo filtro, chiamandolo auth
. Come il nome può suggerire, questo filtro si occupa di controllare se l'utente
amministratore ha effettuato l'accesso oppure no. Nel caso non sia autenticato il filtro blocca tutto ed effettua un redirect alla route “login”.
Evitiamo di concentrarci sulla sintassi interna al filtro, per ora: non rimane altro che collegare il filtro alla route che ci interessa. Ad esempio, nel
caso avessimo una route “pannello”:
Route::get('pannello', array('before' => 'auth', function() {
// l’amministratore è autenticato!
}));
La chiave before
indica che il filtro deve essere eseguito rigorosamente prima delle istruzioni contenute nella route. Nel caso le
istruzioni dovessero essere eseguite dopo, invece, basta usare after
.
Si possono anche usare più filtri insieme. Ad esempio:
Route::get('pannello', array('before' => 'auth|altro_filtro', function() {
// l'amministratore è autenticato!
}));
Come si può vedere, lo spazio di manovra è abbondante.
Passiamo adesso ad esaminare i filtri per i Controller. Riprendiamo il nostro esempio iniziale, il controller “Backend” con i suoi quaranta metodi.
Come fare se volessimo aggiungere un filtro “auth” ad ogni pagina del backend? Semplice:
class User_Controller extends Base_Controller {
public function __construct(){
$this->filter('before', 'auth');
}
// qui vanno i metodi del controller…
}
Ecco fatto. Adesso ad ogni metodo del controller verrà applicato il filtro di autenticazione prima di fare qualsiasi altra operazione.
Attenzione però, c'è un problema. Nel nostro controller abbiamo anche il metodo
login
. Dovremmo agganciare il filtro a tutti i metodi tranne
login
, appunto. Altrimenti entreremmo in un loop infinito!
Niente paura, anche qui la soluzione è semplice:
$this->filter('before', 'auth');
Lo facciamo diventare:
$this->filter('before', 'auth')->except(array('login'));
Una sola istruzione per gestire autenticazione ed eccezione.
Ovviamente la situazione può essere capovolta: anziché usare la parola except
basterà usare la parola chiave
only
per agganciare un filtro ad uno o più
metodi.
Ad esempio:
$this->filter('before', 'auth')->only(array('login'));
Conclusione
Laravel mette a disposizione degli strumenti molto comodi: controller, routes e filtri sono solo alcuni di questi. Nella prossima parte di questo excursus
introduttivo nel framework concentreremo la nostra attenzione sulla sintassi e la sua semplicità: vedremo come
ottenere molto utilizzando una sola
linea di codice.