Sei sulla pagina 1di 103

Laravel 5 in pratica

Una guida semplice per realizzare applicazioni di qualità

Francesco Lettera
This book is for sale at http://leanpub.com/laravel5inpratica

This version was published on 2016-01-12

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2014 - 2016 Francesco Lettera


Indice

Premessa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Perché Laravel? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

A chi è rivolto questo libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

Conoscenze richieste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

Download codice di esempio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

In profondità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

Per Iniziare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Precisazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Installazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Rimuovere la cartella PUBLIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

Autenticazione bella e pronta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11


Migration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Registrazione, login e logout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Blade, un template chiaro e snello . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15


Strutture di controllo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
IF e altre istruzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

Scarichiamo pacchetti per un Form di lusso . . . . . . . . . . . . . . . . . . . . . . . . . . 19


Un nuovo inizio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

Adoro gli address book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23


Database, onnipresente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Controller dell’address book: i metodi principali . . . . . . . . . . . . . . . . . . . . . . . 25
Store, immagazzinare i dati nel db . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Il nostro elenco dati aggiornato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
INDICE

Modificare non guasta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34


Cancellare è, a volte, opportuno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

Refactoring a piccole dosi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39


Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

Eloquent, Factory, Faker e impostori vari . . . . . . . . . . . . . . . . . . . . . . . . . . . 43


Model Factories per riempire a sbafo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Faker, model e Seeder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

Eloquent: un soffice inizio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49


Relazione uno a molti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Uno a molti: operazione inversa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Uno a molti nella vita reale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

Eloquent: relazioni a triangolo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54


Prestiamo libri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Ebook in prestito a chi? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

Eloquent: relazioni complesse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60


Le polimorfiche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Abbattere le query: Eager Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

Middleware, il tuo cane da guardia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65


Il setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
La route e il Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

Paginare è la miglior cosa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69


Seeding dei dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Simple pagination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Paginare con Eloquent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Paginazione personalizzata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

Caching, non solo quando hai poche risorse . . . . . . . . . . . . . . . . . . . . . . . . . . 74


Dove si configura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Salvare dati in cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Recuperare i dati in cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Aggiornare i dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
La cache è per sempre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Cancellare la cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
INDICE

Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Le mie classi, i miei Helper: tutto mio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78


Classi: dove e come . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Helper: dove e come . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

Service Provider, un pacchetto cotto e mangiato . . . . . . . . . . . . . . . . . . . . . . . . 82


La nostra classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Il nostro ServiceProvider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
E i metodi “statici” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Precisazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

View composer: evitare ridondanze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88


Immancabile template bootstrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
La tabella . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Variabile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Download dell’applicazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

Appendice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Laravel 5.2, le novità . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Premessa
Questo libro segna il naturale prosieguo del “fortunoso” mio precedente “Laravel in pratica (versione
4)”. Non occorre aver letto quest’ultimo. Il vecchio lettore (o affezionato lettore) aggiornerà il suo
knowhow su Laravel, il nuovo ne assaporerà la magia e la potenza.

1
Perché Laravel?
Laravel è un framework PHP agile ed effervescente ideato da Taylor Otwell. Ha una sintassi unica
e intuitiva che lo differenzia dagli altri framework. Non solo, Laravel offre un efficace RESTful
routing, un template engine semplice da utilizzare ed è basato su Composer: il tool per eccellenza
per la gestione di pacchetti di terze parti. Laravel utilizza, inoltre, molti componenti di Symfony, un
altro potente e ricco framework. Una scelta che garantisce codice ben testato.

2
A chi è rivolto questo libro
A chi vuole utilizzare subito Laravel. Questo libro ha un approccio pratico. Il mio obiettivo è aiutarti
a realizzare un progetto web funzionante, sin dal primo capitolo. Eventuali approfondimenti sul
framework saranno trattati in un secondo momento. Come webdeveloper sono spesso preso dalla
smania di provare l’ultima novità. Se me ne innamorò, approfondisco. Può non essere un approccio
ortodosso, ma se si ha un lavoro, non c’è molto tempo libero per studiare e migliorarsi: tutte le
decisioni per intraprendere un nuovo studio, quindi, devono essere ponderate. Provare “sul campo”
Laravel ti aiuterà a decidere se questo è il framework giusto per te. Non cianciamo oltre, buona
lettura.

3
Conoscenze richieste
E’ richiesta la conoscenza di PHP, perché Laravel è scritto in PHP. E’ richiesto l’utilizzo e la
conoscenza base di Composer. Il web è pieno di tutorial su Composer. Con Composer puoi scaricare
pacchetti a prescindere dal framework: se non lo si è mai utilizzato occorre esercitarsi un po’ prima
di affrontare questo testo.

4
Download codice di esempio
Ogni qualvolta raggiungeremo un traguardo, sarà disponibile il link per scaricare il codice dell’appli-
cazione che diventerà, passo dopo passo, sempre più complessa. Il presente libro parte dalla versione
Laravel 5.1.x. Il mio consiglio è utilizzare questa versione per seguire con agilità gli esempi.

5
In profondità
In appendice al libro è presente una sezione chiamata “In profondità” che affronterà nel dettaglio
alcuni aspetti teorici omessi durante la stesura dei capitoli. Non è una sezione esclusivamente
teorica. Saranno presenti, invece, ulteriori esempi che chiariranno altrettanti aspetti di Laravel.
Sono in appendice perché voglio che non intralcino il normale flusso dei capitoli. Nel progetto che
realizzeremo non sarà possibile, infatti, trattare tutte le caratteristiche di Laravel ed è qui che entra
in gioco la sezione “In profondità”.

6
Feedback
Mi farebbe piacere ricevere osservazioni su quanto ho scritto. Ecco come contattarmi:

• fralette@gmail.com
• Twitter: @FrancescoLetter

7
Per Iniziare
Precisazioni
L’installazione di Laravel può essere effettuata in diversi modi e in ambienti diversi (MAMP, Vagrant
BOX, WAMP, Laragon, ecc). Nel corso dei capitoli faremo sempre riferimento al seguente URL per
indicare le pagine del progetto: http://localhost:8888/… Noi utilizzeremo MAMP come ambiente, ma
sono valide tutte le alternative citate.

Installazione
I requisiti minimi per installare Laravel sono i seguenti:

1 PHP >= 5.5.9


2 OpenSSL PHP Extension
3 PDO PHP Extension
4 Mbstring PHP Extension
5 Tokenizer PHP Extension

Se qualcosa va storto durante l’installazione del framework è molto probabile che qualche requisito
non sia stato rispettato.
Laravel utilizza Composer e la stringa per installarlo è la seguente. Nel nostro caso creeremo una
cartella chiamata “laravelbook”, al suo interno, quindi, ci sarà il nostro framework preferito:

1 composer create-project laravel/laravel --prefer-dist

Se tutto funziona a dovere, Laravel è pronto all’uso. All’indirizzo: http://localhost::8888 comparirà a


centro pagina la scritta “Laravel 5”.

Rimuovere la cartella PUBLIC


Vuoi che il tuo progetto abbia nell’URL sempre la cartella PUBLIC? Certo che no. L’abbiamo usata
prima, in fase di installazione, ma adesso è il momento di “nasconderla”.
Mi preme avvisarti che la procedura di seguito descritta potrebbe non essere sufficiente risolvere
questo problema. Purtroppo, tra sistemi operativi diversi, varie versioni di PHP e Apache, non ci si
raccapezza più e non sempre questo tipo di configurazione funziona al primo colpo.

8
Per Iniziare 9

MAMP (Mac)
Con MAMP risulta abbastanza semplice: fai puntare il percorso della tua applicazione direttamente
nella cartella public. E il gioco è fatto. Controlla che il rewrite_module e vhost_alias_module sia
attivo tra i moduli Apache.

WampServer (Win)

Cartelle?
Nell’esempio qui sotto Laravel è installato direttamente nella root principale “www” di
WampServer, ma - come anticipato - si può decidere di creare una sottocartella e chiamarla
“laravelbook” all’interno della quale far “girare” la nostra app.

Prima di tutto abilitiamo il rewrite_module tra i moduli di Apache attraverso il comodissimo admin
di WampServer. Assicuriamoci inoltre che sia abilitato anche il modulo vhost_alias_module: mi è
capitato di vederlo abilitato o meno a seconda della versione di WampServer scaricata. Apriamo
quindi il file C:/wamp/bin/apache/Apachex.x.x/conf/httpd.conf e rimuoviamo il cancelletto (#)
dalla seguente linea

1 #Include conf/extra/httpd-vhosts.conf

Poi spostiamoci sul seguente file:

1 C:\wamp\bin\apache\Apachex.x.x\conf\extra\httpd-vhosts.conf

E aggiungiamo questa configurazione:

1 <VirtualHost *:80>
2 ServerAdmin email@miaemailpersonale.com
3 DocumentRoot "C:/wamp/www/public"
4 ServerName lar.dev
5 </VirtualHost>
6
7 <Directory "C:/wamp/www/public">
8 Options Indexes FollowSymLinks
9 AllowOverride all
10 # onlineoffline tag - don't remove
11 Order Deny,Allow
12 Deny from all
13 Allow from 127.0.0.1
14 </Directory>
Per Iniziare 10

Facciamo attenzione al percorso di DocumentRoot: deve puntare alla cartella public di Laravel. Al
ServerName, invece, diamo un nome di fantasia: lar.dev. Sarà quest’ultimo il nome che utilizzeremo
sul browser per accedere alle tue pagine web.
L’ultimo step riguarda il file hosts di Windows. Questo dovrebbe essere il percorso (potrebbe variare
leggermente in base alla diversa versione di Windows):

1 C:/Windows/System32/drivers/etc

Apriamolo e aggiungiamo questa riga di codice:

1 127.0.0.1 lar.dev

Riavviamo WampServer e - se tutto è andato per il verso giusto - non scriveremo più localhost/-
public, ma lar.dev per accedere al nostro progetto.
Autenticazione bella e pronta
Laravel fornisce, out of the box, un sistema di autenticazione corredato di registrazione. Vediamo
come implementarlo velocemente.
In database troveremo la cartella migrations. A cosa serve?

Migration
Per creare le tabelle del nostro database, Laravel utilizza il suo migration system. Questo sistema
permette la gestione completa delle tabelle. Ma non entriamo nei dettagli. Per il progetto è necessario
creare due tabelle
In database/migrations troveremo due file:

1 - 2014_10_12_000000_create_users_table.php
2 - 2014_10_12_100000_create_password_resets_table.php

Apriamo il primo file. All’interno del metodo up() saranno presenti tutte le modifiche necessarie
alla tabella. Il metodo down ci permetterà di effettuare un rollback della migration: cioè nel caso
della tabella users, questa sarà cancellata.
Il secondo file, invece, creerà la tabella password_resets. Il funzionamento è simile al file precedente.
Ma come fare per creare materialmente le due tabelle? Il primo step è configurare i dati d’accesso al
db. In base al setup effettuato (MAMP, WAMP, Homestead, ecc) creiamo un db (es. laravel). Subito
dopo apriamo il file .env presente nella root della nostra applicazione e indichiamo le credenziali
d’accesso al db nelle opportune variabili.

1 // .env
2 ...
3 DB_HOST=localhost
4 DB_DATABASE=laravel
5 DB_USERNAME=root
6 DB_PASSWORD=root
7 ...

Da riga di comando (posizioniamoci sempre nella root della nostra applicazione) scriviamo:
php artisan migrate

11
Autenticazione bella e pronta 12

E voilà, il nostro database avrà dunque la tabella users e password_resets con i suoi campi. Siamo
pronti per testare l’autenticazione fornita di default da Laravel.

Cos’è .env?
Bella domanda. Per adesso è sufficiente sapere che si avvicina molto ad un file di
configurazione.
Nel corso del libro approfondiremo l’argomento.

Registrazione, login e logout


Tocca al file di route. Apriamolo e indichiamo le “strade” per l’autenticazione:

1 // app/Http/routes.php
2
3 // home
4 Route::get('/home', function(){
5 return view('home.main');
6 });
7
8 // Autenticazione
9 Route::get('auth/login', 'Auth\AuthController@getLogin');
10 Route::post('auth/login', 'Auth\AuthController@postLogin');
11 Route::get('auth/logout', 'Auth\AuthController@getLogout');
12
13 // Registrazione
14 Route::get('auth/register', 'Auth\AuthController@getRegister');
15 Route::post('auth/register', 'Auth\AuthController@postRegister');

Benissimo, mancano però le view. Siamo liberi di crearle come vogliamo purchè siano rispettati i
campi di input, naturalmente. Ecco un suggerimento (preso dalla documentazione ufficiale):
Questo è il form di autenticazione:
Autenticazione bella e pronta 13

1 <form method="POST" action="/auth/login">


2 {!! csrf_field() !!}
3
4 <div>
5 Email
6 <input type="email" name="email" value="{{ old('email') }}">
7 </div>
8
9 <div>
10 Password
11 <input type="password" name="password" id="password">
12 </div>
13
14 <div>
15 <input type="checkbox" name="remember"> Remember Me
16 </div>
17
18 <div>
19 <button type="submit">Login</button>
20 </div>
21 </form>

Questo, invece, quello di registrazione:

1 <form method="POST" action="/auth/register">


2 {!! csrf_field() !!}
3
4 <div>
5 Name
6 <input type="text" name="name" value="{{ old('name') }}">
7 </div>
8
9 <div>
10 Email
11 <input type="email" name="email" value="{{ old('email') }}">
12 </div>
13
14 <div>
15 Password
16 <input type="password" name="password">
17 </div>
18
Autenticazione bella e pronta 14

19 <div>
20 Confirm Password
21 <input type="password" name="password_confirmation">
22 </div>
23
24 <div>
25 <button type="submit">Register</button>
26 </div>
27 </form>

Infine l’homepage verso la quale si sarà rediretti dopo il login o la registrazione:

1 <!-- resources/views/home/main.blade.php -->


2
3 <h1>Homepage</h1>
4
5 <p>Benvenuto!</p>

Andiamo su

1 http://localhost:8888/auth/register

e registriamo l’utente (Sì, lo so, non è formattato. Ma nei capitoli successivi renderemo tutto più
piacevole). Subito dopo risulteremo loggati nella nostra applicazione (e saremo, quindi, redirezionati
verso “/home”). Il db sarà popolato dei dati della nostra registrazione. Se effettuiamo il logout:
http://localhost:8888/auth/logout
possiamo testare il login:

1 http://localhost:8888/auth/login

Insomma un ottimo sistema di autenticazione base. Nei capitoli successivi vedremo come customiz-
zare l’autenticazione e come presentarla con tutti i crismi.
Blade, un template chiaro e snello
Blade è il templating engine di Laravel. E lo andremo ad usare per tutti i nostri progetti. Per intenderci
sarà usato in tutte le nostre view. Per far comprendere a Laravel che stiamo usando blade (non è
obbligatorio, intendiamoci) dobbiamo salvare i nostri file con la seguente estensione .blade.php.
Procediamo creando un file main.blade.php:

1 // resources/views/template/main.blade.php
2 <!doctype html>
3 <html lang="en">
4 <head>
5 <meta charset="UTF-8">
6 <title>Document</title>
7 </head>
8 <body>
9 @section('mioheader')
10 <header>Questo è il mio header</header>
11 @show
12
13 @yield('content')
14
15 </body>
16 </html>

Subito dopo creeremo la nostra prima view:

1 // resources/views/homepage/index.blade.php
2 @extends('template/main')
3 @section('content')
4 Questo è il contenuto della view homepage/index.blade.php
5 @stop

Nel template abbiamo definito le aree. C’è l’area section che contiene informazioni di default. Poi
c’è l’istruzione yield(‘content’) che indica un “segnaposto” utilizzato dalla view index.blade.php per
“incastrarsi” nel template. Nella view homepage/index.blade.php è quindi presente il contenuto
content che si posizionerà al posto di yield(‘content’). Vediamo come utilizzare questi due file.
Agiamo sul file di route. Sì, ma cos’è? E’ il file di rotta che indica a Laravel come muoversi tra
le pagine. Lo scopriremo poco a poco. Per adesso andiamolo ad editare per far funzionare il nostro
template e la nostra view:

15
Blade, un template chiaro e snello 16

1 // app/Http/routes.php
2 Route::get('/homepage', function(){
3 return view('homepage.index');
4 });

Questo codice va inserito alla fine (lasciamo perdere le indicazioni per l’autenticazione). Cosa
abbiamo indicato al file di route? Se si digita http://localhost:8888/laravelbook/homepage¹ Laravel
deve mostrare la view nella cartella homepage. Osserviamo inoltre come la sintassi per indicare un
file all’interno della cartella è la dot notation. Se tutto è andato per il verso giusto, quindi, vedremo
la nostra view all’interno template.

Strutture di controllo
Vediamo come “passare” le variabili all’interno della view. E’ una procedura tanto semplice, quanto
efficace. Partiamo dalla route e andiamo a creare una semplice variabile:

1 // app/Http/routes.php
2 Route::get('/homepage', function(){
3 $data['nome'] = 'Francesco';
4 return view('homepage.index', $data);
5 });

All’interno della view ecco come utilizzarla.

1 // resources/views/homepage/index.blade.php
2 @extends('template/main')
3 @section('content')
4 Caro {{$nome}}, questo è il contenuto della view homepage/index.blade.php
5 @stop

Può accadere che la variabile $nome non sia impostata (i motivi possono essere svariati). Laravel ci
viene in aiuto con una sintassi molto intuitiva. Eccola:

¹http://localhost:8888/laravelbook/homepage
Blade, un template chiaro e snello 17

1 // resources/views/homepage/index.blade.php
2 @extends('template/main')
3 @section('content')
4 Caro {{$nome or 'Anonimo'}}, questo è il contenuto della view homepage/index\
5 .blade.php
6 @stop

Se andiamo, infatti, ad eliminare la variabile dalla route:


Route::get(‘/homepage’, function(){ return view(‘homepage.index’); });
Il risultato sarà: Caro Anonimo…
C’è da sottolineare un aspetto di Blade. Come osservato utilizza le doppie parentesi graffe per
mostrare il valore delle stringhe. Di default Blade esegue l’escaping di qualsiasi entità HTML. Quindi,
è buona norma utilizzare questa sintassi. Perché? Blade ne ha un’altra? Sì. Eccola:

1 Ciao {!! $nome !!}

Qual è la differenza? In questo caso non è eseguito l’escaping. Può accadere, infatti, che sia necessario.

IF e altre istruzioni
Per gestire ulteriore codice all’interno di un template blade, ci sono le onnipresenti istruzioni di
controllo.

1 @if($variabile == 1)
2 <p>Qui va i codice HTML, ad esempio </p>
3 @elseif($variabile == 2)
4 <p>Qui va l'alternativa</p>
5 @endif

Interessante anche l’istruzione @unless

1 @unless(Auth::check())
2 <p>Non sei autenticato</p>
3 @endunless

Loop
Eccoli i nostri loop con altre interessanti istruzioni.
Blade, un template chiaro e snello 18

1 @for ($i = 0; $i < 10; $i++)


2 <p>Il mio contatore segna {{$i}}
3 @endfor
4
5 @foreach ($$utenti as $utente)
6 <p>This is user {{ $utente->id }}</p>
7 @endforeach

Diamo un’occhiata a quest’altra istruzione: ideale quando un array è vuoto o inesistente:

1 @forelse($utenti as $utente)
2 <li>{{ $utente->nome }}</li>
3 @empty
4 <p>Nessun utente</p>
5 @endforelse

Poi, il while:

1 @while (true)
2 <p>Faccio il ciclo</p>
3 @endwhile

Ci sono ulteriori istruzioni per Blade, ma sarebbe inutile elencarle senza “incastrarle” in progetti
reali. Ne parleremo nel testo quando occorrerà usarle.
Scarichiamo pacchetti per un Form di
lusso
Chi ha usato in precedenza Laravel, ed in particolare la versione 4, si ricorderà della gestione dei
form con istruzioni ad hoc. Nella versione attuale (la 5.1), invece, questo pacchetto non è incluso.
Possiamo tuttavia installarlo con composer. In soccorso ci viene in aiuto il sito laravecollective.com²
il cui obiettivo è mantenere i componenti rimossi dal core del framework. Uno di questi è, appunto,
quello che si occupava della gestione dei form.

Un nuovo inizio
Andiamo a reinstallare Laravel. Sì, il mio suggerimento è di reinstallare nuovamente laravel. E’ una
prassi che aiuterà a prendere dimestichezza con il framework e a non impigrirsi.
Con una installazione “fresca” occupiamoci di installare il pacchetto per gestire i Form. Lo stesso
sito citato ci viene in soccorso:
Nel file composer.json aggiungiamo in require:

1 "require": {
2 "laravelcollective/html": "5.1.*"
3 }

Subito dopo lanciamo:

1 composer update

Poi aggiungiamo il nuovo provider nella lista dei provider presenti in /config/app.php

²http://laravelcollective.com

19
Scarichiamo pacchetti per un Form di lusso 20

1 // config/app.php
2 'providers' => [
3 // ...
4 Collective\Html\HtmlServiceProvider::class,
5 // ...
6 ],

Più giù, sempre nello stesso file, aggiungiamo le due classi alias che ci faciliteranno il compito:

1 // config/app.php
2 'aliases' => [
3 // ...
4 'Form' => Collective\Html\FormFacade::class,
5 'Html' => Collective\Html\HtmlFacade::class,
6 // ...
7 ],

Perfetto, siamo pronti per testare il nostro form. Partiamo dalla view alla quale abbiamo dato anche
un tocco di stile:

1 // resources/views/iscrizione/form.blade.php
2
3 <!doctype html>
4 <html lang="en">
5 <head>
6 <meta charset="UTF-8">
7 <title>Iscrizione</title>
8 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5\
9 /css/bootstrap.min.css">
10
11
12 </head>
13 <body>
14
15 <div class="container">
16 <div class="row">
17 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
18 {!! Form::open(['url' => 'iscriviti/dati']) !!}
19
20 <div class="form-group">
21 {!! Form::label('nome', 'Il tuo nome') !!}
22 {!! Form::text('nome', null, ['class' => 'form-control']) !!}
Scarichiamo pacchetti per un Form di lusso 21

23 </div>
24
25 <div class="form-group">
26 {!! Form::label('cognome', 'Il tuo cognome') !!}
27 {!! Form::text('cognome', null, ['class' => 'form-control'])\
28 !!}
29 </div>
30
31 {!! Form::submit('salva', ['class' => 'btn btn-success']) !!}
32
33 {!! Form::close() !!}
34 </div>
35 </div>
36 </div>
37
38 </body>
39 </html>

Poi, la view che accoglierà i dati:

1 // views/iscrizione/recupera.blade.php
2 <!doctype html>
3 <html lang="en">
4 <head>
5 <meta charset="UTF-8">
6 <title>Iscrizione</title>
7 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5\
8 /css/bootstrap.min.css">
9
10
11 </head>
12 <body>
13
14 <div class="container">
15 <div class="row">
16 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
17 Ciao {{$nome}} {{$cognome}}
18 </div>
19 </div>
20 </div>
21
22 </body>
23 </html>
Scarichiamo pacchetti per un Form di lusso 22

Poi, nel file di route, scriviamo:

1 //app/Http/routes.php
2 Route::get('iscriviti', function(){
3 return view('iscrizione.form');
4 });
5
6 Route::post('iscriviti/dati', function(){
7 $data = [
8 'nome' => Input::get('nome')
9 ,'cognome' => Input::get('cognome')
10 ];
11
12 return view('iscrizione.recupera', $data);
13 });

La prima istruzione di route è una chiamata get, la seconda è post perché il metodo di invio dati è
post. Se diamo un’occhiata al codice generato dalla pagina: http://localhost:8888/iscriviti noteremo
anche un campo hidden chiamato _token. Questo campo è indispensabile per evitare attacchi di
tipo CSRF (Cross-site request forgeries) e il Middleware di Laravel deputato a questo controllo è
HTTPMiddleware. Quindi se usiamo il pacchetto appena scaricato, il campo hidden _token sarà
inserito automaticamente, altrimenti dovremmo inserirlo a mano in questo modo:

1 <?php echo csrf_field(); ?>

Ma cos’è Middleware? Presto lo presenteremo a dovere.

Installa e reinstalla
Installare e reinstallare Laravel e pacchetti annessi e connessi è una pratica salutare per
prendere dimestichezza con questo framework e con quelli che desidererai nel tempo
imparare.
Adoro gli address book
Il nostro microprogetto sarà incentrato sulla creazione di un address book. Ok, una rubrica. E
utilizzeremo CRUD (Create, Read, Update, Delete) come approccio al progetto.

Database, onnipresente
Prima di tutto occorre creare un Model che gestisca la nostra tabella. Nella shell digitiamo:

1 php artisan make:model Agenda

Laravel creerà un file per il Model e andiamo a fare un piccolo edit:

1 //app/Agenda.php
2 namespace App;
3
4 use Illuminate\Database\Eloquent\Model;
5
6 class Agenda extends Model {
7
8 protected $table = 'agenda';
9
10 }

Laravel, di default, usa i plurali all’inglese, aggiungendo una “s”. Quindi intende la nostra tabella
come “agendas”. Con questa istruzione sovrascriviamo le sue intenzioni e possiamo dare qualsiasi
nome alla tabella.
Subito dopo lanciamo un altro comando:

1 php artisan make:migration create_agenda_table

E la migration è bella e pronta:

23
Adoro gli address book 24

1 //database/2015_xx_xx_181606_create_agenda_table.php
2 use Illuminate\Database\Schema\Blueprint;
3 use Illuminate\Database\Migrations\Migration;
4
5 class CreateAgendaTable extends Migration
6 {
7 /**
8 - Run the migrations.
9 *
10 - @return void
11 */
12 public function up()
13 {
14 //
15 }
16
17 /**
18 - Reverse the migrations.
19 *
20 - @return void
21 */
22 public function down()
23 {
24 //
25 }
26 }

Adesso tocca ai campi della nostra rubrica. Nel metodo up() inseriamo i seguenti campi

1 //database/2015_xx_xx_181606_create_agenda_table.php
2 ...
3 public function up()
4 {
5 Schema::create('agenda', function(Blueprint $table)
6 {
7 $table->increments('id');
8 $table->string('nome', 255);
9 $table->string('cognome', 255);
10 $table->string('email', 255);
11 $table->string('telefono',20)->default(0);
12 $table->timestamps();
13 });
Adoro gli address book 25

14 }
15 ...

Ogni campo nel db ha il suo “tipo”. Nel nostro caso non c’è molta differenza. Laravel, di default,
utilizza anche $table->timestamps() che aggiunge un paio di campi nella tabella: created_at e
updated_at: sono due campi molto utili (in alcuni casi) che tracciano gli aggiornamenti del record
della tabella.
Dopo aver confezionato la nostra migration è giunta l’ora di innescarla per creare la tabella nel
nostro db. Procediamo dalla shell:

1 php artisan migrate

Se tutto è andato per il verso giusto, abbiamo una tabella agenda nel nostro db.

Controller dell’address book: i metodi principali


Ancora una volta artisan ci torna utile. Nella shell scriviamo:

1 php artisan make:controller AgendaController

Ed ecco il risultato:

1 //app/Http/Controllers/AgendaController.php
2 namespace App\Http\Controllers;
3
4 use Illuminate\Http\Request;
5
6 use App\Http\Requests;
7 use App\Http\Controllers\Controller;
8
9 class AgendaController extends Controller
10 {
11 /**
12 - Display a listing of the resource.
13 *
14 - @return Response
15 */
16 public function index()
17 {
18 //
Adoro gli address book 26

19 }
20
21 /**
22 - Show the form for creating a new resource.
23 *
24 - @return Response
25 */
26 public function create()
27 {
28 //
29 }
30
31 /**
32 - Store a newly created resource in storage.
33 *
34 - @param Request $request
35 - @return Response
36 */
37 public function store(Request $request)
38 {
39 //
40 }
41
42 /**
43 - Display the specified resource.
44 *
45 - @param int $id
46 - @return Response
47 */
48 public function show($id)
49 {
50 //
51 }
52
53 /**
54 - Show the form for editing the specified resource.
55 *
56 - @param int $id
57 - @return Response
58 */
59 public function edit($id)
60 {
Adoro gli address book 27

61 //
62 }
63
64 /**
65 - Update the specified resource in storage.
66 *
67 - @param Request $request
68 - @param int $id
69 - @return Response
70 */
71 public function update(Request $request, $id)
72 {
73 //
74 }
75
76 /**
77 - Remove the specified resource from storage.
78 *
79 - @param int $id
80 - @return Response
81 */
82 public function destroy($id)
83 {
84 //
85 }
86 }

Perché tutti questi metodi? Come accennato all’inizio del capitolo, per costruire la nostra agenda
seguiremo il metodo CRUD (Create, Read, Update, Delete), cioè le quattro operazione fondamentali
per gestire i nostri dati. Laravel, dunque, quando creiamo un controller da artisan, ci fornisce già i
metodi (vuoti). Partiamo dal metodo create, ma prima indichiamo al nostro file di route che esiste
questo nuovo controller e che vogliamo usare tutti i suoi metodi. Come? Ecco l’istruzione.

1 Route::resource('agenda', 'AgendaController');

Con questa semplice istruzione Laravel gestirà tutti i metodi presenti nel controller. Vediamo quali
in questa tabella:
Adoro gli address book 28

Verb Path Action Route Name


GET /agenda index agenda.index
GET /agenda/create create agenda.create
POST /agenda store agenda.store
GET /agenda/{agenda} show agenda.show
GET /agenda/{agenda}/edit edit agenda.edit
PUT/PATCH /agenda/{agenda} update agenda.update
DELETE /agenda/{agenda} destroy agenda.destroy

E’ uno schema è molto importante perché illustra bene il funzionamento di Laravel quando ha a che
fare con un controller in CRUD mode. In sostanza ciò che abbiamo scritto nel file di route in una
sola riga, risolve tutte quelle chiamate Http. Adesso ci occuperemo, come detto, del secondo verbo
Http: agenda/create
Il nostro metodo conterrà la view:

1 //app/Http/Controllers/AgendaController.php
2 public function create()
3 {
4 return view('agenda.create');
5 }

Per la view, questa volta, comportiamoci meglio: realizziamo un piccolo template (utilizzando
Twitter Bootstrap) e “incastriamo la view all’interno”.
Ecco il template:

1 // resources/views/template/main.blade.php
2 <!doctype html>
3 <html lang="en">
4 <head>
5 <meta charset="UTF-8">
6 <title>Address Book</title>
7
8 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5\
9 /css/bootstrap.min.css">
10
11 </head>
12 <body>
13
14 <nav class="navbar navbar-default">
15 <div class="container-fluid">
16 <div class="navbar-header">
Adoro gli address book 29

17 <a href="/agenda/create">Nuovo indirizzo</a>


18 </div>
19 </div>
20 </nav>
21
22 <div class="container">
23 <div class="row">
24 @yield('content')
25 </div>
26 </div>
27
28 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js\
29 "></script>
30
31 </body>
32 </html>

Nel template abbiamo inserito l’istruzione @yield(‘content’), dunque facciamo attenzione alla view:

1 //resources/views/agenda/create.blade.php
2 @extends('templates.main')
3
4 @section('content')
5
6 @stop

All’interno del tag section(‘content’) (il nome richiama @yield(‘content’)) presente nel template.
Inseriamo dunque il nostro form. Eccolo:

1 //resources/views/agenda/create.blade.php
2 @extends('templates.main')
3
4 @section('content')
5
6 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
7 {!! Form::open(['url' =>'agenda']) !!}
8
9 <div class="form-group">
10 {!! Form::label('nome', 'Il tuo nome:') !!}
11 {!! Form::text('nome', null, ['class' => 'form-control']) !!}
12 </div>
13
Adoro gli address book 30

14 <div class="form-group">
15 {!! Form::label('cognome', 'Il tuo cognome:') !!}
16 {!! Form::text('cognome', null, ['class' => 'form-control']) !!}
17 </div>
18
19 <div class="form-group">
20 {!! Form::label('email', 'La tua email:') !!}
21 {!! Form::text('email', null, ['class' => 'form-control']) !!}
22 </div>
23
24 <div class="form-group">
25 {!! Form::label('telefono', 'Il tuo telefono:') !!}
26 {!! Form::text('telefono', null, ['class' => 'form-control']) !!}
27 </div>
28
29 {!! Form::submit('invia', ['class' => 'btn btn-success']) !!}
30
31 {!! Form::close() !!}
32 </div>
33 @stop

Hai scaricato il pacchetto per il Form?


La view qui sopra non funzionerà se non è presente il pacchetto FORM & HTML (è tutto
spiegato nel capitolo 5)

Possiamo premere sul pulsante “invia” e ci ritroveremo su una pagina bianca. Intanto, però, Laravel
ha gestito la nostra richiesta. Se facciamo riferimento alla tabella precedente la chiamata in questione
è quella espressa nella terza riga: POST | /agenda | store
E’ in questo metodo che dobbiamo intervenire per accogliere i dati e validarli, prima di inserirli nel
db. Lo vedremo nel prossimo paragrafo.

Store, immagazzinare i dati nel db


Il metodo store che accoglierà i dati avrà il seguente codice:
Adoro gli address book 31

1 // app/Http/Controllers/AgendaController.php
2
3 public function store(Request $request)
4 {
5 $this->validate($request, [
6 'nome' => 'required'
7 ,'cognome' => 'required'
8 ,'email' => 'required|email'
9 ,'telefono' => 'required'
10 ],
11 [
12 'nome.required' => 'Il nome è obbligatorio!'
13 ,'cognome.required' => 'Per favore, anche il cognome'
14 ,'email.required' => 'E l\'email è importante'
15 ,'telefono.required' => 'Per favore, inserisci il numero di telefono'
16 ,'email.email' => 'L\'email non è in formato corretto'
17 ]);
18
19 $agenda = new \App\Agenda();
20
21 $agenda->nome = $request->input('nome');
22 $agenda->cognome = $request->input('cognome');
23 $agenda->email = $request->input('email');
24 $agenda->telefono = $request->input('telefono');
25 $agenda->save();
26
27 return redirect('agenda')->with('ok_message', 'La tua rubrica è stata ag\
28 giornata con un nuovo utente');
29 }

Quando abbiamo creato con artisan il controller, Laravel si è preoccupato di passare nel metodo
store anche la classe Request

1 public function store(Request $request){}

Ma a cosa serve questa classe? Gestisce le richieste Http, i dati che passiamo da un modulo all’altro
e molto di più. Per adesso non approfondiamo, accontentiamoci del suo utilizzo pratico.
Subito dopo la validazione prende forma (questo metodo $this->validate è parte della classe
ValidateRequest di Laravel che si occupa proprio della validazione). Accoglie quattro parametri:
il primo è la classe Request, il secondo le regole per validare, il terzo i messaggi di ritorno in caso di
errore, il quarto riguarda attributi custom (ma sorvoleremo per il momento).
Vorrei sottolineare l’ultimo messaggio di validazione tradotto.
Adoro gli address book 32

1 ,'email.email' => 'L\'email non è in formato corretto'

Siccome per l’email abbiamo richiesto che sia required e che sia formattata come email i messaggi
potenziali di errore sono due. Il primo required e il secondo email. Seguendo la sintassi con punto
(dot), abbiamo personalizzato anche il messaggio relativo alla formattazione. Se non l’avessimo fatto,
Laravel ci avrebbe restituito quello suo di default (in inglese).

Dove sono le regole di validazione?


Alcune le useremo in questo e nei prossimi capitoli. Tutte le altre, invece, le trovi nella
documentazione ufficiale:
http://laravel.com/docs/5.1/validation³

Una volta validati i campi, creiamo un’istanza del model Agenda (anche questo creato con artisan)
e valorizziamo i campi con gli stessi nomi degl’input. Alla fine lanciamo il metodo $agenda->save
L’ultima riga è un redirect ad una pagina inesistente. O meglio, sembra la stessa che abbiamo
utilizzato nel form, giusto? In realtà non lo è. Quest’ultima è una chiamata GET, quella del form è una
chiamata POST. Diamo un’occhiata alla tabella Http di prima e noteremo la differenza. Quest’ultimo
redirect si riferisci alla prima riga della tabella:

GET /agenda index agenda.index

Sembra tutto ok. Ma cosa accade se la validazione non passa? Laravel ci riporta nella pagina di
agenda/create, ma sembra non accadere nulla. Visualizziamo i messaggi di errore valorizzati nel
metodo store. Poco prima dell’apertura del form:

1 // resources/views/agenda/create.blade.php
2 @if(count($errors->all()) > 0)
3 <div class="alert alert-danger" role="alert">
4 <p><b>OOOPS!</b></p>
5 <ul>
6 @foreach($errors->all() as $e)
7 <li>{{$e}}</li>
8 @endforeach
9 </ul>
10 </div>
11 @endif

Nel prossimo paragrafo, ci occuperemo dell’aggiornamento e cancellazione dei dati.


³http://laravel.com/docs/5.1/validation
Adoro gli address book 33

Il nostro elenco dati aggiornato


Prima di procedere con l’aggiornamento dati, dobbiamo visualizzarli e scegliere quale record
aggiornare. Il metodo index del nostro controller fa al caso nostro:

1 //app/Http/Controllers/AgendaController.php
2 public function index()
3 {
4 $data['listaNominativi'] = \App\Agenda::all();
5 return view('agenda.index', $data);
6 }

Ecco una classica istruzione Eloquent (l’ORM di Laravel): con il metodo all() “peschiamo” tutti i
record del tabella agenda. Sono “passati” nella view con il secondo attributo del metodo view.
Poi la view, immediatamente:

1 // resources/views/agenda/index.blade.php
2 @extends('templates.main')
3 @section('content')
4
5 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
6 @if(Session::has('ok_message'))
7 <div class="alert alert-success">{{Session::get('ok_message')}}</div>
8 @endif
9 <table class="table table-bordered">
10 <thead>
11 <tr>
12 <th>Nome</th>
13 <th>Cognome</th>
14 <th>Email</th>
15 <th>Telefono</th>
16 <th>Azioni</th>
17 </tr>
18 </thead>
19
20 <tbody>
21 @foreach($listaNominativi as $ln)
22 <tr>
23 <td>{{$ln['nome']}}</td>
24 <td>{{$ln['cognome']}}</td>
25 <td>{{$ln['email']}}</td>
Adoro gli address book 34

26 <td>{{$ln['telefono']}}</td>
27 <td><a href="/agenda/{{$ln['id']}}/edit">modifica</a></td>
28 </tr>
29 @endforeach
30 </tbody>
31 </table>
32 </div>
33 @stop

Il ciclo foreach non ha da essere spiegato: è autospiegante. Idem per i record. C’è una picco-
la novità: l’istruzione if (Session::has(‘ok_message’) esegue un controllo sulla presenza o me-
no della sessione flash (meglio flash data). In fase di creazione non abbiamo visto gli effetti
del return redirect(‘agenda’)->with(‘ok_message’,…) perchè non era ancora pronta la view in
resources/views/agenda/index.blade.php. Adesso è pronta ed è chiara l’utilità.
Non occorre intervenire nella route perché siamo ancora nell’ambito CRUD e la route intercetta
tutto correttamente. Ecco l’estratto della famosa tabella. Questa è la richesta HTTP:

1 |GET |/agenda |index |agenda.index

I due link, invece, utilizzando queste righe della tabella:

1 |GET |/agenda/{agenda}/edit |edit |agenda.edit

per l’edit; per la cancellazione, invece:

1 |DELETE |/agenda/{agenda} |destroy |agenda.destroy

Dunque:

1 locahost:8888/agenda

e godremo di una tabella well-formatted utile per essere editata.

Modificare non guasta


Occupiamoci della modifica. Partiamo dal metodo del controller:
Adoro gli address book 35

1 //app/Http/Controllers/AgendaController.php
2 public function edit($id)
3 {
4 $data['datiRecuperati'] = \App\Agenda::find($id);
5 return view('agenda.edit', $data);
6 }

Poi della view, con una leggera differenza nell’apertura del form:

1 @extends('templates.main')
2
3 @section('content')
4
5 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
6
7 @if(count($errors->all()) > 0)
8 <div class="alert alert-danger" role="alert">
9 <p><b>OOOPS!</b></p>
10 <ul>
11 @foreach($errors->all() as $e)
12 <li>{{$e}}</li>
13 @endforeach
14 </ul>
15 </div>
16 @endif
17
18 {!! Form::model($datiRecuperati,
19 ['method' => 'put', 'url' =>'agenda/'. $datiRecuperati['id']])
20 !!}
21
22 <div class="form-group">
23 {!! Form::label('nome', 'Il tuo nome:') !!}
24 {!! Form::text('nome', null, ['class' => 'form-control']) !!}
25 </div>
26
27 <div class="form-group">
28 {!! Form::label('cognome', 'Il tuo cognome:') !!}
29 {!! Form::text('cognome', null, ['class' => 'form-control']) !!}
30 </div>
31
32 <div class="form-group">
33 {!! Form::label('email', 'La tua email:') !!}
Adoro gli address book 36

34 {!! Form::text('email', null, ['class' => 'form-control']) !!}


35 </div>
36
37 <div class="form-group">
38 {!! Form::label('telefono', 'Il tuo telefono:') !!}
39 {!! Form::text('telefono', null, ['class' => 'form-control']) !!}
40 </div>
41
42 <div class="pull-right">
43 {!! Form::submit('aggiorna', ['class' => 'btn btn-success']) !!}
44
45 {!! Form::close() !!}
46
47 {!! Form::open([
48 'method' => 'DELETE',
49 'route' => ['agenda.destroy', $datiRecuperati['id']]
50 ]) !!}
51 {!! Form::submit('Cancella', ['class' => 'btn btn-danger']) !!}
52 {!! Form::close() !!}
53 </div>
54 @stop

Questa view è quasi identica a quella presente in /resources/views/agenda/create.blade.php, ma il


form di apertura anzichè essere Form::open() è Form::model(). Si tratta del “Form Model Binding”
che facilita l’autocompletamento dei campi. E’ sufficiente passare al metodo, l’array con i dati (nel
nostro caso $datiRecuperati) e il gioco è fatto. In ultimo l’action del form rispetta la tabella iniziale:

1 |PUT/PATCH|/agenda/{agenda} |update |agenda.update

C’è anche il pulsante per cancellare il record. Lo vedremo a breve

Cosa sono i Flash messages


Sono sessioni, ma temporanee: durano il tempo di una chiamata Http. Sebbene esista il
metodo reflash() che ne allunga la vita.

Prima di premere sul pulsante di aggiornamento, andiamo nel metodo che accoglierà i dati per
aggiornarli:
Adoro gli address book 37

1 //app/Http/Controllers/AgendaController.php
2 public function update(Request $request, $id)
3 {
4 $this->validate($request, [
5 'nome' => 'required'
6 ,'cognome' => 'required'
7 ,'email' => 'required|email'
8 ,'telefono' => 'required'
9 ],
10 [
11 'nome.required' => 'Il nome è obbligatorio!'
12 ,'cognome.required' => 'Per favore, anche il cognome'
13 ,'email.required' => 'E l\'email è importante'
14 ,'telefono.required' => 'Per favore, inserisci il numero di telefono'
15 ,'email.email' => 'L\'email non è in formato corretto'
16 ]);
17
18 $agenda = \App\Agenda::find($id);
19 $agenda->nome = $request->input('nome');
20 $agenda->cognome = $request->input('cognome');
21 $agenda->email = $request->input('email');
22 $agenda->telefono = $request->input('telefono');
23 $agenda->save();
24
25 return redirect('agenda')->with('ok_message', 'La tua rubrica è stata aggior\
26 nata con un nuovo utente');
27 }

Molto simile all’inserimento. Ma vediamo nel dettaglio: la differenza che salta agli occhi è un’altra
istruzione Eloquent: AppAgenda:.find($id), cioè Laravel cerca prima il record da aggiornare, poi
aggiorna le variabili ed infine salva tutto con il comando save().

Cancellare è, a volte, opportuno


Siamo arrivati al momento della cancellazione:
Adoro gli address book 38

1 //app/Http/Controllers/AgendaController.php
2 public function destroy($id)
3 {
4 \App\Agenda::destroy($id);
5 return redirect('agenda')->with('ok_message', 'La tua rubrica è stata aggior\
6 nata con un nuovo utente');
7
8 }

Ritorniamo alla view:

1 //resources/views/agenda/edit.blade.php
2
3 ...
4
5 {!! Form::open([
6 'method' => 'DELETE',
7 'route' => ['agenda.destroy', $datiRecuperati['id']]
8 ]) !!}
9 {!! Form::submit('Cancella', ['class' => 'btn btn-danger']) !!}
10 {!! Form::close() !!}

Ci troviamo di fronte ad un nuovo form per rispettare la tabella:

DELETE /agenda/{agenda} destroy agenda.destroy

In questo caso, utilizziamo un attributo alternativo a quello già utilizzato: ‘route’ ⇒ […] dove
indichiamo esattamente la rotta.

Prova a cambiare questo attributo


Prova a trovare un’alternativa a ‘route’ ⇒ […]. Come è possibile cancellare il record
diversamente? A me, personalmente, piace cancellare il record dalla lista, magari con alert.

Ok, siamo pronti per cancellare il record. Nel prossimo capitolo ci occuperemo del refactoring di
questo CRUD. Non lo trovi troppo ridondante?
Refactoring a piccole dosi
Il refactoring prima si fa, meglio è per tutti. I controller devono essere snelli, non tutta la logica
di business deve essere assorbita dai suoi metodi. E ridurre al minimo il codice ridondante è un
obbligo, non una necessità. Inoltre dobbiamo tatuarci il principio della single responsibility: ogni
metodo deve svolgere pochissime attività. Vediamo come: il metodo del nostro controller store() può
esser concettualmente così migliorato:

1 public function store()


2 {
3 // controlla i dati
4 // inserisci
5 // redireziona
6 }

Creiamo una nuova classe con un paio di metodi (per cominciare):

1 //app/Handlers/AgendaHandler.php
2 namespace App\Handlers;
3
4 use Illuminate\Http\Request;
5 use Validator;
6
7 class AgendaHandler
8 {
9 protected $request;
10
11 public function __construct(Request $request){
12 $this->request = $request;
13 }
14
15 public function datiValidi()
16 {
17 $valida = Validator::make($this->request->all(), [
18 'nome' => 'required'
19 , 'cognome' => 'required'
20 , 'email' => 'required|email'
21 , 'telefono' => 'required'

39
Refactoring a piccole dosi 40

22 ],
23 [
24 'nome.required' => 'Il nome è obbligatorio!'
25 , 'cognome.required' => 'Per favore, anche il cognome'
26 , 'email.required' => 'E l\'email è importante'
27 , 'telefono.required' => 'Per favore, inserisci il numero di tel\
28 efono'
29 , 'email.email' => 'L\'email non è in formato corretto'
30 ]);
31
32 if ($valida->fails()) {
33 return $valida->errors();
34 }
35 return true;
36 }
37
38 public function recuperaDati($agenda){
39 $agenda->nome = $this->request->input('nome');
40 $agenda->cognome = $this->request->input('cognome');
41 $agenda->email = $this->request->input('email');
42 $agenda->telefono = $this->request->input('telefono');
43 return $agenda;
44 }
45
46 public function inserisciDati(){
47 $agenda = new \App\Agenda();
48 $this->recuperaDati($agenda);
49 $agenda->save();
50 }
51
52 public function aggiornaDati($id){
53 $agenda = \App\Agenda::find($id);
54 $this->recuperaDati($agenda);
55 $agenda->save();
56 }
57 }

Non sono proprio un paio: ho barato. Prima di tutto richiamiamo le due classi che ci serviranno:
IlluminateHttpRequest; e Validator. Questa è una nostra classe e a Laravel dobbiamo dire tutto, ma
proprio tutto.
Nel metodo __construct passiamo la classe Request che si occuperà di recuperare i dati così come
faceva nel controller. Nel metodo datiValidi(), invece, effettueremo la validazione. Il codice è molto
Refactoring a piccole dosi 41

simile a quello presente nel controller: la differenza sostanziale è che si usa la classe Validator e il suo
metodo make per inizializzare la validazione e customizzare i messaggi di errore. Se la validazione
fallisce, il metodo ritorna gli errori che verrano usati per un redirect nel form di inserimento. Se la
validazione NON fallisce, il metodo restituisce true.
Il secondo metodo inserisciDati(), invece, inserirà i dati, così come li ricordiamo nel controller. Ma
vediamo cosa è accaduto nel controller? Certo. Nella parte alta aggiungiamo:

1 //app/Http/Controllers/AgendaController.php
2 use App\Handlers\AgendaHandler as Ah;

E’ la nostra nuova classe. Dobbiamo rendere noto a Laravel che esiste e che la useremo nel controller.
Il metodo store() invece:

1 //app/Http/Controllers/AgendaController.php
2 public function store(Ah $ah)
3 {
4 $esitoValidazioneDati = $ah->datiValidi();
5 if ($esitoValidazioneDati === true) {
6 $ah->inserisciDati();
7 return redirect('agenda')->with('ok_message', 'La tua rubrica è stata ag\
8 giornata con un nuovo utente');
9 }
10 return redirect('agenda/create')->withErrors($esitoValidazioneDati)->withInp\
11 ut();
12 }

Prima di tutto “innestiamo” la nuova classe che ha come alias Ah (lo abbiamo scritto in cima) poi…
Se l’esito restituisce true, allora inserisci e redirezione come al solito. Se restituisce i messaggi di
errore, invece, redireziona nel metodo create con i messaggi inclusi. Moooolto più chiaro e pulito,
no?
Passiamo al metodo update(), molto simile a store(). Ecco cosa accade:
Refactoring a piccole dosi 42

1 //app/Http/Controllers/AgendaController.php
2 public function update(Ah $ah, $id)
3 {
4 $esitoValidazioneDati = $ah->datiValidi();
5 if ($esitoValidazioneDati === true) {
6 $ah->aggiornaDati($id);
7 return redirect('agenda')->with('ok_message', 'La tua rubrica è stata ag\
8 giornata');
9 }
10 return redirect('agenda/'.$id.'/edit')->withErrors($esitoValidazioneDati)->w\
11 ithInput();
12 }

La differenza è piccola: se l’esito restituisce true, richiameremo il metodo aggiornaDati($id). Il resto


è quasi identico: trattandosi di un update, subito dopo si verrà redirezionati nella pagina edit (non
in create).
Nessuno mi ha chiesto: e il piccolo metodo (in AgendaHandler) che recupera solo i dati? Sì, si chiama
recuperaDati(), ed è utile sia per inserisciDati() che per aggiornaDati().
Dunque un bel risparmio di codice e di tempo. Se dobbiamo aggiungere un campo da validare,
andremo nel metodo relativo e lo aggiungeremo una volta. I metodi dei controller, invece, sono
molto più chiari e concisi. Anche i metodi nella nuova classe svolgono pochissime operazioni.
Naturalmente il refactoring è come l’Universo: senza fine. I margini per migliorare ci saranno
sempre.

Single Responsibility cosa?


Approfondisci qui, per favore: Tutsplus⁴

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo⁵.
⁴http://code.tutsplus.com/tutorials/solid-part-1-the-single-responsibility-principle--net-36074
⁵https://www.dropbox.com/s/klyof3r7ingb6wc/chapter_7.zip?dl=0
Eloquent, Factory, Faker e impostori
vari
Eloquent è l’ORM di Laravel ed è fornito “out of the box”: quindi non è necessario installare alcunché.
Lo abbiamo già usato nei precedenti capitoli, senza illustrarne la versatilità, però. Ricominciamo
dunque con una installazione di Laravel. E partiamo dalle origini. Lanciamo il nostro composer:

1 composer create-project laravel/laravel --prefer-dist

Pigro?
Se sei alle prime armi con Laravel (e hai usato poche volte Composer), reinstallare
continuamente è un’attività che fa bene alla salute.

Ad installazione di Laravel avvenuta, cancelliamo i file presenti in database/migrations: sono i file


per creare la tabella di login (che poi fa funzionare il sistema di autenticazione visto in precedenza).
Non ci occorre per il momento. L’obiettivo è creare un nuovo db Biblioteca con all’interno una serie
di libri.
Prima di tutto creiamo il database biblioteca, poi settiamo il file .env con le credenziali di accesso al
db. Nel mio caso:

1 APP_ENV=local
2 APP_DEBUG=true
3 APP_KEY=SomeRandomString
4
5 DB_HOST=localhost
6 DB_DATABASE=biblioteca
7 DB_USERNAME=root
8 DB_PASSWORD=root
9
10 CACHE_DRIVER=file
11 SESSION_DRIVER=file
12 QUEUE_DRIVER=sync
13
14 MAIL_DRIVER=smtp
15 MAIL_HOST=mailtrap.io

43
Eloquent, Factory, Faker e impostori vari 44

16 MAIL_PORT=2525
17 MAIL_USERNAME=null
18 MAIL_PASSWORD=null
19 MAIL_ENCRYPTION=null

Poi lanciamo la prima migration che creerà la tabella autori:

1 php artisan make:migration create_autori_table

Andiamo dunque ad aprire il file per indicare quali campi debba avere questa tabella:

1 // database/migrations/xxxx_xx_xx_xxxxxx_create_autori_table
2
3 public function up(){
4
5 }
6
7 public function down(){
8
9 }

Il metodo up serve per aggiungere nuove tabelle, colonne, o indici del db. Il metodo down serve
per l’inverso. Entrambi i metodi utilizzano lo schema builder. Vediamo, in pratica, come creare la
tabella:

1 // database/migrations/xxxx_xx_xx_xxxxxx_create_autori_table
2 public function up()
3 {
4 Schema::create('autori', function (Blueprint $table) {
5 $table->increments('id');
6 $table->string('nome');
7 $table->string('cognome');
8 $table->timestamps();
9 });
10 }

Il primo id è incrementale, poi abbiamo nome e cognome nel metodo string() che equivale a
VARCHAR(255)
Lanciamo la migrazione per creare la tabella:
Eloquent, Factory, Faker e impostori vari 45

1 php artisan migrate

Subito dopo tocca alla tabella libri:

1 php artisan make:migration create_libri_table

Apriamo il file:

1 // database/migrations/ xxxx_xx_xx_xxxxxx_create_libri_table
2
3 public function up()
4 {
5 Schema::create('libri', function (Blueprint $table) {
6 $table->increments('id');
7 $table->string('nome');
8 $table->string('descrizione');
9 $table->string('ISBN');
10 $table->integer('autore_id')->unsigned();
11 $table->foreign('autore_id')->references('id')->on('autori')->onDele\
12 te('cascade');
13 $table->timestamps();
14 });
15 }

Abbiamo un intero: autore_id, che nella riga successiva è indicato come foreign key della tabella
autori. Il metodo finale onDelete rappresenta l’azione in caso di cancellazione dei record della tabella
madre (autori). Con $table->timestamps(), infine, indichiamo a Laravel di creare due campi created_-
at e updated_at: molto utili per comprendere creazione e aggiornamento del record.
Lanciamo la migrazione per creare la tabella. Siamo pronti per interrogare il db? Non ancora: sono
tabelle vuote: possiamo riempirle “a mano”, oppure sfruttare un’altra opzione di Laravel. Come
procediamo? E’ una domanda retorica :)

Model Factories per riempire a sbafo


Laravel ci mette a dispozione un efficace metodo per riempire il nostro db in pochi secondi: il model
factory. Creiamo, prima di tutto un seeder che inserirà i nostri dati nel db. Il comando artisan fa al
caso nostro:
Eloquent, Factory, Faker e impostori vari 46

1 php artisan make:seeder AutoriTableSeeder

Nella cartella /database/seeds/ troveremo il file appena creato. Adesso tocca al model factory. Diamo
un’occhiata a questo file:

1 // database/factories/ModelFactory.php
2 $factory->define(App\User::class, function ($faker) {
3 return [
4 'name' => $faker->name,
5 'email' => $faker->email,
6 'password' => str_random(10),
7 'remember_token' => str_random(10),
8 ];
9 });

L’istruzione si riferisce al model User ed indica come riempire i rispettivi campi. A noi, invece,
interessa, la tabella Autori e quella dei Libri: sostituiamo il codice con queste istruzioni:

1 // database/factories/ModelFactories.php
2 $factory->define(App\Autori::class, function ($faker) {
3 return [
4 'nome' => $faker->name,
5 'cognome' => $faker->lastName
6 ];
7 });
8
9 $factory->define(App\Libri::class, function ($faker) {
10 return [
11 'nome' => $faker->name,
12 'descrizione' => $faker->lastName,
13 'ISBN' => $faker->text(10),
14 'autore_id' => factory(App\Autori::class)->create()->id,
15 ];
16 });

Siamo quasi pronti: mancano i model di riferimento. Ancora artisan, il comando è pane quotidiano:

1 php artisan make:model Autori


2 php artisan make:model Libri

Apriamo prima il model Autori:


Eloquent, Factory, Faker e impostori vari 47

1 // app/Autori.php
2
3 class Autori extends Model
4 {
5 protected $table = 'autori';
6 //
7
8
9 public function libri()
10 {
11 return $this->hasMany('App\Libri', 'autore_id');
12 }
13 }

Per via dell’inglese, indichiamo il nome della tabella. E creiamo un metodo che stabilisce una
relazione tra la tabella Autori e Libri: è una relazione uno a molti e il secondo attributo autore_id,
indica la foreign key presente nella tabella libri. Questo è un frammento di Eloquent che discuteremo
in maniera più approfondita più in là. Questo metodo, tuttavia, è utile sia per il seeding, ma
soprattutto per le future query delle nostre app. Proseguiamo e apriamo l’altro model:

1 // app/Libri.php
2
3 class Libri extends Model
4 {
5 protected $table = 'libri';
6 }

In questo caso abbiamo solo aggiunto il nome in italiano della nostra tabella.

Faker, model e Seeder


Ok, come far interagire Faker, Model e Seeder?
Eloquent, Factory, Faker e impostori vari 48

1 //database/seeds/AutoriTableSeeder.php
2
3 public function run()
4 {
5 factory(App\Autori::class, 20)->create()->each(function($u) {
6 $u->libri()->save(factory(App\Libri::class)->make());
7 });
8 }

Creeremo 20 record di autori e per ogni record autori un record nella tabella Libri. La gestione del
foreign key presente in quest’ultima tabella è gestita direttamente nel ModelFactory.php:

1 //database/factories/ModelFactory.php
2 ...
3 'autore_id' => factory(App\Autori::class)->create()->id,
4 ...

Non ci resta che lanciare il seeder:

1 php artisan db:seed --class=AutoriTableSeeder

E come per incanto ambedue le tabelle saranno riempite con tanti dati.

Faker, dove?
La documentazione completa la trovi qui⁶

⁶https://github.com/fzaninotto/Faker
Eloquent: un soffice inizio
La prima istruzione che ci tornerà utile è una query molto semplice. Apriamo la nostra route e
creiamo una nuova pagina. Il nostro onnipresente controller:

1 php artisan make:controller AutoriController --plain

Poi lo apriamo:

1 // app/Http/Controllers/AutoriController.php
2
3 use App\Autori;
4 ...
5
6 public function lista()
7 {
8 $listaAutori = Autori::all();
9
10 foreach($listaAutori as $la)
11 {
12 echo $la['nome'] . ' ' . $la['cognome'] . '<br>';
13 }
14 }

In cima alla classe abbiamo richiamato il Model “Autori” con use…. Poi il metodo lista() del
controller richiama al suo interno un metodo Eloquent: Autori::all(). Il foreach è chiaro, non necessita
spiegazioni.
Subito dopo apriamo il file di route:

1 // app/Http/routes.php
2
3 Route::get('autori', 'AutoriController@lista');

Poi lanciamo:

49
Eloquent: un soffice inizio 50

1 http//localhost:8888/autori

E comparirà la lista di tutti gli autori.


Se volessimo limitare la quantità di dati è sufficiente aggiungere il metodo take():

1 // app/Http/Controllers/AutoriController.php
2
3 public function lista()
4 {
5 $listaAutori = Autori::all()->take(5);
6
7 foreach($listaAutori as $la)
8 {
9 echo $la['nome'] . ' ' . $la['cognome'] . '<br>';
10 }
11 }

Il filtro where, invece, va a sostituire il metodo all():

1 $listaAutori = Autori::where('nome', 'like', '%cel%')->get();

E’ stato aggiunto anche un ulteriore metodo: get(), necessario quando non è più presente all().

Relazione uno a molti


La tabella “autori” è strettamente connessa con la tabella “libri”. La relazione è “uno a molti”: un
autore, molti libri. Vediamo come chiarirla:

1 // app/Autori.php
2 public function libri()
3 {
4 return $this->hasMany('App\Libri', 'autore_id');
5 }

Questo metodo è stato già utilizzato nel precedente capitolo per il factory. Vediamo come utilizzarlo
per la nostra query:
Eloquent: un soffice inizio 51

1 // app/Http/Controllers/AutoriController.php
2 public function listaLibri()
3 {
4 $listaLibri = Autori::find(5)->libri()->get();
5
6 foreach($listaLibri as $li)
7 {
8 echo $li['nome'] . ' ' . $li['descrizione'] . '<br>';
9 }
10 }

Interveniamo nel file di route:

1 // app/Http/routes.php
2 Route::get('listalibri', 'AutoriController@listaLibri');

e lanciamo:

1 http://localhost:8888/listalibri

Laravel ci restituirà solo i libri con autore_id equivalente a 5.

Uno a molti: operazione inversa


E’ anche possibile effettuare l’operazione inversa. Vediamo come:

1 // app/Libri.php
2
3 public function autore()
4 {
5 return $this->belongsTo('App\Autori', 'autore_id');
6 }

Vogliamo sapere l’autore di un determinato libro? Ecco fatto: con l’istruzione belongsTo() indichiamo
l’autore di appartenenza. E’ necessaria anche l’indicazione della foreign_key (secondo attributo).
Il nostro controller sarà (ricordiamoci di richiamare questo metodo nel file di route: evitiamo di
scriverlo qui, ma diamo per scontato di averlo fatto):
Eloquent: un soffice inizio 52

1 // app/Http/AutoriController.php
2 public function qualeAutore()
3 {
4 $autore = \App\Libri::find(5)->autore->nome;
5 echo $autore;
6 }

Qual è la query? Eccola: “cercami il nome dell’autore del libro che ha come id = 5”.

La parola chiave use


In quest’ultimo esempio non ho utilizzato la parola chiave use App/Libri, ma direttamente
il percorso: in Laravel sono ammessi ambedue i metodi.

Uno a molti nella vita reale


L’obiettivo di questo paragrafo è mostrare una lista di libri con i rispettivi autori. Vediamo come?
Aggiungiamo anche una view per mantenere un certo decoro :)

1 // app/Http/Controllers/AutoriController.php
2 public function bigList()
3 {
4 $mieiLibri = \App\Libri::all();
5 return view('libri.lista', compact('mieiLibri'));
6 }

Poi la view:

1 // resources/views/libri/lista.blade.php
2 <table >
3 <thead>
4 <tr>
5 <th>Titolo libro</th>
6 <th>Autore</th>
7 </tr>
8 </thead>
9 <tbody>
10 @foreach($mieiLibri as $ml)
11 <tr>
12 <td>{{ $ml['descrizione'] }}</td>
Eloquent: un soffice inizio 53

13 <td>{{$ml->autore->nome}}</td>
14 </tr>
15 @endforeach
16 </tbody>
17 </table>

Infine il file di route:

1 // app/Http/routes.php
2 Route::get('bigList', 'AutoriController@bigList');

Lanciamo la nostra pagina:

1 http://localhost:8888/bigList

Fatto. Mostruosamente semplice. La relazione è tutta nella view. Ma è possibile l’operazione perché
nel Model Libri c’è il metodo autore

Uno a molti: esercizio


Il processo fin qui appreso è piuttosto semplice, ma il suggerimento è di ripeterlo più e più
volte realizzando opportune varianti: es “where”, “whereLike”, ecc. Il query builder può
aiutare in questi test⁷

Nel prossimo capitolo affronteremo la bestia nera: relazioni molti a molti e invasioni aliene. Stay
tuned!

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo⁸.
⁷http://laravel.com/docs/5.1/queries
⁸https://www.dropbox.com/s/komlve58uf7cgkm/chapter_9.zip?dl=0
Eloquent: relazioni a triangolo
Ampliamo la nostra biblioteca con un nuovo attore: l’utente che prende in prestito l’ebook (accadrà
presto! O forme ibride già sono in corso). Una tipica relazione “molti a molti” consiste nella possibilità
di un utente di prendere in prestito più ebook e un ebook può essere preso in prestito da più utenti.

Prestiamo libri
Creiamo subito la nostra tabella utenti:

1 php artisan make:migration create_utenti_table

Lo schema è piuttosto semplice:

1 // xxxx_xx_xx_xxxxxx_create_utenti_table
2 public function up()
3 {
4 Schema::create('utenti', function (Blueprint $table) {
5 $table->increments('id');
6 $table->string('nome');
7 $table->string('cognome');
8 $table->timestamps();
9 });
10 }

Adesso tocca alla tabella intermedia (detta anche “pivot”) che ospiterà gli ID delle due tabelle “utenti”
e “libri”:

54
Eloquent: relazioni a triangolo 55

1 // xxxx_xx_xx_xxxxxx_create_utenti_table
2 public function up()
3 {
4 Schema::create('prestiti', function (Blueprint $table) {
5 $table->increments('id');
6 $table->integer('utente_id')->unsigned();
7 $table->foreign('utente_id')->references('id')->on('utenti')->onDelete('\
8 cascade');
9 $table->integer('libro_id')->unsigned();
10 $table->foreign('libro_id')->references('id')->on('libri')->onDelete('ca\
11 scade');
12 $table->timestamps();
13 });
14 }

E’ importante notare le foreign key “utente_id” e “libro_id” che fanno rispettivamente riferimento
alla tabella “utenti” e “libri”. Lanciamo il comando per innescare la migration:

1 php artisan migrate

Creiamo i due model delle due tabelle. In sequenza questi due comandi:

1 php artisan make:model Utenti


2 php artisan make:model Prestiti

Nel model “Prestiti” indichiamo il nome della tabella:

1 // app/Prestiti.php
2 class Prestiti extends Model
3 {
4 protected $table = 'prestiti';
5 }

Nel model “Utenti”, la tabella relativa:


Eloquent: relazioni a triangolo 56

1 // app/Utenti.php
2 class Utenti extends Model
3 {
4 protected $table = 'utenti';
5 }

Riempiamo le nostre tabelle (“utenti” e “prestiti”) a piacere assicurandoci che nella tabella “prestiti”
gli ID (“utente_id” e “libro_id”) siano validi, cioè presenti nelle rispettive tabelle “utenti” e “libri” (è
probabile che “libri” ce l’hai già piena di dati). L’obiettivo è riuscire a visualizzare chi ha preso in
prestito il libro oppure più libri. Partiamo dal model “Utenti”:

1 //app/Utenti.php
2
3 public function libriInPrestito()
4 {
5 return $this->belongsToMany('App\Libri', 'prestiti', 'utente_id', 'libro_id'\
6 );
7 }

Creiamo un controller:

1 php artisan make:controller LibriController --plain

Ecco il metodo che fa al caso nostro:

1 //app/Http/Controllers/LibriController.php
2 public function inPrestito()
3 {
4 $data['utente'] = \App\Utenti::find(1);
5
6 return view('prestiti.inprestito', $data);
7 }

Cerchiamo l’utente che ha come id = 1 e vediamo quanti libri ha preso in prestito (se abbiamo
assegnato id diversi, dobbiamo cambiare questo numero, naturalmente).
Poi creiamo la nostra view:
Eloquent: relazioni a triangolo 57

1 // resources/views/prestiti/inprestito.blade.php
2 <table class="table table-hover">
3 <thead>
4 <tr>
5 <th>Utente</th>
6 <th>Libro in Prestito</th>
7
8 </tr>
9 </thead>
10 <tbody>
11 @foreach($utente->libriInPrestito as $libro)
12 <tr>
13 <td>{{$utente['nome']}}</td>
14 <td>{{ $libro['nome'] }}</td>
15
16 </tr>
17 @endforeach
18 </tbody>
19 </table>

Infine la route. Aggiungiamo questa riga:

1 //app/Http/routes.php
2 Route::get('libriPrestito', 'LibriController@inPrestito');

Nel browser, dunque:

1 http://laravelbook:8888/libriPrestito

Compariranno i libri (o il libro) preso in prestito dall’utente (id = 1).

Ebook in prestito a chi?


E se volessimo sapere quali e quanti sono gli utenti che hanno preso un singolo ebook? Apriamo il
model:
Eloquent: relazioni a triangolo 58

1 // app/Libri.php
2 public function miLeggono()
3 {
4 return $this->belongsToMany('App\Utenti', 'prestiti', 'utente_id', 'libro_id\
5 ');
6 }

Il metodo differisce poco da quello presente nel model “Utenti”: cambia solo l’attributo model. In
quest’ultimo caso, infatti, è ‘AppUtenti’.
Andiamo nel nostro controller:

1 //app/Http/Controllers/LibriController.php
2 public function quantiMiLeggono()
3 {
4 $data['libro'] = \App\Libri::find(1);
5
6 return view('prestiti.leggono', $data);
7 }

Creiamo una view:

1 //resources/views/prestiti/leggono.blade.php
2 <table class="table table-hover">
3 <thead>
4 <tr>
5 <th>Libro</th>
6 <th>Chi lo ha preso in prestito</th>
7
8 </tr>
9 </thead>
10 <tbody>
11 @foreach($libro->miLeggono as $ut)
12 <tr>
13 <td>{{$libro['nome']}}</td>
14 <td>{{ $ut['nome'] . ' ' . $ut['cognome'] }}</td>
15 </tr>
16 @endforeach
17 </tbody>
18 </table>

E la route, non dimentichiamola:


Eloquent: relazioni a triangolo 59

1 Route::get('UtentiCheLeggono', 'LibriController@quantiMiLeggono');

Ok, nel browser, infine digitiamo:

1 http://laravelbook:8888/UtentiCheLeggono

Il libro (ebook) con id = 1 è stato preso in prestito dagli utenti x e y.

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo⁹.
⁹https://www.dropbox.com/s/lr72zc46zebub3q/chapter_10.zip?dl=0
Eloquent: relazioni complesse
Le polimorfiche
Due tabelle: “Libri” e “Autori” potrebbero condividere una tabella “Genere”. Questo triangolo
particolare può essere espresso con le relazioni polimorfiche. Analizziamo le nostre tabelle:
Autori - id - nome - cognome
Libri - id - nome - descrizione
Genere - id (integer) - nome_genere (string) - genereble_id (integer) - genereble_type (stringa)
La novità, in questo elenco, è rappresentata dalla nuova tabella “Genere”: ha il suo ID e il suo
NOME_GENERE, la GENEREBLE_ID (che può essere indifferentemente l’ID di “Autori” oppure
“Libri”) e la GENEREBLE_TYPE che non contiene altro che il nome del model a cui GENEREBLE_ID
fa riferimento.
Creiamo subito la migration per la tabella “Genere”:

1 php artisan make:migration create_genere_table

Subito dopo i campi:

1 // database/migrations/xxxx_xx_xx_xxxxxx_create_genere_table.php
2 ...
3 public function up()
4 {
5 Schema::create('genere', function (Blueprint $table) {
6 $table->increments('id');
7 $table->string('nome_genere');
8 $table->morphs('genereble'); // genera automaticamente generable_id e ge\
9 nerable_type
10
11 });
12 }

Lanciamo la migration con:

60
Eloquent: relazioni complesse 61

1 php artisan migrate

Popoliamola, infine con qualche dato, facendo attenzione ai due campi sensibili come generable_id
e generable_type. Ecco un esempio:

1 generable_id (1)
2 generable_type ('Libri')
3
4 generable_id (2)
5 generable_type ('Libri')
6
7 generable_id (10)
8 generable_type ('Autori')
9
10 generable_id (12)
11 generable_type ('Autori')

Anche il NOME_GENERE va riempito, naturalmente. Poi creiamo il model “Genere”:

1 php artisan make:model Genere

Eccolo:

1 //app/Genere.php
2 namespace App;
3
4 use Illuminate\Database\Eloquent\Model;
5
6 class Genere extends Model
7 {
8 protected $table = 'genere';
9
10 public function genereble(){
11 return $this->morphTo();
12 }
13 }

Il metodo genereble sarà utile per creare la relazione con le altre due tabelle (“LIBRI” e “AUTORI”).
Nel model Libri aggiungeremo un nuovo metodo:
Eloquent: relazioni complesse 62

1 //app/Libri.php
2 ...
3 protected $morphClass = 'Libri';
4
5 public function generi()
6 {
7 return $this->morphMany('\App\Genere', 'genereble');
8 }

Il metodo generi() restituisce la relazione polimorfica attraverso il metodo morphMany() che accoglie
due attributi: il Model e il suo metodo (lo abbiamo definito prima). E’ bene notare anche la variabile
protetta $morphClass, anch’essa necessaria perché funzioni il tutto.
Apriamo il nostro file di route e verifichiamo il funzionamento:

1 //app/Http/route.php
2 Route::get('LibriPoly', function () {
3 $libri = App\Libri::find(2);
4
5 foreach ($libri->generi as $gen) {
6 echo $libri->nome . ' [' . $gen->nome_genere . ']';
7 }
8 });

Il foreach è necessario se ci sono più generi associati ad un determinato libro.


Il medesimo procedimento investirà anche il model Autori:

1 //app/Autori.php
2 ...
3 protected $morphClass = 'Autori';
4
5 public function generi()
6 {
7 return $this->morphMany('\App\Genere', 'genereble');
8 }

Utilizziamolo nel file di route:


Eloquent: relazioni complesse 63

1 //app/Http/routes.php
2 Route::get('AutoriPoly', function(){
3 $autori = App\Autori::find(2);
4
5 foreach($autori->generi as $gen){
6 echo $autori->nome . ' [' . $gen->nome_genere . ']';
7 }
8 });

Gli ID, quali?


Nell’esempio ho usato gli ID effettivamente presenti nel mio db. Se i tuoi ID fossero diversi,
provvedi a modificare il codice, altrimenti non avresti alcun risultato.

Abbattere le query: Eager Loading


Mettiamo il caso che si debba effettuare una query dei nostri libri e per ognuno di essi si debba “tirar
fuori” il nome e cognome dell’autore. Con un foreach come questo:

1 $libri = App\Libri::all();
2
3 foreach($libri as $libro)
4 {
5 echo $libro->autore->nome;
6 }

Laravel effettuerebbe una query per i libri e “n” query per ogni autore del libro. Gosh: se avessimo
200 libri, una query per i libri e 200 query per sapere il nome di autore del libro. C’è un modo per
ovviare questo problema di eccessivo uso di risorse: L’Eager Loading. Ecco come:

1 $libri = App\Libri::with('autore')->get();
2
3 foreach($libri as $libro)
4 {
5 echo $libro->autore->nome;
6 }

Capperi, abbiamo solo aggiunto il metodo with e il gioco è fatto: ecco le query reali:
Eloquent: relazioni complesse 64

1 SELECT * FROM libri; // prima query


2 SELECT * FROM autori WHERE id in (1,2,3,4,...)

Yes, davvero conveniente. Proviamo nella nostra route:visivamente il risultato non cambierà, ma
ci troviamo di fronte ad un risparmio “energetico” meraviglioso. L’eager loading dovrebbe essere
utilizzato praticamente sempre, sempre, sempre.

Eager Loading, Lazy Eager Loading…


La gestione di Eloquent non finisce qui. Tratteremo in seguito questo argomento perché
ricco di sfumature.

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁰.
¹⁰https://www.dropbox.com/s/0cdmolqa1i1a87i/chapter_11.zip?dl=0
Middleware, il tuo cane da guardia
Un fondamentale meccanismo per filtrare le richieste HTTP è rappresentato dal Middleware.
Lo abbiamo (passivamente) incontrato nel capitolo sull’autenticazione. Grazie al Middleware di
autenticazione, infatti, possiamo proteggere agevolmente le pagine rendendole visibili solo previa
autenticazione. Possiamo però creare il nostro Middleware ed un esempio leggermente diverso
dall’autenticazione può essere il seguente: stiamo realizzando un sito ecommerce e per la pagina
legata al metodo di pagamento, abbiamo bisogno di verificare che sia presente almeno un prodotto
nel carrello. In caso contrario l’utente NON può accedere alla pagina del metodo di pagamento.

Il setup
Ripartiamo con una installazione di Laravel (pochi minuti e via). Poi lanciamo il comando artisan
per creare il nostro middleware:

1 php artisan make:middleware IlCarrelloEPieno

Ricordiamoci di dare sempre nomi significativi al MiddleWare: questo approccio ci aiuterà nella
leggibilità del codice e del filtro (middleware) che stiamo creando. Ottima prassi anche per i colleghi
che lavoreranno sullo stesso progetto. Dopo aver creato il nostro Middleware, registriamolo nel file
Kernel:

1 // app/Http/Kernel.php
2 namespace App\Http;
3
4 use Illuminate\Foundation\Http\Kernel as HttpKernel;
5
6 class Kernel extends HttpKernel
7 {
8 /**
9 * The application's global HTTP middleware stack.
10 *
11 * @var array
12 */
13 protected $middleware = [
14 \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
15 \App\Http\Middleware\EncryptCookies::class,

65
Middleware, il tuo cane da guardia 66

16 \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
17 \Illuminate\Session\Middleware\StartSession::class,
18 \Illuminate\View\Middleware\ShareErrorsFromSession::class,
19 \App\Http\Middleware\VerifyCsrfToken::class,
20 ];
21
22 /**
23 * The application's route middleware.
24 *
25 * @var array
26 */
27 protected $routeMiddleware = [
28 'auth' => \App\Http\Middleware\Authenticate::class,
29 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::c\
30 lass,
31 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
32 ];
33 }

Nell’array “$middleware” registriamo i middleware globali che prescindono dalle chiamate HTTP:
e infatti troviamo la verifica CSRF, la gestione dei Cookie, gestione Sessione, e altro. Nell’array
“$routeMiddleware” registriamo i middleware che filtrano le chiamate Http presenti nel file di route
ed è qui che andremo a registrare il nostro “IlCarrelloEPieno”:

1 // app/Http/Kernel.php
2 ...
3 protected $routeMiddleware = [
4 ...
5 'carrellopieno' => \App\Http\Middleware\IlCarrelloEPieno::class,
6 ];

La route e il Model
Adesso apriamo il file di route e applichiamo questo middleware:

1 // app/Http/routes.php
2 Route::get('/metodospedizione', ['middleware' => 'carrellopieno', function(){
3 return 'Pagina Metodo spedizione';
4 }]);

Bene, abbiamo impostato il filtro, ma non possiamo ancora usarlo: dobbiamo infatti simulare un
controllo nel db e precisamente nel carrello utente per verificare che sia presente almeno un prodotto.
Prima artisan per creare il Model:
Middleware, il tuo cane da guardia 67

1 php artisan make:model Carrello

Apriamo il file e creiamo un nuovo metodo che simula una chiamata al db:

1 // app/Carrello.php
2 public function ePieno()
3 {
4 $prodottiCarrello = 1;
5
6 if ( $prodottiCarrello > 0)
7 {
8 return true;
9 }
10 return false;
11 }

Nel metodo ePieno() simuliamo che il prodotto sia effettivamente presente. Il metodo restituisce
semplicemente “true” o “false”. Subito dopo gestiamo il metodo già presente nel middleware:

1 // app/Http/Middleware/IlCarrelloEPieno.php
2 public function handle($request, Closure $next)
3 {
4 $carrello = new \App\Carrello;
5 if ($carrello && $carrello->ePieno())
6 {
7 return $next($request);
8 }
9 return redirect('/');
10 }

Il significato è chiaro. Se il metodo restituisce “true” la pagina viene visualizzata, altrimenti c’è un
reindirizzamento alla homepage. Proviamo:

1 http://localhost:8888/metodospedizione

Se tutto è andato per il verso giusto dovremmo vedere il testo:

1 Pagina metodo spedizione

Proviamo a modificare il metodo che simula la chiamata al db:


Middleware, il tuo cane da guardia 68

1 // app/Carrello.php
2 public function ePieno()
3 {
4 $prodottiCarrello = 0;
5
6 if ( $prodottiCarrello > 0)
7 {
8 return true;
9 }
10 return false;
11 }

Se digitiamo:

1 http://localhost:8888/metodospedizione

saremo reindirizzati nell’homepage.

Middleware e request, Middleware e parame-


tri
Filtrare la nostra applicazione con i Middleware è un’attività che molto frequente. E’
argomento questo che verrà trattato più in là in un esempio più complesso e con l’utilizzo
di più filtri in contemporanea.

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹¹.
¹¹https://www.dropbox.com/s/vb0c6zn9h1b7ou7/chapter_12.zip?dl=0
Paginare è la miglior cosa
Prima o poi capiterà a tutti di avere indecorose liste dati da visualizzare. E la paginazione è il
primo step da valutare per renderle più fruibili. Laravel, per fortuna, offre una serie di soluzioni
comodissime.

Seeding dei dati


Abbiamo già parlato del seeding e diamo per scontato due aspetti: una installazione “pulita” di
Laravel ed una tabella piena di dati. Nell’esempio utilizzeremo la tabella “libri”, ma può andar bene
qualsiasi tabella.

Simple pagination
E’ la paginazione più sbrigativa. Eccola:

1 $libri = DB::table('libri')->simplePaginate(15);

La possiamo implementare nel nostro model, opportunamento creato con:

1 php artisan make:model Libri

Subito dopo tocca al nostro controller:

1 php artisan make:controller LibriController

Ok, apriamo il nostro model e creiamo un nuovo metodo (ricordiamoci di aggiungere la variabile
protetta “$table”: ci servirà dopo):

1 // app/Libri.php
2 public function lista()
3 {
4 return \DB::table('libri')->simplePaginate(3);
5 }

Nel nostro controller, invece, richiamiamo il metodo:

69
Paginare è la miglior cosa 70

1 // app/Http/Controllers/LibriController.php
2 public function index()
3 {
4 $libri = new \App\Libri();
5 $lista = $libri->lista();
6 return view('libri.lista', compact('lista'));
7 }

compact(), cos’è?
Non è una istruzione Laravel, ma PHP: crea un array con il nome delle variabili e con i
relativi valori (maggiori info qui¹² )

Tocca alla view:

1 // resources/views/libri/lista.blade.php
2 <ul>
3 @foreach($lista as $lib)
4 <li>{{$lib->titolo}}</li>
5 @endforeach
6 </ul>

Il file di route, per richiamare la pagina, dovrà essere modificato:

1 // app/Http/routes.php
2 Route::get('/listalibri', 'LibriController@index');

All’indirizzo:

1 http://localhost:8888/listalibri

avremo la lista dei nostri libri, ma senza link “next”, “previous”, o numeri di paginazione.

Paginare con Eloquent


Anche Eloquent ha il suo sistema di paginazione: lo useremo per un esempio lievemente più
complesso.
Nel nostro model:
¹²http://php.net/manual/en/function.compact.php
Paginare è la miglior cosa 71

1 // app/Libri.php
2 public function listaEloquent()
3 {
4 return \App\Libri::where('id', '>', 3)->paginate(15);
5 }

abbiamo usato anche una condizione. Il risultato è il medesimo: cambia il nome del metodo.
Testiamolo subito con un nuovo metodo nel controller:

1 // app/Http/Controllers/LibriController.php
2 public function eloquentLibri()
3 {
4 $libri = new \App\Libri();
5 $lista = $libri->listaEloquent();
6 return view('libri.lista_elo', compact('lista'));
7 }

poi nella route, aggiungiamo:

1 // app/Http/routes.php
2 Route::get('/listaeloquent', 'LibriController@eloquentLibri');

Prima di verificare, aggiungiamo i link per la paginazione nella view:

1 // resources/views/libri/lista_elo.blade.php
2 <ul>
3 @foreach($lista as $lib)
4 <li>{{$lib->titolo}}</li>
5 @endforeach
6 </ul>
7
8 {!! $lista->render() !!}

Verifichiamo:

1 http://laravelbook:8888/listaeloquent

Con una grafica molto triste, comparirà un ulteriore elenco puntato corredato di numeri e freccette
per spostarsi nella paginazione. In realtà la paginazione è pre-formattata per aderire perfettamente al
Framework CSS Bootstrap. Dunque, se includiamo il file css del framework Bootstrap, la paginazione
renderizzata avrà un altro effetto.
Paginare è la miglior cosa 72

Paginazione personalizzata
Se, invece, vogliamo personalizzare la paginazione con le nostre classi CSS, Laravel offre una serie
di metodi per recuperare la pagina precedente, quella successiva, e così via. Ecco l’elenco:

1 $results->count()
2 $results->currentPage()
3 $results->hasMorePages()
4 $results->lastPage() (non disponibile per il metodo simplePaginate)
5 $results->nextPageUrl()
6 $results->perPage()
7 $results->previousPageUrl()
8 $results->total() (non disponibile per il metodo simplePaginate)
9 $results->url($page)

Pacchetti per paginare


In rete esistono pacchetti interessanti per formattare la paginazione in diverso modo. Uno
di questi è Landish/Pagination¹³

Se volessimo, infine, aggiungere un’ulteriore variabile all’url di paginazione, utilizzeremo il metodo


appends(). Ecco come:

1 // resources/views/libri/lista_elo.blade.php
2 {!! $lista->appends(['categoria' => 'gialli'])->render() !!}

L’url, dopo questa modifica, avrà una sintassi simile a questa:

1 http://laravelbook:8888/listaeloquent?categoria=gialli&page=2

Laravel, infine, permette anche di variare l’URL con il metodo setPath(). Se infatti aggiungessimo
nel metodo del controller, l’istruzione:

¹³https://github.com/Landish/Pagination
Paginare è la miglior cosa 73

1 // app/Http/Controllers/LibriController.php
2 public function eloquentLibri()
3 {
4 $libri = new \App\Libri();
5 $lista = $libri->listaEloquent();
6 $lista->setPath('custom/url');
7 return view('libri.lista_elo', compact('lista'));
8 }

Il percorso cambierebbe in:

1 http://laravelbook:8888/custom/url?categoria=gialli&page=2

E naturalmente sarà opportuno cambiare le indicazioni nel file di route.

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁴.
¹⁴https://www.dropbox.com/s/fw1flyi4k692rtd/chapter_13.zip?dl=0
Caching, non solo quando hai poche
risorse
La nostra applicazione è talmente popolare che il server non ce la fa a gestire migliaia di pagine.
Ogni richiesta della pagina è una query al db, il server rallenta, poi va in crash. Diverse le soluzioni:
un server più potente, refactoring del codice, caching delle query. Il servizio di caching offerto da
Laravel è piuttosto intuitivo e di facile applicazione. Può essere utilizzato con i più importanti sistemi
di caching backend (Memcached o Redis, ad esempio).
Ma può gestire anche il caching attraverso file, ed è questa l’impostazione di default che andremo
ad utilizzare. Prima di proseguire è consigliabile utilizzare una installazione fresh di Laravel.

Dove si configura
Il file di configurazione è in config/cache.php e quello che ci interessa sapere è che la cartella per il
caching è localizzata qui:

1 'file' => [
2 'driver' => 'file',
3 'path' => storage_path('framework/cache'),
4 ],

Non occorre modificare nulla per adesso (verifichiamo che la cartella in questione, però, abbia i
permessi di scrittura).

Salvare dati in cache


Apriamo il nostro file di route e simuliamo una chiamata al db che ci restituisce un array di dati:

74
Caching, non solo quando hai poche risorse 75

1 // app/Http/routes.php
2 Route::get('/salva_dati_in_cache', function(){
3 $scadenza = \Carbon\Carbon::now()->addMinutes(10);
4 \Cache::put('nome', 'Francesco', $scadenza);
5 return 'Dati salvati';
6 });

L’istruzione put accoglie tre valori: il primo è la chiave (che poi utilizzeremo per richiamare il dato),
il secondo è il valore, il terzo è la quantità di minuti di “resistenza” della cache: allo scadere di
questi ultimi il dato non sarà più disponibile. Ecco perché prima valorizzeremo una variabile che
rappresenta la data e l’ora con 10 minuti in più dell’ora attuale (now()).
Prima di procedere oltre, richiamiamo questa pagina per salvare i dati in cache:

1 http://localhost:8888/salva_dati_in_cache

Ok, adesso i nostri dati sono in cache.

Cos’è Carbon?
E’ un pacchetto molto conosciuto che Laravel include di default nel suo set di pacchetti.
Con Carbon la gestione delle date in PHP risulta piuttosto semplice. (maggiori info qui¹⁵)

Recuperare i dati in cache


Per richiamare il dato salvato in cache è sufficiente questa istruzione:

1 // app/Http/routes.php
2 Route::get('/recupera_dati_in_cache', function(){
3 return \Cache::get('nome');
4 });

Con get, dunque, andremo a recuperare ciò che abbiamo salvato. Per sapere se il dato è in cache,
modifichiamo l’istruzione precedente con un if :

¹⁵http://carbon.nesbot.com/
Caching, non solo quando hai poche risorse 76

1 //app/Http/routes.php
2 if ( \Cache::has('nome'))
3 {
4 return \Cache::get('nome');
5 }

Aggiornare i dati
E’ possibile gestire anche il caso in cui i dati in cache non siano presenti e si desideri una chiamata
ad un db per recuperarli e salvarli, dunque, in cache. Tutto in un colpo solo! Vediamo come:

1 // app/Http/routes.php
2 Route::get('/se_non_ci_sono_recupera', function(){
3 $scadenza = \Carbon\Carbon::now()->addMinutes(10);
4 \Cache::remember('lavoro', $scadenza, function(){
5 return 'Web Developer'; // questo potrebbe essere il risultato di una qu\
6 ery
7 });
8 });

Richiamiamo questa pagina: http://localhost:8888/se_non_ci_sono_recupera


Con il metodo remember Laravel controlla se sia o meno presente la chiave ‘lavoro’: se non è presente
la crea con il dato della query simulata. Verifichiamo adesso se è stata creata:

1 // app/Http/routes.php
2 Route::get('/esiste_cache', function(){
3 if (\Cache::has('lavoro'))
4 {
5 return \Cache::get('lavoro');
6 }
7 });

Andiamo all’URL indicato: http://localhost:8888/esiste_cache


Se tutto è andato per il verso giusto, leggeremo ‘Web Developer’.

La cache è per sempre


E’ possibile anche utilizzare la cache in modo permanente, senza scadenza. Questa istruzione può
essere utilizzata per dati per i quali siamo sicuri che non verranno mai aggiornati o solo di rado: al
posto di put ecco cosa scrivere:
Caching, non solo quando hai poche risorse 77

1 \Cache::forever('nome', 'Francesco');

E possiamo sostituire il metodo richiamato precedentemente remeber, con rememberForever:

1 // app/Http/routes.php
2 Route::get('/se_non_ci_sono_recupera_per_sempre', function(){
3 \Cache::rememberForever('lavoro', function(){
4 return 'Web Developer'; // questo potrebbe essere il risultato di una qu\
5 ery
6 });
7 });

Cancellare la cache
Qualsiasi dato salvato in cache sia con il metodo put, sia con il metodo forever può essere cancellato:
l’istruzione è tanto semplice quanto importante:

1 \Cache::forget('nome');

Può essere utile anche richiamare il dato e cancellarlo subito dopo. Ecco come:

1 $variabile = \Cache::pull('nome');

Per cancellare tutto il “pacchetto” in cache, invece:

1 \Cache::flush();

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁶.
¹⁶https://www.dropbox.com/s/554v7u4jyleg7u8/chapter_14.zip?dl=0
Le mie classi, i miei Helper: tutto mio
Laravel è un framework molto potente, ma i web developer di una certa portata potrebbero avere
la necessità di portarsi nello zaino le proprie classi realizzate in anni di fatica. Il framework “alza le
mani” e ne permette un facile utilizzo. Dalla nostra fresca installazione di Laravel vediamo come.

Classi: dove e come


Mettiamo il caso che vogliamo creare una classe che gestisca una serie di messaggi. Andiamo subito
a crearla, ponendo attenzione al namespace:

1 // app/Services/Messaggio.php
2
3 namespace App/Services;
4
5 class Message{
6
7 public function sayHello(){
8 return 'hello';
9 }
10 }

Una classe molto semplice. Vogliamo però utilizzarla all’interno della nostra applicazione. Creiamo
un classico controller con artisan:

1 php artisan make:controller Homepage --plain

Apriamo il controller e facciamo funzionare la nostra piccola classe:

78
Le mie classi, i miei Helper: tutto mio 79

1 // app/Http/Controllers/Homepage.php
2
3 use App\Services\Message;
4
5 class Homepage extends Controller
6 {
7
8 public function index()
9 {
10 $m = new Message();
11 return $m->sayHello();
12 }
13 }

La prima cosa che dovrebbe saltare all’occhio è il richiamo alla classe “use AppServicesMessage”.
All’interno del metodo, invece, istanzieremo la classe e richiameremo il metodo: troppo semplice!
Un ultimo accorgimento nel file di route:

1 // app/Http/routes.php
2
3 Route::get('/', 'Homepage@index');

Ok, all’indirizzo:

1 http://localhost:8888

avremo il nostro messaggio stampato a video.


E se volessimo utilizzare la classe Session di Laravel all’interno della classe Message? Presto detto:

1 // app/Services/Message.php
2 public function mySessionId()
3 {
4 return \Session::getId();
5 }

Nel nostro controller, facciamo una piccola sostituzione:


Le mie classi, i miei Helper: tutto mio 80

1 // app/Http/Controllers/Homepage.php
2
3 ...
4 public function index()
5 {
6 $m = new Message();
7 return $m->mySessionId();
8 }

Al solito indirizzo:

1 http://localhost:8888

avremo il valore della nostra sessione.

Helper: dove e come


Si ricorre agli helper per attività più semplici, che non richiedono l’utilizzo di una classe con i suoi
metodi. Laravel ha una serie di helper molto utili. Ad esempio, per gestire gli array, i path, le sessioni.
Basta richiamare il metodo nel controller o nella view e il gioco è fatto. Questo, per esempio, limita
i caratteri di una stringa:

1 str_limit('Questo testo è abbastanza lungo, servirà ridurlo al momento opportuno\


2 ', 7);

Il secondo attributo numerico indica la quantità di caratteri che verranno estratti.


E se volessimo crearci il nostro helper? Niente di più semplice. Ecco come: creiamo un file helper
dove vogliamo, anche nel folder app:

1 // app/helper.php
2
3 function moltiplicaPerCento($numero)
4 {
5 return $numero * 100;
6 }

Tutto qui? In un certo senso sì. Non bisogna creare una classe, ma solo metodi. Dobbiamo però dire
a Laravel che c’è questa classe. Apriamo il file composer e aggiungiamo nella sezione “autoload”:
Le mie classi, i miei Helper: tutto mio 81

1 "autoload": {
2 "classmap": [
3 "database"
4 ],
5 "psr-4": {
6 "App\\": "app/"
7 },
8 "files": [
9 "app/helper.php"
10 ]
11
12 },

subito dopo lanciamo:

1 composer dump-autoload

Ecco fatto, nella nostra route possiamo subito verificarne il funzionamento:

1 // app/Http/routes.php
2
3 Route::get('numeri', function(){
4 return moltiplicaPerCento(150);
5 });

Alla pagina:

1 http://localhost:8888/numeri

avremo il nostro risultato.

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁷.
¹⁷https://www.dropbox.com/s/w343e157wpslj4g/chapter_15.zip?dl=0
Service Provider, un pacchetto cotto e
mangiato
Utilizzare nelle nostre applicazioni un ServiceProvider ha senso se di applicazioni complesse si tratta.
E’ un libro pratico e passiamo alla pratica. Nella lettura se ne comprenderà l’utilità.

La nostra classe
Abbiamo la necessità di costruire un sistema di classi: immaginiamo di avere una classe Biblioteca
e due sottoclassi Autori e Libri. Partiamo:

1 // app/Services/BibliotecaClass.php
2
3 namespace App\Services;
4
5 class BibliotecaClass{
6
7 public function listaAutori()
8 {
9
10 }
11
12
13 public function listaLibri()
14 {
15
16 }
17 }

Due i metodi. Adesso tocca alle altre due classi.

82
Service Provider, un pacchetto cotto e mangiato 83

1 // app/Services/AutoriClass;
2 namespace App\Services;
3
4 class AutoriClass{
5
6 public function lista()
7 {
8 return [
9 'Umberto Eco'
10 ,'Sandro Veronesi'
11 ,'Vittorio Sgarbi'
12 ];
13 }
14 }

In ultimo LibriClass:

1 // app/Services/LibriClass.php
2 namespace App\Services;
3
4 class LibriClass{
5
6 public function lista()
7 {
8 return [
9 'Il nome della rosa'
10 ,'Caos Calmo'
11 ,'Piene di Grazia'
12 ];
13 }
14 }

Dunque, a questo punto consideriamo la classe BibliotecaClass come quella principale, cioè quella
che utilizzerà, al suo interno, AutoriClass e LibriClass. Vediamo come:
Service Provider, un pacchetto cotto e mangiato 84

1 // app/Services/BibliotecaClass.php
2 namespace App\Services;
3 use App\Services\AutoriClass;
4
5 class BibliotecaClass{
6
7 public function listaAutori()
8 {
9 $autori = new AutoriClass();
10 return $autori->lista();
11 }
12
13
14 public function listaLibri()
15 {
16
17 }
18 }

Nel nostro file di route:

1 // app/Http/routes.php
2 Route::get('/', function () {
3 $bi = new App\Services\BibliotecaClass;
4 return $bi->listaAutori();
5 });

Il nostro ServiceProvider
La procedura è identica se vogliamo utilizzare la classe LibriClass: evitiamo l’esempio e andiamo
avanti. Siamo pronti per il ServiceProvider. Artisan ci viene in aiuto:

1 php artisan make:provider BibliotecaServiceProvider

In app/Providers troveremo il file appena creato:


Service Provider, un pacchetto cotto e mangiato 85

1 // app/Providers/BibliotecaServiceProvider.php
2 namespace App\Providers;
3
4 use Illuminate\Support\ServiceProvider;
5
6 class BibliotecaServiceProvider extends ServiceProvider
7 {
8 /**
9 - Bootstrap the application services.
10 *
11 - @return void
12 */
13 public function boot()
14 {
15 //
16 }
17
18 /**
19 - Register the application services.
20 *
21 - @return void
22 */
23 public function register()
24 {
25 //
26 }
27 }

Su questa classe ci ritorneremo a breve. Facciamo una piccola digressione.

E i metodi “statici”
L’obiettivo è rendere “statici” i metodi di BibliotecaClass. Per fare questo occorre una classe Facade.
Eccola:
Service Provider, un pacchetto cotto e mangiato 86

1 // app/Services/Facade/BibliotecaClass.php
2 namespace App\Services\Facades;
3
4 use Illuminate\Support\Facades\Facade;
5
6 class BibliotecaClass extends Facade{
7
8 protected static function getFacadeAccessor() { return 'bibliotecaclass'; }
9 }

Questa classe ha solo un metodo getFacadeAccessor con all’interno il nome della classe. Facciamo
interagire questa classe con il ServiceProvider:

1 // app/Providers/BibliotecaServiceProvider.php
2
3 ...
4 public function register()
5 {
6 \App::bind('bibliotecaclass', function () {
7 return new \App\Services\BibliotecaClass;
8 });
9 }

Poi registriamo il ServiceProvider in config/app.php

1 // config/app.php
2 'providers' => [
3 ...
4 App\Providers\BibliotecaServiceProvider::class,
5
6 ];

Creiamo, sempre nello stesso file, un comodo Alias:

1 // config/app.php
2
3 'aliases' => [
4 ...
5 'Biblio' => App\Services\Facades\BibliotecaClass::class,
6 ];

Ok, vediamo infine l’effetto nel file di route:


Service Provider, un pacchetto cotto e mangiato 87

1 // app/Http/routes.php
2 Route::get('/', function () {
3
4 return Biblio::listaAutori();
5 });

Precisazioni
L’esempio mostrato è ridicolo. Ma, come accennato all’inizio del capitolo, il ServiceProvider ha una
sua utilità in progetti complessi, dove l’interazione tra classi è essenziale. E’ inoltre un approccio
molto elegante e pulito se vogliamo creare dei pacchetti per Laravel da scaricare nella cartella vendor.
Ad esempio:

1 composer require mionome/miopacchetto

Come? Sarebbe bello sapere come farlo? Nei prossimi capitoli affronteremo anche questo argomento
:)

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁸.
¹⁸https://www.dropbox.com/s/sftwsbguh1pfj0f/chapter_16.zip?dl=0
View composer: evitare ridondanze
Quante volte sarà capitato di ripetere query in ogni metodo del controller? Sempre, mai? Qualunque
sia la risposta, le View Composer sono un “must” per chi vuol fare questo mestiere con serietà.
L’utilità è proprio quella di evitare ridondanze nel codice, ottimizzando il trasferimento di variabili
all’interno delle view.

Immancabile template bootstrap


Abbiamo bisogno di una view e di un suo include parziale che conterrà il risultato di questo capitolo.
Ecco la view (è una banale pagina di esempio prelevata dal sito del framework CSS Bootstrap:

1 // resources/views/template.blade.php
2 <!DOCTYPE html>
3 <html lang="en">
4 <head>
5 <meta charset="utf-8">
6 <meta http-equiv="X-UA-Compatible" content="IE=edge">
7 <meta name="viewport" content="width=device-width, initial-scale=1">
8 <!-- The above 3 meta tags *must* come first in the head; any other head content\
9 must come *after* these tags -->
10 <title>Bootstrap 101 Template</title>
11
12 <!-- Bootstrap -->
13 <!-- Latest compiled and minified CSS -->
14 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css\
15 /bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZl\
16 pLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
17
18 <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queri\
19 es -->
20 <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
21 <!--[if lt IE 9]>
22 <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
23 <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
24 <![endif]-->
25
26 </head>

88
View composer: evitare ridondanze 89

27 <body>
28 <nav class="navbar navbar-inverse navbar-fixed-top">
29 <div class="container">
30 <div class="navbar-header">
31 <button type="button" class="navbar-toggle collapsed" data-toggle="colla\
32 pse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
33 <span class="sr-only">Toggle navigation</span>
34 <span class="icon-bar"></span>
35 <span class="icon-bar"></span>
36 <span class="icon-bar"></span>
37 </button>
38 <a class="navbar-brand" href="#">Project name</a>
39 </div>
40 <div id="navbar" class="collapse navbar-collapse">
41 <ul class="nav navbar-nav">
42 <li class="active"><a href="#">Home</a></li>
43 <li><a href="#about">About</a></li>
44 <li><a href="#contact">Contact</a></li>
45 </ul>
46 </div><!--/.nav-collapse -->
47 </div>
48 </nav>
49
50 <div class="container">
51 <div class="row">
52 <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
53 Hello
54 </div>
55 </div>
56 </div>
57
58 <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
59 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">\
60 </script>
61 <!-- Include all compiled plugins (below), or include individual files as needed\
62 -->
63
64 <!-- Latest compiled and minified JavaScript -->
65 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js\
66 " integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9a\
67 J7xS" crossorigin="anonymous"></script>
68
View composer: evitare ridondanze 90

69 </body>
70 </html>

Andiamo ad isolare la navbar in un include a parte:

1 // resources/views/includes/partialnav.blade.php
2 <nav class="navbar navbar-inverse navbar-fixed-top">
3 <div class="container">
4 <div class="navbar-header">
5 <button type="button" class="navbar-toggle collapsed" data-toggle="colla\
6 pse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
7 <span class="sr-only">Toggle navigation</span>
8 <span class="icon-bar"></span>
9 <span class="icon-bar"></span>
10 <span class="icon-bar"></span>
11 </button>
12 <a class="navbar-brand" href="#">Project name</a>
13 </div>
14 <div id="navbar" class="collapse navbar-collapse">
15 <ul class="nav navbar-nav">
16 <li class="active"><a href="#">Home</a></li>
17 <li><a href="#about">About</a></li>
18 <li><a href="#contact">Contact</a></li>
19 </ul>
20 </div><!--/.nav-collapse -->
21 </div>
22 </nav>

E nella parte “tagliata” del template scriviamo:

1 // resources/views/template.blade.php
2
3 @include('includes.partialnav')
4 ...

Per verificarne il funzionamento modifichiamo il file di route:


View composer: evitare ridondanze 91

1 // app/Http/routes.php
2 Route::get('/', function () {
3 return view('template');
4 });

All’indirizzo localhost (o come è stato chiamato in base al vostro ambiente), avremmo il template
Bootstrap.

La tabella
Prima di tutto ci occorre un Model per gestire la nostra tabella “cart”:

1 php artisan make:model Cart

Nel file appena creato indichiamo che la tabella non sarà al plurale:

1 // app/Cart.php
2
3 class Cart extends Model
4 {
5 protected $table = 'cart';
6 }

Poi occupiamoci brevemente della migration:

1 php artisan make:migration create_cart_table

Andiamo a cancellare nella cartella “database/migrations/” i due file che riguardano la tabella “users”
e “password”: non ci interessa creare queste tabelle. Lavoriamo, invece, sulla tabella “cart”:

1 // database/migrations/2015_xx_xx_101927_create_cart_table.php
2
3 public function up()
4 {
5 Schema::create('cart', function (Blueprint $table) {
6 $table->increments('id');
7 $table->integer('idprodotto');
8 $table->timestamps();
9 });
10 }

La tabella è imbarazzante per la sua semplicità. A noi serve solo riempirla con un paio di record. E
lo faremo senza alcuna illustrazione.
View composer: evitare ridondanze 92

Variabile
Nel nostro file di inclusione ‘partialnavbar’ vogliamo aggiungere la quantità di prodotti presenti nel
carrello (mi auguro siano stati aggiunti un paio di record). Ecco come: lo faremo sostituendo la riga
“About” (ma può essere posizionato ovunque):

1 // resources/views/includes/partialnav.blade.php
2 <ul class="nav navbar-nav">
3 <li class="active"><a href="#">Home</a></li>
4 <li><a href="">Carrello ({{$prodottiCarrello}})</a></li>
5 <li><a href="#contact">Contact</a></li>
6 </ul>

Naturalmente se richarichiamo la pagina, Laravel ci restituirà l’errore. Risolviamolo nel file di route:

1 // app/Http/routes.php
2
3 Route::get('/', function () {
4
5 $prodottiCarrello = App\Cart::count();
6 return view('template', compact('prodottiCarrello'));
7 });

Bene, fin qui nulla di eccezionale. Ma se dovessimo visualizzare la quantità dei prodotti in ogni
metodo del controller (quindi in ogni pagina), dovremmo portarci appresso questa query ovunque
perché si trova nel template, o meglio nella barra di navigazione. Quindi, in un’ipotetica nuova
pagina dovremmo scrivere questo:

1 // app/Http/routes.php
2 Route::get('prodotti', function(){
3 $prodottiCarrello = App\Cart::count();
4 return view('template', compact('prodottiCarrello'));
5 });

E così per tutte. Laravel ci viene in aiuto con le View Composer. Vediamo come ottimizzare questo
processo. Creiamo un nostro ServiceProvider con il comando artisan:

1 php artisan make:serviceprovider ViewComposerServiceProvider

E aggiungiamo la nuova istruzione nel metodo “boot”:


View composer: evitare ridondanze 93

1 // app/Providers/ViewComposerServiceProvider.php
2 namespace App\Providers;
3
4 use Illuminate\Support\ServiceProvider;
5
6 class ViewComposerServiceProvider extends ServiceProvider
7 {
8 /**
9 - Bootstrap the application services.
10 *
11 - @return void
12 */
13 public function boot()
14 {
15 view()->composer('includes.partialnav', function($view){
16 $view->with('prodottiCarrello', \App\Cart::count());
17 });
18 }
19
20 /**
21 - Register the application services.
22 *
23 - @return void
24 */
25 public function register()
26 {
27 //
28 }
29 }

Subito dopo informiamo Laravel che esiste questo nuovo ServiceProvider:

1 // app/config.php
2
3 'providers' => [
4 ...
5 App\Providers\ViewComposerServiceProvider::class,
6 ],

Quasi finito: ripuliamo il nostro file di route dalle chiamate al db:


View composer: evitare ridondanze 94

1 // app/Http/routes.php
2 Route::get('/', function () {
3 return view('template', compact('prodottiCarrello'));
4 });
5
6
7 Route::get('prodotti', function(){
8 return view('template', compact('prodottiCarrello'));
9 });

Adesso richiamiamo le nostre pagine sul browser e, come per incanto, funzionerà tutto alla
perfezione. Ma facciamo qualcosina di più, rendiamo il nostro codice ancora più “lungimirante”. Nel
nostro ServiceProvider spostiamo la porzione del codice in un ulteriore metodo, perché potremmo
aver bisogno di più View Composer in base alle esigenze e il metodo “boot” si sovraffollerebbe:

1 // app/Providers/ViewComposerServiceProvider.php
2
3 public function boot()
4 {
5 $this->viewForNavigation();
6 }
7
8 private function viewForNavigation()
9 {
10 view()->composer('includes.partialnav', function ($view) {
11 $view->with('prodottiCarrello', \App\Cart::count());
12 });
13 }

Inoltre possiamo evitare di utilizzare una Closure nel metodo “composer”, passando a quest’ultimo
direttamente un metodo di una classe ulteriore. Vediamo in pratica:

1 // app/Providers/ViewComposerServiceProvider.php
2 private function viewForNavigation()
3 {
4 view()->composer('includes.partialnav', 'App\Http\Composers\Navigation');
5 }

La classe composer che andremo a creare ha un metodo di default “compose” all’interno del quale
andremo a definire la nostra funzione. Creiamola:
View composer: evitare ridondanze 95

1 // app/Http/Composers/Navigation.php
2 namespace App\Http\Composers;
3
4 use Illuminate\Contracts\View\View;
5
6 class Navigation
7 {
8
9 public function compose(View $view){
10
11 $view->with('prodottiCarrello', \App\Cart::count());
12 }
13 }

Se invece dovessimo cambiare il nome del metodo in “nav” (ad esempio):

1 // app/Http/Composers/Navigation.php
2 namespace App\Http\Composers;
3
4 use Illuminate\Contracts\View\View;
5
6 class Navigation
7 {
8
9 public function nav(View $view){
10
11 $view->with('prodottiCarrello', \App\Cart::count());
12 }
13 }

Nel nostro ServiceProvider dobbiamo indicarlo in questo modo:

1 // app/Providers/ViewComposerServiceProvider.php
2 private function viewForNavigation()
3 {
4 view()->composer('includes.partialnav', 'App\Http\Composers\Navigation@nav');
5 }

Conclusioni
Le View Composer sono uno strumento efficacissimo per le operazioni ridondanti e per l’ottimiz-
zazione del codice. Quando si presentano query da ripetere in diverse pagine il loro utilizzo è
d’obbligo.
View composer: evitare ridondanze 96

Download dell’applicazione
I file trattati in questo capitolo puoi scaricarli a questo indirizzo¹⁹.
¹⁹https://www.dropbox.com/s/jr3mt1vl325vjdo/chapter_17.zip?dl=0
Appendice
Laravel 5.2, le novità

Implicit route binding


Per comprendere questa nuova funzionalità, installiamo la versione 5.2 di Laravel (il comando è il
medesimo della versione 5.1). Configuriamo, nel file env i parametri per connetterci con il db. Subito
dopo lanciamo la migration fornita da Laravel per creare la tabella utenti:

1 php artisan migrate

A questo punto la tabella users è creata. Con la classe Factory riempiamo velocemente la tabella
con un po’ di dati. Ecco come: nel file database/factories/ModelFactory.php troveremo una closure
che riceverà un’istanza dalla libreria PHP Faker che - a sua volta - genererà una serie di dati dalla
tipologia indicata in questo file. Non tocchiamo nulla ed apriamo il file di route.

1 // app/Http/routes.php
2 Route::get('genera', function(){
3 factory(App\User::class, 3)->create();
4 });

Abbiamo appena utilizzato la closure che creerà tre record casuali nel nostro db. Dopo aver riempito
un db vediamo la procedura per visualizzare un record ed entriamo nel vivo dell’implicit route
binding. Ecco un esempio:

1 // app/Http/routes.php
2
3 Route::get('utenti/{user}', function(App\User $user){
4 return $user;
5 });

Se andiamo alla pagina “http://localhost/utenti/3” comparirà il record numero 3 (a proposito, con


il semplice return $user Laravel trasforma l’output direttamente in JSON). Se dovessimo fare un
cambiamento di questo tipo:

97
Appendice 98

1 // app/Http/routes.php
2 Route::get('utenti/{user}', function(App\User $utente){
3 return $utente;
4 });

non avremmo alcun risultato perché la variabile non è identica alla wildcard {user}, quindi è una
comodità, ma può diventare una scomodità in caso di refactoring del codice. Questa procedura è
inoltre rapida se vogliamo procedere per ID, ma cosa accade se volessimo utilizzare come segmento
il campo name presente nella tabella? Se volessimo utilizzare lo stesso esempio di prima:

1 // app/Http/routes.php
2 Route::get('utenti/{name}', function(App\User $name){
3 return $name;
4 });

Laravel continuerebbe a considerare la wildcard {name} come ID. Per variare questo comportamento,
andiamo nel nostro RouteServiceProvider e scriviamo:

1 // app/Providers/RouteServiceProvider.php
2
3 ...
4
5 public function boot(Router $router)
6 {
7 parent::boot($router);
8
9 \Route::bind('name', function($name){
10 return \App\User::where('name', $name)->firstOrFail();
11 });
12 }

Subito dopo digitiamo:

1 http://localhost/utenti/Markus Block

(nel mio caso uno dei nomi è Markus Block: è una variabile!).
Ed ecco che il risultato è sempre il record indicato. E’ bene osservare come il primo parametro di
Route::bind() sia importante: deve coincidere con la wildcard nel file di route.

Potrebbero piacerti anche