Differenze

Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.

Link a questa pagina di confronto

Entrambe le parti precedenti la revisioneRevisione precedente
Prossima revisione
Revisione precedente
php:laravel [2017/04/30 20:33] – wip apressatophp:laravel [2017/04/30 23:47] (versione attuale) – Prima Stesura Definitiva apressato
Linea 1: Linea 1:
 ====== Laravel ====== ====== Laravel ======
  
-<WRAP center round alert 60%> +<WRAP center round important 60%> 
-**Attenzione:** Documento non completo in fase di stesura+**Attenzione:** Documento completo in fase di revisione
 </WRAP> </WRAP>
  
Linea 126: Linea 126:
 In questo breve esempio sfruttiamo la classe Request, mappata tramite alias verso ''Illuminate\Support\Facades\Request'', per recuperare metodo HTTP e URL della richiesta. E’ interessate però sapere che all’interno del file relativo (presente nella cartella ''vendor''), non è presente nessun metodo statico ''method()'' o ''url()''. In questo breve esempio sfruttiamo la classe Request, mappata tramite alias verso ''Illuminate\Support\Facades\Request'', per recuperare metodo HTTP e URL della richiesta. E’ interessate però sapere che all’interno del file relativo (presente nella cartella ''vendor''), non è presente nessun metodo statico ''method()'' o ''url()''.
  
-L’unico metodo disponibile è ''getFacadeAccessor'' che determina il nome dell’oggetto presente nel ServiceContainer sul quale invocare il metodo relativo. Grazie al //magic method// di PHP ''__callStaticMethod'' è infatti possibile invocare il metodo sull’istanza dell’oggetto relativo che nel caso di ''Request'' è ''Illuminate\Http\Request''.+L’unico metodo disponibile è ''getFacadeAccessor'' che determina il nome dell’oggetto presente nel ServiceContainer sul quale invocare il metodo relativo. Grazie al //magic method// di PHP ''<nowiki>__</nowiki>callStaticMethod'' è infatti possibile invocare il metodo sull’istanza dell’oggetto relativo che nel caso di ''Request'' è ''Illuminate\Http\Request''.
  
 Consultando questa [[http://laravel.com/docs/5.1/facades#facade-class-reference|pagina]] sarà possibile reperire l’elenco dei facade disponibili in Laravel e dei quali verrà fatto largo uso nei prossimi articoli. Consultando questa [[http://laravel.com/docs/5.1/facades#facade-class-reference|pagina]] sarà possibile reperire l’elenco dei facade disponibili in Laravel e dei quali verrà fatto largo uso nei prossimi articoli.
Linea 781: Linea 781:
      
 Per definire la relazione inversa possiamo utilizzare il metodo ''belongsTo'' nello stesso modo analizzato per le relazioni uno a uno.   Per definire la relazione inversa possiamo utilizzare il metodo ''belongsTo'' nello stesso modo analizzato per le relazioni uno a uno.  
-Nel prossimo capitolo verranno analizzate le restanti tipologie di relazione, più articolate rispetto a quelle già esposte.                                                     +Nel prossimo capitolo verranno analizzate le restanti tipologie di relazione, più articolate rispetto a quelle già esposte.       
 + 
 +==== Eloquent, relazioni uno a molti, molti a molti e polimorfiche ====                                  
 + 
 +=== Relazioni molti a molti ===   
 +Le precedenti relazioni erano abbastanza semplici, rappresentavano in fondo la stessa tipologia di relazione e non introducevano strutture dati relazionali particolari, se non la necessità  di avere una colonna in più nel database. Le **relazioni molti a molti** sono più complesse e necessitano la presenza di tre tabelle: due per rappresentare le entità e una, chiamata **tabella pivot**, per gestire le relazioni. Il nome di questa terza tabella è derivato dai nomi della altre due unendo i nomi singolari di esse, in ordine alfabetico, separati da un underscore.   
 +Un'implementazione di una classica ''wishlist'' presenterà quindi la tabella ''users'', la tabella ''products'' e la tabella ''product_user''. Quest'ultima dovrà contenere la colonna ''user_id'' e la colonna ''product_id''  
 +Per definire la relazione basta utilizzare il metodo ''belongsToMany''. La relazione non ha modelli "deboli" e "forti", quindi il metodo potrà essere utilizzato da entrambe le entità.   
 +<code php> 
 +class User extends Model { 
 +    public function products() { 
 +        return $this->belongsToMany('App\Product'); 
 +    } 
 +
 +[...] 
 +class Product extends Model { 
 +    public function users() { 
 +        return $this->belongsToMany('App\User'); 
 +    } 
 +
 +</code> 
 +   
 +Eventuali parametri addizionali del metodo ''belongsToMany'', utili solo nel caso non si rispettino le convenzioni, sono: nome della tabella pivot, nome della colonna che contiene l'id della prima tabella e nome della colonna della seconda tabella.   
 +Alcuni tipi di relazioni molti a molti necessitano la presenza di eventuali altre colonne all'interno della tabella pivot. Nel nostro piccolo esempio della ''wishlist'' potrebbe essere la data di inserimento del prodotto. Laravel permette di accedere ai dati addizionali della tabella pivot tramite una particolare ''property'' ''pivot'' a patto che questi dati siano evidenziati nella configurazione della relazione.   
 +<code php> 
 +class User extends Model { 
 +    public function products() { 
 +        return $this->belongsToMany('App\Product')->withPivot('extraField'); 
 +    } 
 +
 +[...] 
 +$products = User::find(1)->products(); 
 +$products[0]->pivot->extraField; 
 +</code> 
 +   
 + 
 +=== Relazioni uno a molti indiretta ===   
 +Questo tipo di relazione rappresenta una scorciatoia nel caso di struttura complessa di entità relazionate tra loro secondo un modello uno a molti. Supponendo una struttura dati che modella le entità ''Artist'', ''Album'' e ''Song'', dove ''Artist'' e ''Album'' sono relazionati uno a molti così come ''Album'' e ''Song'', tramite una **relazione uno a molti indiretta** è possibile risalire alle canzoni di un artista, passando, in maniera totalmente trasparente, dalla tabella degli album.   
 +Per definire questo tipo di relazione usiamo il metodo ''hasManyThrough''  
 +<code php> 
 +class Artist extends Model { 
 +    public function songs() { 
 +        return $this->hasManyThrough('App\Song', 'App\Album'); 
 +    } 
 +
 +</code> 
 +   
 +Le convenzioni utilizzate da Laravel sono quelle già viste in precedenza. Nel caso fosse necessario personalizzare qualcosa, è possibile utilizzare i parametri addizionali del metodo ''hasManyThrough''  
 + 
 +=== Relazioni polimorfiche ===   
 +Le **relazioni polimorfiche** sono una delle funzionalità di Eloquent più particolari e spesso non si trovano in altri ORM. Immaginiamo un modello dati che permetta di avere relazioni uno a molti ma con oggetti di natura diversa e un'unica entità correlata. Pensiamo per esempio alle entità ''Album'', ''Artist'' e ''Photo'' e in particolare alla possibilità di avere foto sia legate all'album (per esempio la copertina) che all'artista.   
 +Ovviamente questo modello è implementabile con una doppia relazione uno a molti, ma questo sarebbe limitante nel caso si voglia considerare integra l'entità ''Photo''. Le relazioni polimorfiche permettono appunto di avere un unica tabella ''Photo'' che è in grado di gestire relazioni con ''Album'' e ''Artist''  
 +Le tabelle ''Artists'' e ''Albums'' non presentano nulla di particolare, tutto è implementato nella tabella ''Photos''. Oltre alle colonne di business, sarà  necessario avere due colonne dedicate alla relazione, una contenente l'id dell'entità relazionata e uno contenente il tipo (che in questo modello potrà essere ''album'' o ''artist''). Queste due colonne devono condividere un prefisso che rappresenta il nome astratto delle entità relazionate, per esempio ''coverable''  
 +Riassumendo quindi una struttura database per questo tipo di relazione potrebbe essere:   
 +<code php> 
 +// tabella artists 
 +id, name 
 + 
 +// tabella albums 
 +id, name, year, artist_id 
 + 
 +// tabella photos 
 +id, url, coverable_id, coverable_type</code> 
 +   
 +La definizione della relazione invece:   
 +<code php> 
 +class Photo extends Model { 
 +    public function coverable() { 
 +        return $this->morphTo(); 
 +    } 
 +
 +class Artist extends Model { 
 +    public function photos() { 
 +        return $this->morphMany('App\Photo', 'coverable'); 
 +    } 
 +
 +class Album extends Model { 
 +    public function photos() { 
 +        return $this->morphMany('App\Photo', 'coverable'); 
 +    } 
 +
 +</code> 
 +   
 +Grazie a questi metodi abbiamo creato una relazione bidirezionale. Sarà  quindi possibile recuperare le foto di un album (o artista) in questo modo:   
 +<code php> 
 +Album::find(1)->photos 
 +</code> 
 +   
 +e l'entità  relazionata a partire dalla photo:   
 +<code php> 
 +Photo::find(1)->coverable 
 +</code> 
 +   
 + 
 +=== Relazioni polimorfiche molti a molti ===   
 +L'ultima tipologia di relazione configurabile in Laravel è una versione modificata delle relazioni polimorfiche che però include la possibilità  di avere una relazione molti a molti tra l'entità ''morph'' e le altre. Riprendendo il nostro contesto musicale, possiamo creare una relazione di questo tipo partendo da ''Artists'', ''Album'', ''Songs'' e ''Genre'' e supponendo che un artista possa avere un genere principale, ma possa aver inciso album o canzoni di un diverso genere. In questo caso il genere è l'oggetto ''morph'' che si relaziona a ben 3 diverse entità .   
 +La struttura dati sarà  simile a quella precedente se non per il fatto che viene creata una tabella pivot per gestire la relazione molti a molti:   
 +<code php> 
 +// tabella artists 
 +id, name 
 + 
 +// tabella albums 
 +id, name, year, artist_id 
 + 
 +// tabella songs 
 +id, name, album_id 
 + 
 +// tabella genre 
 +id, genre 
 + 
 +// tabella genreable 
 +id, genreable_id, genreable_type 
 +</code> 
 +   
 +Per definire la relazione all'interno delle nostre classi PHP utilizziamo i metodi ''morphToMany'' e ''morphByMany''   
 +<code php> 
 +class Artist { 
 +    public function genres() { 
 +        return $this->morphToMany('App\Genre', 'genreable'); 
 +    } 
 +
 +class Album { 
 +    public function genres() { 
 +        return $this->morphToMany('App\Genre', 'genreable'); 
 +    } 
 +
 +class Song { 
 +    public function genres() { 
 +        return $this->morphToMany('App\Genre', 'genreable'); 
 +    } 
 +
 +class Genre { 
 +    public function artists() { 
 +        return $this->morphedByMany('App\Artist', 'genreable'); 
 +    } 
 +    public function albums() { 
 +        return $this->morphedByMany('App\Album', 'genreable'); 
 +    } 
 +    public function songs() { 
 +        return $this->morphedByMany('App\Song', 'genreable'); 
 +    } 
 +
 +</code>                                                
 + 
 +==== Eloquent e Migration in Laravel ====                                  
 +L'ultima parte di questa trattazione dedicata ad Eloquent, il motore di ORM presente in Laravel, riguarderà le **migration** e i **seeder**, due strumenti per la gestione del database e dei dati tramite il framework. Nonostante la loro semplicità, si tratta di strumenti di vitale importanza nella definizione del database (migration) e di test (seeder).   
 + 
 +=== Migration ===   
 +Le migration rappresentano lo strumento per il **versioning del database** della nostra applicazione. Quando si lavora in team esistono diversi strumenti per il controllo delle versioni del codice, ma nessuno si occupa delle versioni del database: le migration servono proprio a questo.   
 +Ciascun file rappresenterà un'operazione da eseguire sul database applicativo. Questi file saranno ordinati e sarà possibile gestirli tramite appositi comandi come una vera e propria ''history'', muovendosi in avanti e indietro tra le diverse versioni.   
 +Le migration verranno ospitate nella cartella ''database/migrations'' all'interno della nostra applicazione. Per creare un nuovo file esiste un apposito comando da terminale: ''php artisan make:migration nome_migration''  
 +Ciascuna migration è a tutti gli effetti una **classe PHP** che estende la super classe ''Illuminate\Database\Migrations\Migration''. La classe presenta due soli metodi: ''up'' e ''down''  
 +Questi ultimi rappresentano rispettivamente il comando che si occuperà di creare nuove tabelle o colonne e il comando per annullare queste modifiche. Sarà compito del framework invocare il metodo ''up'' quando si vorrà  aggiornare il database all'ultima versione e ''down'' in caso di revert delle modifiche.   
 +Una volta definita la nostra migration, la potremo attivare tramite comandi da terminale:   
 + ^Comando^Descrizione^ 
 + |''php artisan migrate''|Permetterà aggiornare il database all'ultima versione delle migration.| 
 + |''php artisan migrate:rollback''|Consentirà di tornare indietro di un gruppo di versioni.| 
 + |''php artisan migrate:reset''| Istruzione con cui sarà possibile tornare indietro alla prima versione.| 
 +  
 +   
 + 
 +=== Creazione di nuove tabelle ===   
 +Per creare una nuova tabella possiamo invocare il metodo ''create'' sulla facade ''Schema'' passando come parametro una callback che permette di definire le colonne della nuova tabella.   
 +<code php> 
 +Schema::create('my_first_table', function (Blueprint $table) { 
 +        $table->increments('my_first_id'); 
 +    $table->string('my_first_string_column'); 
 +}); 
 +</code> 
 +   
 +Esistono diversi metodi per le varie tipologie di colonne. Un elenco esaustivo è disponibile nella  [[https://laravel.com/docs/5.1/migrations|documentazione ufficiale]].   
 +Per rinominare una tabella utilizziamo:   
 +<code php> 
 +Schema::rename('my_first_table', 'my_first_renamed_table'); 
 +</code> 
 +   
 +Invece, per eliminarne una sarà possibile ricorrere a:   
 +<code php> 
 +Schema::drop('my_first_table'); 
 +</code> 
 +   
 + 
 +=== Creazione di nuove colonne ===   
 +Per creare nuove colonne possiamo utilizzare un metodo simile a ''create'': ''table''  
 +<code php> 
 +Schema::table('my_first_table', function ($table) { 
 +    $table->integer('my_first_integer_column'); 
 +}); 
 +</code> 
 +   
 +Le colonne possono presentare anche dei modificatori, utili a meglio descrivere la struttura dei dati. Per esempio per definire una colonna come ''nullable'' scriviamo:   
 +<code php> 
 +Schema::table('my_first_table', function ($table) { 
 +    $table->integer('my_first_nullable_column')->nullable(); 
 +}); 
 +</code> 
 +   
 +Eventuali altri modificatori sono ''first'', ''after'' (per definire la posizione della colonna nella tabella), ''default'' (per impostare un valore di default) e ''unsigned'' (per impostare la colonna numerica come ''unsigned'').   
 +Per modificare o rinominare colonne già  esistenti possiamo utilizzare:   
 +<code php> 
 +Schema::table('my_first_table', function ($table) { 
 +    $table->string('my_first_string_column', 50)->nullable()->change(); //imposto la lunghezza a 50 e la rendo nullable 
 +}); 
 + 
 +Schema::table('my_first_table', function ($table) { 
 +    $table->renameColumn('my_first_string_column', 'my_first_renamed_string_column'); 
 +}); 
 +</code> 
 +   
 +Questi ultimi comandi, dato che richiedono query SQL non banali per essere eseguite, necessitano della presenza di un modulo addizionale di Laravel installabile tramite composer: ''doctrine/dbal''  
 +Per eliminare una colonna si ricorrerà invece a:   
 +<code php> 
 +Schema::table('my_first_table', function ($table) { 
 +    $table->dropColumn('my_first_dropped_column'); 
 +}); 
 +</code> 
 +   
 + 
 +=== Indici e chiavi esterne ===   
 +Grazie alle migration è anche possibile definire aspetti più avanzati come indici e chiavi esterne.   
 +Per quanto riguarda gli indici abbiamo a disposizione diversi modificatori: ''unique'' (per creare un indice ''unique''), ''primary'' (per impostare una chiave primaria) e ''index'' (per creare un indice standard).   
 +Le chiavi esterne invece possono essere create con:   
 +<code php> 
 +$table->foreign('external_table_id'
 +        ->references('id')->on('external_table'
 +        ->onDelete('cascade'); 
 +</code> 
 + 
 +==== Eloquent e Seeder in Laravel ====                                  
 + 
 +=== I seeder ===   
 +I seeder rappresentano l'altra faccia della medaglia delle migration e si occupano dell'**inserimento di dati temporanei nel database**. Questi permettono di avere dei dati di test caricati sul database a scopo dimostrativo. A differenza di quanto accade con le migration, data la loro natura i dati inseriti dai seeder non devono rappresentare informazioni utili per il setup dell'applicazione.   
 +Come per le migration è possibile creare un nuovo seeder tramite un'istruzione inviata da linea di comando sulla base della seguente sintassi:    
 +<code> 
 +php artisan make:seeder NomeDelSeeder 
 +</code> 
 +I seeder sono **classi PHP** ospitate nella cartella ''database/seeds'' che presentano un unico metodo ''run'' che dovrà  contenere la logica per l'inserimento dei dati di test. Questi ultimi possono essere inseriti sia attraverso del codice ad hoc che tramite ''factory''  
 +Per il primo caso è sufficiente sfruttare le **API query builder** o direttamente Eloquent per l'inserimento di nuovi record:   
 +<code php> 
 +DB::table('my_first_table')->insert([ 
 +        'name' => str_random(10), 
 +        'age' => rand(10,40) 
 +    ]); 
 +</code> 
 +   
 +Nel caso fosse necessario inserire una mole di dati più corposa possiamo utilizzare le ''Model Factory''  
 + 
 +=== Model Factory ===   
 +Le **Model Factory** permettono di definire, per ciascun modello dell'applicazione, logiche per la definizione di oggetti partendo da dei modelli ''fake'', cioè a solo scopo di test. Tramite la libreria ''Faker'', inclusa direttamente in Laravel, sarà  possibile creare oggetti sempre diversi in pochissimo tempo.   
 +Le factory vengono definite all'interno della cartella denominata ''database/factories'' e sono composte di fatto da una singola callback, utile a definire la struttura dei modelli.   
 +<code php> 
 +$factory->define(App\Album::class, function (Faker\Generator $faker) { 
 +    return [ 
 +    'name' => $faker->name, 
 +    'year' => $faker->year, 
 +    'track_count' => rand(5,15) 
 +    ]; 
 +}); 
 +</code> 
 +   
 +Una volta definita la factory, sarà  possibile invocarla all'interno del seeder tramite l'helper ''factory'':   
 +<code php> 
 +factory(App\Album::class, 50)->create(); //50 album creati con un unico comando. 
 +</code> 
 +   
 + 
 +=== Invocare i seeder ===   
 +Per eseguire i seeder la prima cosa da fare è quella di aggiungere il riferimento all'interno della classe che funge da ''entry point'': ''DatabaseSeeder''. Grazie al metodo ''call'' possiamo aggiungere tanti seeder quanti ne desideriamo.   
 +Una volta fatto ciò, possiamo lanciare il comando   
 +<code> 
 +php artisan seed 
 +</code> 
 +per invocare tutti i seeder configurati. Tramite l'istruzione    
 +<code> 
 +php artisan db:seed --class=MySeeder 
 +</code> 
 +possiamo poi limitare l'esecuzione ad un solo seeder.   
 +Con questo capitolo si chiude la parte teorica dedicata a Eloquent, nel prossimo sfrutteremo le competenze acquisite per incrementare le funzionalità dell'applicazione "Biblios".                                                      
                                  
  
-===== Sviluppare un progetto con Laravel =====+===== Sviluppare un progetto con Laravel =====     
 + 
 +==== Database, modelli, Factory e seed ====                                  
 + 
 +=== Setup del database ===   
 +Dopo la serie di articoli dedicati ad Eloquent è ora di mettere in pratica quanto appreso nel nostro progetto. La prima cosa da fare è quella di configurare i parametri di connessione al database.   
 +Il file di configurazione dedicato al database è banalmente ''config/database.php'' ma il miglior modo di configurare i parametri è utilizzare il file ''.env'' in modo da poter riutilizzare gli stessi file su diversi ambienti; ''.env'' contiene infatti tutte le configurazioni dipendenti dall'ambiente. Le property interessate sono:   
 +^Property^Descrizione^ 
 +|**DB_CONNECTION**|Contiene la tipologia di database utilizzato, di default MySQL| 
 +|**DB_HOST**|Contiene l'ip o l'indirizzo del server db| 
 +|**DB_DATABASE**|Contiene il nome del database| 
 +|**DB_USERNAME**|Contiene lo username| 
 +|**DB_PASSWORD**|Contiene la password| 
 +   
 +=== Definizione dei modelli ===   
 +I primi modelli che creeremo all'interno della nostra applicazione saranno ''Book'' e ''Author''. La relazione che intercorrerà  tra di essi sarà  la classica uno-a-molti basandoci sulla convenzione che un libro abbia un solo autore e lo stesso autore può aver scritto più libri. Oltre a questa relazione esisterà  anche una relazione molti-a-molti tra utente e libro che rappresenta la lettura di un libro: un utente può aver letto più libri e un libro può essere stato letto da più utenti. L'entità ''User'' viene definita di default da Laravel e non ci sarà bisogno di crearla, sia a livello di classe PHP sia di migration.   
 +Partiamo quindi con la creazione delle tabelle tramite le relative migrations. I comandi da eseguire sono:   
 +<code php> 
 +php artisan make:migration create_books_table 
 +php artisan make:migration create_authors_table 
 +php artisan make:migration create_book_user_table 
 +</code> 
 +   
 +La prima tabella (''books'') rappresenta l'entità ''Book'', la seconda tabella (''authors'') rappresenta l'entità  ''Author'' e la terza tabella (''bookuser'') rappresenta la relazione molti-a-molti tra ''User'' e ''Book''  
 +Tutte le migrations dovranno implementare sia il metodo ''up'' che il metodo ''down''. I metodi ''up'' si occuperanno della definizione vera a propria della tabella, mentre i ''down'' solo della loro eliminazione:   
 +<code php> 
 +// metodo up di create_books_table 
 +Schema::create('authors', function (Blueprint $table)  
 +    { 
 +        $table->increments('id'); 
 +        $table->string('firstname'); 
 +        $table->string('lastname'); 
 +        $table->timestamps(); 
 +    }); 
 + 
 +// metodo up di create_authors_table 
 +Schema::create('books', function (Blueprint $table)  
 +    { 
 +        $table->increments('id'); 
 +        $table->string('title'); 
 +        $table->integer('author_id')->unsigned(); 
 +        $table->timestamps(); 
 +    }); 
 + 
 +    Schema::table('books', function (Blueprint $table)  
 +    { 
 +        $table->foreign('author_id'
 +            ->references('id')->on('authors'
 +            ->onDelete('cascade'); 
 +    }); 
 + 
 +// metodo up di create_book_user_table 
 +Schema::create('book_user', function (Blueprint $table)  
 +    { 
 +        $table->integer('book_id')->unsigned(); 
 +        $table->integer('user_id')->unsigned(); 
 +        $table->timestamps(); 
 +    }); 
 +    Schema::table('book_user', function (Blueprint $table)  
 +    { 
 +        $table->foreign('book_id'
 +            ->references('id')->on('books'
 +            ->onDelete('cascade'); 
 +        $table->foreign('user_id'
 +            ->references('id')->on('users'
 +            ->onDelete('cascade'); 
 +    }); 
 +</code> 
 +   
 +Nel primo file vengono create 3 colonne (''id'', ''firstname'' e ''lastname'') e le colonne ''createdat'' e ''updatedat'' grazie al metodo dedicato timestamps(). Nel secondo file vengono create 3 colonne (''id'', ''title'' e ''author_id'') e le colonne timestamps. Viene inoltre creato una chiave esterna verso la tabella ''authors''. Da notare che la chiave esterna viene creata tramite una seconda query, in modo da avere la struttura dati già definita. Nel terzo file, quello della tabella pivot, vengono create le due colonne contenenti le chiavi esterne e i metodi timestamps.   
 +Una volta definite le migrations, lanciamo ''php artisan migrate'' e, se tutto ok, dovremmo ritrovarci con le 3 tabelle create sul database (più l'eventuale tabella ''users'' creata di default da Laravel). Passiamo ora alla definizione delle classi PHP che rappresentano i modelli. Da linea di comando lanciamo:   
 +<code php> 
 +php artisan make:model Book 
 +php artisan make:model Author 
 +</code> 
 +   
 +e andiamo a configure le relazioni utilizzando i metodi di Eloquent:   
 +<code php> 
 +// User.php 
 +public function books() 
 +
 +    return $this->hasMany('Biblios\Book')->withTimestamps(); 
 +
 + 
 +// Book.php 
 +public function author() 
 +
 +    return $this->belongsTo('Biblios\Author'); 
 +
 +public function users() 
 +
 +    return $this->hasMany('Biblios\User')->withTimestamps(); 
 +
 + 
 +// Author.php 
 +public function books() 
 +
 +    return $this->hasMany('Biblios\Book'); 
 +
 +</code> 
 +   
 +La configurazione è abbastanza triviale, grazie al fatto che abbiamo utilizzato i nomi convenzionali per le tabelle e le colonne. L'unica funzionalità  degna di nota è l'utilizzo di ''withTimestamps()'' in coda a ''hasMany'' in modo da avere accesso alle informazioni temporali all'interno della tabella pivot di relazione.   
 +Il primo step è quindi completato. Prima di andare oltre possiamo testare quanto fatto utilizzando tinker, la console disponibile in Laravel. Lanciamo quindi ''php artisan tinker'' e eseguiamo il comando:    
 +<code php> 
 +use Biblios\Author; 
 +use Biblios\Book; 
 +$author = new Author(); 
 +$author->firstname = 'Nome autore'; 
 +$author->lastname = 'Cognome autore'; 
 +$author->save(); 
 +$book = new Book(); 
 +$book->title = 'Prova titolo'; 
 +$book->author()->associate($author); 
 +$book->save(); 
 +</code> 
 +   
 +Se tutto è stato implementato correttamente non dovremmo ottenere errori.   
 + 
 +=== Factory e seed ===   
 +Lo step successivo prevede di definire dei seed che si occuperanno di creare dei dati di test nel database. Le **factory** sono classi che si occupano di costruire istanze di particolari modelli inserendo dei dati di test nelle loro property. Creiamo quindi 2 file all'interno di ''database/factories'' ciascuno dedicato ad un modello: ''AuthorFactory'' e ''BookFactory''  
 +<code php> 
 +// author factory 
 +$factory->define(Biblios\Author::class, function (Faker\Generator $faker)  
 +
 +    return [ 
 +        'firstname' => $faker->firstName, 
 +        'lastname' => $faker->lastName 
 +    ]; 
 +}); 
 + 
 +// book factory 
 +$factory->define(Biblios\Book::class, function (Faker\Generator $faker)  
 +
 +    return [ 
 +        'title' => $faker->sentence(rand(1,5)) 
 +    ]; 
 +}); 
 +</code> 
 +   
 +Dopo le factory possiamo definire il nostro seeder con il comando: ''php artisan make:seed AuthorBookSeeder''. All'interno del file run del nostro nuovo file inseriamo quindi questa porzione di codice per creare 10 autori e 10 libri:   
 +<code php> 
 +factory(Biblios\Author::class, 10)->create()->each(function($author)  
 +    { 
 +        foreach(range(1, 10) as $i)  
 +        { 
 +            $author->books()->save(factory(Biblios\Book::class)->make()); 
 +        } 
 +    }); 
 +</code> 
 +   
 +Il seed può essere avviato con ''php artisan db:seed'' e se tutto è stato implementato correttamente dovremmo ritrovarci un database popolato.                                                       
 + 
 + 
 +==== Controller e interfacce per le operazioni CRUD ====                                  
 + 
 +=== I primi controller CRUD ===   
 +Dopo aver definito la struttura dei dati e dopo aver introdotto una reale persistenza dei dati, possiamo finalmente concentrarci sui **controller** più o meno ufficiali per il nostro progetto. La prima funzionalità che aggiungeremo metterà a disposizione del cliente alcune interfacce per le operazioni **CRUD** (''Create'', ''Read'', ''Update'', ''Delete'') sulle varie entità  disponibili. L'acronimo CRUD incapsula tutte le funzionalità base che vengono spesso implementate nei backoffice. Per il momento ci concentreremo sulle funzionalità core e tralasceremo altri aspetti come le performance e la sicurezza, questi argomenti, non secondari, li affronteremo in futuro.   
 +Il core di Laravel non presenta un modulo per la gestione dell'HTML e dei form, ma esiste una dipendenza esterna, chiamata **Laravel Collective Form**, che permette di creare form in maniera dichiarativa e ''object-oriented''. Laravel Collective è una suite che può includere diverse funzionalità, per il momento utilizzeremo solamente il [[https://laravelcollective.com/docs/5.1/html|modulo HTML]]. Una volta installato tramite Composer, dobbiamo configurare il provider e i due alias. Per il momento ignoriamo lo scopo di queste attività in quanto le approfondiremo nelle prossime lezioni.   
 +Passiamo ora alla creazione dei controller tramite i comandi Laravel. Lanciamo quindi ''php artisan make:controller AuthorController'' e ''php artisan make:controller BookController'' e configuriamo le rotte in questo modo per il mapping automatizzato tra rotte e metodi:   
 +<code php> 
 +Route::resource('author', 'AuthorController'); 
 +Route::resource('book', 'BookController'); 
 +</code> 
 +   
 +L'implementazione dei controller è molto simile, all'interno dell'articolo approfondiremo in dettaglio solamente ''AuthorController'' e per quanto riguarda ''BookController'' le sole caratteristiche peculiari.   
 + 
 +=== AuthorController ===   
 +Partiamo quindi con la definizione del controller ''AuthorController'' analizzando metodo per metodo, ricordando che ogni metodo corrisponde ad un URL mappato automaticamente tramite ''Route::resource''   
 +Il metodo ''index'' si occupa di mostrare l'elenco degli autori disponibili:   
 +<code php> 
 +public function index() 
 +
 +    $authorList = Author::orderBy('firstname', 'asc')->orderBy('lastname', 'asc')->get(); 
 +    return View::make('author/index')->with('authorList', $authorList); 
 +
 +</code> 
 +   
 +Il metodo è abbastanza banale: tramite Eloquent recuperiamo l'elenco degli autori ordinati per ''firstname'' e ''lastname'' e passiamo la lista ottenuta alla view ''author/index''. I metodi ''create'' e ''store'' si occupano della creazione di un autore. Il primo permette di inizializzare un form vuoto, mentre il secondo della validazione e della persistenza:   
 +<code php> 
 +public function create() 
 +
 +    $author = new Author(); 
 +    return View::make('author/form')->with('author', $author); 
 +
 + 
 +public function store(Request $request) 
 +
 +    $this->validate($request, Author::$rules); 
 +    Author::create($request->all()); 
 +    return Redirect::to(route('author.index')); 
 +
 +</code> 
 +   
 +Il primo metodo non fa altro che istanziare un nuovo autore vuoto e di passarlo a ''author/form'', ''store'' invece invoca la validazione e in caso positivo salva l'autore all'interno del database e redirige l'utente alla pagina precedente.   
 +Riguardo alla validazione, l'implementazione di ''store'' utilizza il metodo ''validate'', ereditato dal controller grazie al trait ''ValidatesRequests'' che richiede l'oggetto ''request'' e un elenco di regole di validazione, nella fattispecie la proprietà  statica ''$rules'' presente in ''Author''. Avere le regole di validazione definite dentro il modello è una prassi consolidata in modo da poterle condividere senza doverle ripetere. Ecco come sono implementate:   
 +<code php> 
 +public static $rules = [ 
 +    'firstname' => 'required|min:3|max:40', 
 +    'lastname' => 'required|min:3|max:40' 
 +]; 
 +</code> 
 +   
 +I metodi ''edit'' ed ''update'' rappresentano gli speculari di ''create'' e ''store'' ma si occupano della modifica di un record esistente. Il primo recupera l'autore corrente dal database mentre il secondo valida e persiste:   
 +<code php> 
 +public function edit($id) 
 +
 +    $author = Author::findOrFail($id); 
 +    return View::make('author/form')->with('author', $author); 
 +
 + 
 +public function update(Request $request, $id) 
 +
 +    $this->validate($request, Author::$rules); 
 +    $author = Author::findOrFail($id); 
 +    $author->update($request->all()); 
 +    return Redirect::to(route('author.index')); 
 +
 +</code> 
 +   
 +Rispetto ai due metodi precedenti l'unica differenza risiede nel fatto che non partiamo da un autore vuoto, ma lo recuperiamo, grazie a ''findOrFail'' dal database. L'ultimo metodo si occupa dell'eliminazione di un record:   
 +<code php> 
 +public function destroy($id) 
 +
 +    Author::destroy($id); 
 +    return Redirect::to(route('author.index')); 
 +
 +</code> 
 +   
 +Una volta definiti i metodi passiamo alle view: ''index'' e ''form'' (riutilizzato sia in fase di create che di edit).   
 +<code php> 
 +@section('content'
 +    <p> 
 +        <a href="{{ route('author.create') }}">Create new author</a> 
 +    </p> 
 +    <table class="table"> 
 +        @foreach($authorList as $author) 
 +            <tr> 
 +                <td>{{ $author->firstname }} {{ $author->lastname }}</td> 
 +                <td>{{ $author->bookCount }}</td> 
 +                <td> 
 +                    <a class="btn btn-default" href="{{ route('author.edit', ['author' => $author->id]) }}">Modifica</a> 
 +                </td> 
 +                <td> 
 +                    {!! Form::open(['route' => ['author.destroy', $author->id], 'method' => 'delete' ]) !!} 
 +                        {!! Form::submit('Elimina', ['class' => 'btn btn-danger']) !!} 
 +                    {!! Form::close() !!} 
 +                </td> 
 +            </tr> 
 +        @endforeach 
 +    </table> 
 +@endsection 
 +</code> 
 +   
 +''index.blade.php'' si occupa di mostrare all'interno di una table i record ottenuti dal controller e di inserire i link per la modifica e l'eliminazione. Da notare che il metodo ''delete'' deve essere invocato utilizzando POST, quindi è necessario mascherare il form con un pulsante.   
 +<code php> 
 +@section('content'
 +  
 +    {!! Form::model($author,
 +        'route' => isset($author->id) ? ['author.update', $author->id] : 'author.store',  
 +        'method' => isset($author->id) ? 'put' : 'post' 
 +        ]) !!} 
 +  
 +        <div class="form-group {{ $errors->has('firstname') ? 'has-error' : '' }}"> 
 +            {!! Form::label('firstname', 'Firstname') !!} 
 +            {!! Form::text('firstname', null, ['class' => 'form-control']) !!} 
 +            @foreach($errors->get('firstname') as $error) 
 +                <span class="help-block">{{ $error }}</span> 
 +            @endforeach 
 +        </div> 
 +  
 +        <div class="form-group {{ $errors->has('lastname') ? 'has-error' : '' }}"> 
 +            {!! Form::label('lastname', 'Lastname') !!} 
 +            {!! Form::text('lastname', null, ['class' => 'form-control']) !!} 
 +            @foreach($errors->get('lastname') as $error) 
 +                <span class="help-block">{{ $error }}</span> 
 +            @endforeach 
 +        </div> 
 +  
 +        <div class="form-group"> 
 +            {!! Form::submit('Save', ['class' => 'btn btn-primary']) !!} 
 +        </div> 
 +  
 +  
 +    {!! Form::close() !!} 
 +  
 +@endsection 
 +</code> 
 +   
 +La seconda view, ''form.blade.php'', è senza dubbio più interessante. Innanzitutto si nota come il form viene instanziato grazie all'helper ''Form::model'' che permette di associare automaticamente i campi HTML con le proprietà del modello passato come parametro. Inoltre differenziamo la rotta in base alla presenza o meno dell'id (se non ha ''id'' sarà  una ''create'' altrimenti una ''edit''). Per ogni campo viene mostrata label, campo di testo (gestito automaticamente da ''Form::model'') e l'eventuale messaggio di errore.   
 + 
 +=== BookController ===   
 +Il secondo controller è sviluppato con gli stessi pattern visti in precedenza tranne per alcuni aspetti. Per esempio nel metodo ''index'' utilizziamo ''with'' per usare l'eager loading e ottimizzare il numero di query eseguite:   
 +<code php> 
 +$bookList = Book::orderBy('title', 'asc')->with('author')->get(); 
 +</code> 
 +   
 +Ciò è perché l'informazione dell'autore sarà  necessaria all'interno della view:   
 +<code php> 
 +<td>{{ $book->author->lastname }}</td> 
 +</code> 
 +   
 +Nei metodi ''create'' e ''edit'', che devono preparare la form per la creazione e la modifica, sarà  necessario recuperare la lista degli autori disponibili che serviranno per popolare una select dando all'utente la possibilità  di scegliere l'autore del libro corrente. Cosi facendo costruiamo un array associativo chiave/valore (in particolare ''id''/''lastname'') da passare alla view:   
 +<code php> 
 +$authorList = Author::orderBy('lastname', 'asc')->orderBy('firstname', 'asc')->lists('lastname', 'id'); 
 +</code> 
 +   
 +per poi utilizzarlo nella view grazie a ''Form::select'':   
 +<code php> 
 +{!! Form::select('author_id', $authorList, null, ['class' => 'form-control'])!!} 
 +</code> 
 +   
 + 
 +=== Conclusioni ===   
 +Biblios ha finalmente ha raggiunto un livello di utilizzabilità accettabile. Dal prossimo articolo introdurremo aspetti avanzati che ci permetteranno di arricchire l'applicazione.                                                       
 +         
 + 
 +==== I middleware in un'applicazione basata su Laravel ====                                  
 +I **middleware** rappresentano dei componenti della applicazione Web che fungono da filtri per le chiamate HTTP in entrata. Possono essere usati per esempio per gestire l'autenticazione, ridirigendo l'utente ad una pagina di errore nel caso cercasse di accedere ad una risorsa privata, o per creare un sistema di logging integrato autonomo dai diversi controller. Laravel viene fornito con già un proprio set di middleware, ma è ovviamente possibile definirne di propri.   
 +Per creare un nuovo middleware, Laravel propone un apposito comando artisan:    
 +<code php> 
 +php artisan make:middleware MyBrandNewMiddleware 
 +</code> 
 +   
 +I middleware, all'interno della struttura di cartelle di Laravel, vengono salvati in ''app/Http/Middleware''  
 +Il miglior modo per comprendere il meccanismo dei middleware è quello di immaginarli come dei diversi layer che vengono invocati in serie prima dello scatenamento del metodo del controller. In un qualsiasi punto di questi layer sarà  possibile bloccare l'esecuzione standard o continuare con il flusso normale. Ciascun middleware deve implementare il metodo ''handle($request, Closure $next)''. All'interno di questo metodo sarà nostro onere quello di effettuare la logica di business desiderata prima di invocare la closure ''$next'' che equivale a continuare la catena di layers normalmente.    
 +Tramite i middleware è possibile intervenire sia prima che dopo l'invocazione del controller specifico. In base al momento in cui intervengono, i middleware prendono rispettivamente i nomi di ''before middleware'' e ''after middleware''. Ecco due esempi:   
 +<code php> 
 +class BeforeMiddleware 
 +
 +    public function handle($request, Closure $next) 
 +    { 
 +        // eseguo il codice custom del middleware 
 + 
 +        return $next($request); 
 +    } 
 +
 + 
 +class AfterMiddleware 
 +
 +    public function handle($request, Closure $next) 
 +    { 
 +        $response = $next($request); 
 + 
 +        // eseguo il codice custom del middleware ($response conterrà  il corpo della risposta) 
 + 
 +        return $response; 
 +    } 
 +
 +</code> 
 +   
 + 
 +=== Registrare i middleware ===   
 +In base al contesto di utilizzo, possono esistere due diverse tipologie di middleware: i **middleware globali** e i **middleware route-based**. Nel primo caso si tratta di middleware che scattano per ogni chiamata HTTP verso l'applicazione, nel secondo caso è invece possibile filtrare la loro esecuzione in base alla rotta corrente.   
 +Per registrare dei middleware globali è necessario aggiungere il riferimento alla nostra classe middleware all'interno del file ''app/Http/kernel.php''. Per registrare invece dei middleware basati sulle route è necessario prima registrarli ed assegnargli un nome (sempre all'interno di ''app/Http/Kernel.php'') e successivamente utilizzare il loro nome all'interno della definizione delle rotte impiegando, per esempio, questa sintassi:   
 +<code php> 
 +Route::get('/route/123', ['middleware' => 'auth', function() { 
 +    //  
 +}]); 
 +</code> 
 +   
 +Nel caso fosse necessario, i middleware possono essere assegnati anche utilizzando dei gruppi di rotte:   
 +<code php> 
 +Route::group(['middleware' => 'auth'], function () { 
 + 
 +    Route::get('/route/123', function() { 
 + 
 +    }); 
 + 
 +    [....] 
 + 
 +}); 
 +</code> 
 +   
 +Nell'ottica della non duplicazione del codice, è possibile definire **middleware astratti** e che possono modificare il loro comportamento in base a parametri definibili all'esterno del middleware stesso. Per implementare questa funzionalità è necessario inserire eventuali nuovi parametri nella definizione del metodo ''handle()'' e, nel momento della registrazione, impostare questi nuovi parametri.    
 +Supponendo di dover creare un middleware che comunichi via mail eventuali accessi all'applicazione, potremmo scrivere:   
 +<code php> 
 +class EmailNotifierMiddleware 
 +
 + 
 +    public function handle($request, Closure $next, $recipient) 
 +    { 
 +        //invio mail a $recipient 
 + 
 +        return $next($request); 
 +    } 
 + 
 +
 + 
 +Route::get('/rotta/123', ['middleware' => 'emailnotifier:mail123@domain.it', function ($id) { 
 +    // 
 +}]); 
 + 
 +Route::get('/rotta/456', ['middleware' => 'emailnotifier:mail345@domain.it', function ($id) { 
 +    // 
 +}]); 
 +</code> 
 +                                                               
 + 
 +==== Service Provider in Laravel ====                                  
 +I **service provider** rappresentano il cuore del framework, la parte interna che si occupa di registrare e avviare tutti i componenti presenti in una WebApp, come ad esempio i servizi, eventuali listener di eventi, i middleware e le rotte. All'interno del file ''config/app.php'' è possibile visualizzare l'elenco dei service provider configurati per la nostra applicazione.   
 +Ovviamente Laravel viene fornito con un set di service provider già  configurati: alcuni di questi fanno parte del framework vero e proprio (quelli che appartengono al namespace ''Illuminate\'') mentre altri, nonostante sono già  automaticamente disponibili, sono fisicamente locati all'interno del nostro progetto (in ''app/Providers'') e che appartengono al namespace custom definito (nel caso della nostra applicazione ''Biblios\''). Tale differenza risiede nel fatto che questi ultimi presentano funzionalità che potrebbero essere personalizzate e quindi gli autori del framework hanno deciso di rendere eventuali modifiche più semplici.   
 +Nel dettaglio i service provider sono:   
 +^Service Provider^Descrizione^ 
 +|''AppServiceProvider''|Un service provider vuoto, da utilizzare per piccole configurazioni.| 
 +|''AuthServiceProvider''|Un service provider utilizzato per definire il modello di autenticazione scelto.| 
 +|''EventServiceProvider''|Un service provider dedicato alla registrazione di eventuali eventi custom.| 
 +|''RouteServiceProvider''|Un service dedicato alla configurazione delle rotte al cui interno viene incluso il classico ''app/Http/Routes.php''.| 
 +  
 + 
 +=== Creare service provider ===   
 +Oltre ai service provider già  disponibili in Laravel è ovviamente possibile registrarne altri. Il suggerimento è quello di crearne di nuovi solamente se i 4 descritti precedentemente non sono sufficienti. Per esempio per definire comportamenti personalizzati a livello di rotte o per creare eventi ''application-wide'' bisognerebbe utilizzare rispettivamente il ''RouteServiceProvider'' e l'''EventServiceProvider''  
 +Per creare nuovi provider Laravel mette a disposizione il comando    
 +<code php> 
 +php artisan make:provider NomeProvider 
 +</code> 
 +I provider così creati verranno posizionati insieme agli altri in ''app/Providers''. Le classi create dovranno estendere ''Illuminate\Support\ServiceProvider'' e dovranno avere due metodi: ''register'' e ''boot''. Ovviamente generando il file con ''make:provider'' tutto sarà  già correttamente configurato.   
 +Il metodo ''register'' deve occuparsi esclusivamente della registrazione di nuovi componenti all'interno del service container. **Non è consigliato scrivere frammenti di codice diversi dalla registrazione** perché il metodo viene invocato prima del completamento del container e quindi eventuali servizi richiesti potrebbero non essere ancora pronti e istanziabili.   
 +Il metodo ''boot'' deve occuparsi di eventuali altre logiche da demandare al service provider, come per esempio configurare dei ''ViewComposer''. All'interno del metodo ''boot'', abbiamo la certezza che il service container è già  stato inizializzato con successo e che quindi tutti i componenti sono già  stati bindati con successo.   
 +Una volta definita la nostra classe è necessario registrare il service provider appena definito all'interno del file ''config/app.php'' nella sezione ''providers''  
 + 
 +=== Biblios, servizi e provider ===   
 +Il nostro progetto è rimasto fermo da qualche articolo. La situazione attuale è la seguente:    
 +  * i modelli disponibili sono ''Book'', ''Author'' e ''User''. Tra ''Book'' e ''Author'' esiste una relazione uno a molti, mentre tra ''Book'' e ''User'' una relazione molti a molti (che permette di capire quali utenti hanno letto quali libri).  
 +  * All'url ''/book'' è disponibile l'anagrafica dei libri, gestita dal ''BookController''.  
 +  * All'url ''/author'' è disponibile l'anagrafica degli autori, gestita dall'''AuthorController''.  
 +  * Le rotte sono configurate tramite ''Route::resource''    
 +   
 +La parte disponibile potrebbe essere considerata una sezione di BackOffice (anche se non ancora resa privata). Occupiamoci ora di definire la parte publica a partire dalla home. La homepage presenterà  diverse sezioni:    
 +  * Gli ultimi 3 libri caricati in catalogo.  
 +  * I 3 autori più prolifici.    
 +   
 +Questi blocchi di contenuti dovranno essere riutilizzati in differenti pagine del sito e per questo motivo creeremo dei ''ViewComposer''  
 +Partiamo quindi creando un ''ViewComposerServiceProvider'' con il comando    
 +<code php> 
 +php artisan make:provider ViewComposerServiceProvider 
 +</code> 
 +e lo registriamo in ''config/app.php''. Nel provider registriamo due view composer:   
 +<code php> 
 +public function boot() 
 +
 +    View::composer('shared.lastBook', \Biblios\Http\ViewComposers\LastBookViewComposer::class); 
 +    View::composer('shared.prolificAuthor', \Biblios\Http\ViewComposers\ProlificAuthorViewComposer::class); 
 +
 +</code> 
 +   
 +Creiamo quindi i due view composer, il primo che si occuperà  di recuperare gli ultimi 3 libri e il secondo i 3 autori più prolifici.   
 +<code php> 
 +class LastBookViewComposer { 
 + 
 +    protected $lastBookList = []; 
 + 
 +    public function __construct() { 
 +        $this->lastBookList = Book::orderBy('created_at', 'desc')->limit(3)->get(); 
 +    } 
 + 
 +    public function compose(View $view) { 
 +        $view->with('lastBookList', $this->lastBookList); 
 +    } 
 + 
 +
 + 
 +class ProlificAuthorViewComposer { 
 + 
 +    protected $prolificAuthorList = []; 
 + 
 +    public function __construct() { 
 +        $this->prolificAuthorList = Author::with('books')->limit(3)->get()->sortBy(function($author) { 
 +            return $author->books->count(); 
 +        })->reverse(); 
 +    } 
 + 
 +    public function compose(View $view) { 
 +        $view->with('prolificAuthorList', $this->prolificAuthorList); 
 +    } 
 + 
 +
 +</code> 
 +   
 +Passiamo quindi alla creazione di una nuova rotta per la homepage nella quale includeremo due viste che dovranno chiamarsi esattamente come i nomi registrati nel service provider: ''shared.lastBook'' e ''shared.prolificAuthor''. Puntiamo quindi il nostro browser su:    
 + 
 +<code> 
 +localhost:8000 
 +</code> 
 +e dovremmo vedere le due liste.                                                       
 + 
 + 
 +==== Service Container in Laravel ====                                  
 + 
 +=== Dipendency Injection ===   
 +Alcuni dei pattern più importanti di Laravel, oltre al già introdotto Facade Pattern, sono l'**Inversion of Control** e la **Dependecy Injection**. L'''Inversion of Control'' prevede un'inversione rispetto al classico modello di definizione delle librerie e dipendenze usabili da un particolare componente: non è piu il componente stesso a istanziare e gestire eventuali dipendenze, ma esisterà  un componente globale a livello applicativo che fornirà  le dipendenze.   
 +La ''Dependency Injection'' è un implementazione dell'''Inversion of Control'' che prevede il passaggio di dipendenze attraverso i costruttori delle classi o tramite metodi ''setter'' dedicati. Una delle caratteristiche comuni a tutti i framework che implementano questi pattern, anche in linguaggi diversi da PHP, è il concetto di "Container", un raccoglitore di componenti che si occupa di creare le relazioni di dipendenza tra di essi. Il **Service Container** di Laravel è appunto questo contenitore di classi dal quale sarà  possibile utilizzare le dipendenze.   
 +Cerchiamo di capire meglio tramite un esempio contestualizzato alla nostra applicazione. Supponiamo di voler introdurre un sistema di prenotazione di libri che prevede delle logiche particolari di disponibilità; per esempio un libro potrebbe essere disponibile ad un determinato utente solamente se non c'è nessun altro utente in "coda" o se è la prima volta che lo richiede. A prescindere dall'implementazione, una buona pratica è quella di isolare questa logica in una classe dedicata, in modo da poterla riutilizzare in diversi controller.   
 +A questo scopo creiamo un servizio chiamato ''BookAvailabilityManager'' che implementa un particolare metodo ''isAvailable''. Dato che l'argomento è la ''Dependency Injection'' non ci occuperemo della sua implementazione, diamo solamente per assodato che la classe esista e funzioni correttamente. Abbiamo però bisogno di utilizzare questo servizio all'interno del nostro ''BookController'':   
 +<code php> 
 +class BookController extends Controller { 
 + 
 +    public function __construct(Biblios\Service\BookAvailabilityManager $bookAvailabilityManager)  
 +    { 
 +        $this->bookAvailabilityManager = $bookAvailabilityManager; 
 +    } 
 + 
 +    public function showIfBookIsAvailable(Book $book)  
 +    { 
 +        $isAvailable = $this->bookAvailabilityManager->isAvailable($book); 
 +        [...] 
 +    } 
 + 
 +
 +</code> 
 +   
 +In questo piccolo esempio, abbiamo definito un costruttore per il nostro controller che si aspetta di ricevere come parametro il nostro ''BookAvailabilityManager''. In questo caso sarà  Laravel stesso ad accorgersi che abbiamo definito una dipendenza e a passare automaticamente un'istanza durante la creazione del ''BookController''   
 + 
 +=== Binding ===   
 +Per poter utilizzare la ''Dependecy Injection'', oltre alla definizione inevitabile delle nostre classi è necessario creare dei binding all'interno del Service Container per istruire Laravel su quali componenti devono essere gestiti a livello di framework. La creazione dei binding è triviale e viene effettuata all'interno dei service provider (argomento del prossimo capitolo). Esistono tre tipologie di binding.   
 +La prima è il **binding semplice** che permette di definire una closure per istanziare una particolare classe. In questo caso, ogni volta che una classe richiederà il componente registrato la closure verrà  invocata e il suo risultato verrà  iniettato tramite costruttore:   
 +<code php> 
 +$this->app->bind('Biblios\Service\BookAvailabilityManager', function ($app) { 
 +    return new Biblios\Service\BookAvailabilityManager(); 
 +}); 
 +</code> 
 +   
 +La seconda è il **binding singleton**, simile al binding semplice tranne per il fatto che la closure viene invocata solamente una volta e, ad eventuali richieste successive del componente, verrà  iniettata sempre la stessa istanza:   
 +<code php> 
 +$this->app->singleton('Biblios\Service\BookAvailabilityManager', function ($app) { 
 +    return new Biblios\Service\BookAvailabilityManager(); 
 +}); 
 +</code> 
 +   
 +Infine abbiamo il **binding di un'istanza** che, rispetto alle due precedenti modalità, permette di aggiungere al Service Container una particolare istanza di una classe e non una closure.   
 +<code php> 
 +$bam = new Biblios\Service\BookAvailabilityManager(); 
 +$this->app->instance('Biblios\Service\BookAvailabilityManager', $bam); 
 +</code> 
 +   
 + 
 +=== Risolvere le dipendenze ===   
 +Come abbiamo già  visto nell'esempio iniziale, il miglior modo per risolvere una dipendenza è tramite il **type-hinting** nel costruttore del nostro componente, sia esso un controller, un middleware o un event listener. E' altresì possibile accedere ai componenti presenti nel Service Container tramite API dedicate sfruttando il metodo ''make'':   
 +<code php> 
 +$bam = $this->app->make('Biblios\Service\BookAvailabilityManager'); 
 +</code> 
 +   
 +o utilizzare il Service Container come una array associativo PHP:   
 +<code php> 
 +$bam = $this->app['Biblios\Service\BookAvailabilityManager']; 
 +</code> 
 +   
 +Anche secondo gli sviluppatori di Laravel, la modalità  di inject tramite costruttore è da preferire a queste ultime.                                                      
 + 
 + 
 +==== Gestione Utenti in Laravel ====                                  
 +Laravel presenta anche un modulo per la gestione dell'**autenticazione e autorizzazione delle applicazioni Web**. Il framework include automaticamente tra i modelli disponibili la classe ''User'' che rappresenta, grazie ad alcuni traits disponibili nel framework, l'entità  che si occuperà  di rappresentare gli utenti che potranno loggarsi al sito.    
 +All'interno del file ''config/auth.php'' saranno invece disponibili una serie di configurazioni per modificare il flusso di default del framework. Come impostazione predefinita Laravel sfrutta un'autenticazione basata su database e su Eloquent, ma è possibile modificarne il comportamento sia ignorando l'ORM sia non utilizzando del tutto il database.    
 +All'interno di questo e del prossimo articolo utilizzeremo il pattern standard offerto dal framework. Oltre al modello Laravel ci mette a disposizione anche due migration per il setup delle tabelle richieste (''users'' e ''password_resets'').   
 + 
 +=== Controller out-of-the-box ===   
 +All'interno della codebase di Laravel, sono presenti due controller dedicati alla gestione utente e disponibili nella cartella ''app/controllers/auth'':   
 +^Controller^Descrizione^ 
 +|''app\Http\Controllers\Auth\AuthController''|Dedicato ad autenticazione e nuove registrazioni.| 
 +|''app\Http\Controllers\Auth\PasswordController''|Dedicato al reset della password per utenti già registrati.| 
 +  
 +   
 +L'approccio offerto da Laravel allo sviluppatore è quello di rendere disponibili le principali logiche già implementate (comunque configurabili) ma di lasciare a lui la definizione delle rotte e le view (che dipendono strettamente dalle logiche di business).   
 +I metodi offerti dal framework sono questi:   
 +^Metodo^Descrizione^ 
 +|''AuthController@getLogin''|Creazione e visualizzazione della form di login, carica in automatico la view ''auth.login''.| 
 +|''AuthController@postLogin''|Validazione e eventuale procedura di login.| 
 +|''AuthController@getLogout''|Logout.| 
 +|''AuthController@getRegister''|Creazione e visualizzazione della form di registrazione, carica in automatico la view ''auth.register''.| 
 +|''AuthController@getLogout''|Validazione e eventuale registrazione di un nuovo utente.| 
 +|''PasswordController@getEmail''|Creazione e visualizzazion del form "ricorda password", carica in automatico la view ''auth.password''.| 
 +|''PasswordController@postEmail''|Validazione e invio della mail contenente un link con token partendo dalla view ''emails.password''.| 
 +|''Auth\PasswordController@getReset''|Validazione del token ricevuto via mail e visualizzazione del form di reset password, carica in automatico la view ''auth.reset''.| 
 +|''Auth\PasswordController@postReset''|Validazione e modifica della password.| 
 +  
 +=== Configurazioni addizionali ===   
 +Come anticipato, l'approccio del framework è quello di offrire logiche già  implementate ma fortemente configurabili tramite ''property'' dedicate all'interno dell'''AuthController''  
 +Quando un utente è autenticato con successo, il framework lo redirigerà  all'URL ''/home'' ma nel caso questo URL non fosse compatibile con la nostra applicazione possiamo impostare la variabile ''$redirectPath''. Viceversa, in caso di errore durante il processo di autenticazione verrà  caricato l'URL ''/auth/login'' o eventualmente il valore della proprietà  ''$loginPath''  
 +Oltre a poter configurare gli URL, all'interno di ''AuthController'' è possibile implementare nuovamente alcuni metodi, lasciati apposta a livello di applicazione:   
 +^Metodo^Descrizione^ 
 +|''validator''|Permette di modificare le regole di validazione del form di registrazione.| 
 +|''create''|Permette di implementare una nuova logica per inserire il record nel database.|  
 +   
 +Entrambi i metodi vengono utilizzati nel caso in cui in fase di registrazione vengano chiesti ulteriori dati agli utenti (per esempio indirizzo, avatar..).   
 + 
 +=== La facade Auth ===   
 +Oltre ai controller descritti, Laravel presenta anche una facade dedicata a tutte le funzionalità legate all'autenticazione.   
 +Grazie al metodo ''attempt'' è possibile autenticare manualmente un utente passando email e password a prescindere dall'''AuthController''. Questo metodo è utile nel caso si creino link di autologin o possibilità  di impersonificare un utente da parte di un amministratore. Oltre ad ''attempt'' è possibile utilizzare il metodo ''login'' che riceve direttamente un oggetto ''User'' come parametro o ''loginUsingId'' che richiede l'id dell'utente oppure ''once'' che permette di autenticare l'utente solamente per la richiesta successiva, utile in caso di API ''stateless'' che non sfruttino la sessione HTTP.   
 +Nel prossimo articolo implementeremo questo pattern all'interno di Biblios.                                                      
 + 
 + 
 +==== Login e registrazione utenti ====                                  
 +Dopo aver appreso le basi su come Laravel gestisce autenticazioni e autorizzazioni, aggiungiamo ora una gestione utenti basilare ma efficace nella nostra applicazione, Biblios. Le specifiche da implementare sono:    
 + *maschera di **login** a partire da email e password;  
 + *pannello nella parte alta del sito che mostri il link alla pagina di login (se l'utente non è loggato) o i dati dell'utente loggato;  
 + *pagina di **registrazione** che utilizzi **CAPTCHA** per evitare i bot;  
 + ***pagina privata** dove definire alcuni libri come "preferiti";  
 + *rendere private le pagine di anagrafica già create solo per gli amministratori, identificati da una colonna booleana su database.    
 +All'interno dell'articolo ci soffermeremo sugli aspetti specifici dell'argomento, non verrà invece proposto codice utile allo scopo ma non relativo alla "gestione utenti". A corredo verranno comunque forniti i sorgenti funzionanti dell'applicazione in modo da poter testare il tutto e approfondire le parti non esplicitate nel testo.   
 + 
 +=== Il login ===   
 +Come primo passo per implementare il login dobbiamo creare una nuova ''migration'' che si occupi di modificare il database (per inserire la nuova colonna ''admin'' come da specifiche) e un nuovo ''seeder'' per popolare il database con degli utenti di test. Lanciamo quindi    
 +<code php> 
 +php artisan make:migration update_users_admin 
 +</code>   
 +e    
 +<code php> 
 +php artisan make:seed UserSeeder 
 +</code> 
 +e modifichiamo i file appena creati in base alle nostre esigenze.   
 +Una volta modificato e popolato il database possiamo concentrarci sulle prime due specifiche. Iniziamo dalle rotte necessarie che per il momento sono 3:   
 +<code php> 
 +Route::get('/login',
 +    'uses' => 'Auth\AuthController@getLogin', 
 +    'as' => 'login' 
 +]); 
 +Route::post('/login',
 +    'uses' => 'Auth\AuthController@postLogin', 
 +    'as' => 'login.post' 
 +]); 
 +Route::group(['middleware' => 'auth'], function () { 
 +    Route::get('/logout',
 +        'uses' => 'Auth\AuthController@getLogout', 
 +        'as' => 'logout' 
 +    ]); 
 +}); 
 +</code> 
 +   
 +Da notare come la rotta di logout è inserita in un gruppo con un ''middleware'' (''auth'') in quanto è privata ed accessibile solo se l'utente è loggato. I controller utilizzati per le rotte sono quelli standard di Laravel.   
 +Dato che abbiamo configurato delle rotte personalizzate rispetto a quelle out-of-the box, dobbiamo configurare l'''AuthController'' in modo che sappia dove redirigere l'utente. Aggiungiamo quindi queste righe sotto i traits:   
 +<code php> 
 +protected $redirectPath = '/'; 
 +protected $loginPath = '/login'; 
 +</code> 
 +   
 +La prima regola farà si che l'utente una volta loggato venga  rediretto alla home, la seconda lo porterà al login nel caso cercasse di accedere a pagine riservate senza permessi.   
 +Ora possiamo concentrarci sulle view. Gli interventi da fare sono due, implementare la pagina ''login.blade.php'' in ''resources/view/auth'' e modificare ''layout/biblios.blade.php'' per aggiungere il pannello nell'header che verrà  mostrato in tutte le pagine.   
 +<code php> 
 +<div class="row"> 
 +    <div class="col-md-6 pull-right"> 
 +        @if(Auth::check()) 
 +            Benvenuto <b>{{ Auth::user()->name }}</b> <a href="{{ route('logout') }}">Logout</a> 
 +        @else 
 +            <a href="{{ route('login') }}">Login</a> 
 +        @endif 
 +    </div> 
 +</div 
 +</code> 
 +   
 +Se tutto è stato implementato correttamente, dopo queste modifiche saremo in grado di loggarci e di fare logout. Un test ulteriore è provare ad accedere a ''/logout'' da utenti anonimi e verificare che l'applicazione ci rimandi al login.   
 + 
 +=== Registrazione di nuovi utenti ===   
 +Un login è poco funzionale se non è possibile registrarsi. Implementiamo quindi la terza specifica e aggiungiamo due rotte mappate verso i controller standard di Laravel:   
 +<code php> 
 +Route::get('/register',
 +    'uses' => 'Auth\AuthController@getRegister', 
 +    'as' => 'register' 
 +]); 
 + 
 +Route::post('/register',
 +    'uses' => 'Auth\AuthController@postRegister', 
 +    'as' => 'register.post' 
 +]); 
 +</code> 
 +   
 +Per l'implementazione del CAPTCHA dobbiamo affidarci ad una libreria. Per gli esempi ho utilizzato [[https://github.com/mewebstudio/captcha|captcha]]  che oltre ad essere di buona fattura è disponibile come dipendenza [[http://www.html.it/guide/composer-e-packagist-la-guida/|composer]]. Installiamola con:   
 +<code php> 
 +composer require mews/captcha 
 +</code> 
 +e pubblichiamone la configurazione con:   
 +<code php> 
 +php artisan vendor:publish 
 +</code> 
 +verrà creato il file ''config/captcha.php''  
 +Dopo aver creato il file ''resources/view/register.blade.php'' (che sarà  disponibile nei sorgenti), configuriamo l'''AuthController'' in base alle nostre esigenze.   
 +Per far questo dobbiamo modificare le regole di validazione in quanto è disponibile un nuovo campo, il CAPTCHA che richiede una validazione e il metodo di costruzione per impostare su ''false'' il nuovo campo ''admin'' (passaggio non strettamente obbligatorio in quanto i campi boolean sono falsi di default).   
 +<code php> 
 +protected function validator(array $data) 
 +
 +    return Validator::make($data,
 +        'name' => 'required|max:255', 
 +        'email' => 'required|email|max:255|unique:users', 
 +        'password' => 'required|confirmed|min:6', 
 +        'captcha' => 'required|captcha' 
 +    ]); 
 +
 + 
 +protected function create(array $data) 
 +
 +    return User::create([ 
 +        'name' => $data['name'], 
 +        'email' => $data['email'], 
 +        'password' => bcrypt($data['password']), 
 +        'admin' => false 
 +    ]); 
 +
 +</code> 
 +   
 +Facciamo quindi un test di registrazione alla fine del quale dovremmo ritrovarci nella home ma con un nuovo utente archiviato su database.                                                      
 +         
 + 
 +==== Pagina privata, amministratori e anagrafica ====                                  
 + 
 +=== Accesso alla pagina privata ===   
 +Manteniamo lo stesso pattern di sviluppo utilizzato per il capitolo precedente e occupiamoci ora delle rotte:   
 +<code php> 
 +Route::group(['middleware' => 'auth'], function () { 
 +    Route::get('/my-page',
 +        'uses' => 'FrontendController@getPrivatePage', 
 +        'as' => 'private-page' 
 +    ]); 
 +    Route::get('/my-page/{bookId}',
 +        'uses' => 'FrontendController@addFavouriteBook', 
 +        'as' => 'favourite-book' 
 +    ]); 
 +}); 
 +</code> 
 +   
 +Dedichiamoci quindi ai due nuovi metodi nel ''FrontendController'':   
 +<code php> 
 +public function getPrivatePage() 
 +
 +    return View::make('private'); 
 +
 + 
 +public function addFavouriteBook($bookId) 
 +
 +    Auth::user()->books()->attach(Book::findOrFail($bookId)); 
 +    return redirect(route('private-page')); 
 +
 +</code> 
 +   
 +Il primo metodo (''getPrivatePage'') non fa altro che mostrare una view dedicata, mentre il secondo metodo si occupa di ottenere l'oggetto ''Book'' dal database e di associarlo all'elenco dei libri preferiti dall'utente corrente.   
 +Nelle view dobbiamo implementare due aspetti. Il primo è la creazione della **pagina privata**:   
 +<code php> 
 +<div class="row"> 
 +    <div class="col-md-6"> 
 +  
 +        @include('shared.lastBook'
 +  
 +    </div> 
 +    <div class="col-md-6"> 
 +  
 +        <h3>I miei libri preferiti</h3> 
 +  
 +        <ul> 
 +            @foreach(Auth::user()->books as $book) 
 +                <li>{{ $book->title }} ({{ $book->pivot->created_at }})</li> 
 +            @endforeach 
 +        </ul> 
 +  
 +    </div> 
 +</div> 
 +</code> 
 +   
 +Il secondo è la modifica del view composer ''lastBook'' per mostrare un link dedicato all'**aggiunta del libro tra i preferiti**:   
 +<code php> 
 +<ul> 
 +    @foreach($lastBookList as $book) 
 +        <li> 
 +            {{ $book->title }} 
 +            @if(Auth::check()) 
 +                <a href="{{ route('favourite-book', [ 'bookId' => $book->id ]) }}"> 
 +                    Aggiungi 
 +                </a> 
 +            @endif 
 +        </li> 
 +    @endforeach 
 +</ul 
 +</code> 
 +   
 +In questo caso, se tutto è stato implementato correttamente, potremmo aggiungere dei libri tra i preferiti. Ulteriori implementazioni potrebbero essere quelle di evitare l'inserimento di "doppioni" e implementare l'operazione inversa, ovvero l'eliminazione di un libro dai preferiti.   
 + 
 +=== Amministratori e anagrafica contenuti ===   
 +L'ultima specifica che manca è quella di negare l'accesso alle pagine di anagrafica per gli utenti non amministratori. A livello di configurazione di modelli abbiamo già svolto il lavoro aggiungendo una nuova colonna nel database. L'operazione rimanente è a livello di configurazione di rotte, per aggiungere un middleware dedicato a questo controllo personalizzato per le rotte del backoffice.   
 +Creiamo quindi un nuovo middleware con il comando:   
 +<code php> 
 +php artisan make:middleware Admin 
 +</code> 
 +e aggiungiamolo all'interno di ''app/Http/Kernel.php'' tra i middleware registrati.   
 +Implementiamo quindi la sua logica basandoci sul middleware ''Authenticate'' già  presente:   
 +<code php> 
 +public function handle($request, Closure $next) 
 +
 +    if (!$this->auth->user()->admin) { 
 +        if ($request->ajax()) { 
 +            return response('Unauthorized.', 401); 
 +        } else { 
 +            return redirect()->guest('login'); 
 +        } 
 +    } 
 + 
 +    return $next($request); 
 +
 +</code> 
 +   
 +Come ultima operazione modifichiamo il file delle rotte, incapsulando le rotte di anagrafica in un nuovo gruppo dedicato a questo controllo:   
 +<code php> 
 +Route::group(['middleware' => 'admin'], function () { 
 +    Route::resource('author', 'AuthorController'); 
 +    Route::resource('book', 'BookController'); 
 +}); 
 +</code> 
 +   
 +Se tutto è stato implementato correttamente, ora solo gli utenti amministratori potranno accedere alle rotte ''/author'' e ''/book''                                                     
 + 
 + 
 +==== Localizzazione e pluralizzazione ====                                  
 + 
 +=== Localizzazione ===   
 +La cartella ''resources/lang'' contiene le stringhe localizzate utili all'**internazionalizzazione** delle applicazioni Web. All'interno di questa cartella sono presenti diverse sotto cartelle, ognuna per ogni linguaggio supportato. Dentro ciascuna di queste cartelle sarà nostro compito creare diversi file, che fungono da raccolte logiche di etichette localizzate. Ciascuno di questi file si occuperà di definire un hash chiave/valore.   
 +Di default Laravel inizializza una applicazione con una serie di file dedicati alla lingua inglese: ''en''  
 +Il linguaggio di default di una applicazione è definito in ''config/app.php'' ma ovviamente può essere modificato tramite il metodo ''setLocale'' della facade App. Sempre dentro ''app.php'' è possibile configurare un linguaggio di fallback, utilizzato nel caso manchi qualche etichetta del linguaggio corrente.   
 +Per poter utilizzare le etichette localizzate all'interno dei componenti software, il framework mette a disposizione un helper: ''trans''. Il metodo riceve in ingresso una stringa che identifica sia il contesto sia il nome della label da stampare. Per esempio la dicitura:   
 +<code php> 
 +{{ trans('auth.failed') }} 
 +</code> 
 +stamperà il valore dell'etichetta ''failed'' all'interno del file ''auth.php''  
 +L'helper può ricevere anche un ulteriore parametro, una mappa di valori da sostituire nella stringa corrente. Supponendo di avere una label del tipo:   
 +<code php> 
 +'required' => 'The :attribute field is required.' 
 +</code> 
 +sarà  possibile scrivere   
 +<code php> 
 +{{ trans('validation.required', [ 'attribute' => 'username ]) }} 
 +</code> 
 +per avere un messaggio personalizzato in base all'attributo corrente.   
 + 
 +=== Pluralizzazione ===   
 +Un ulteriore feature del componente dedicato alle localizzazioni è la pluralizzazione. Tutte le lingue del mondo presentano regole differenti per creare le **versioni plurali dei sostantivi** e per questo non è sempre possibile automatizzare questo processo. Con un particolare sintassi e un metodo ad hoc, è possibile configurare Laravel impostando diverse frasi in base al numero di elementi. Facciamo un esempio:   
 +<code php> 
 +'utenti' => '{0}Sei l'unico utente|{1,3} Siete in quattro gatti|{4,10} Un bel gruppetto|{11, Inf}Troppo casino' 
 + 
 +trans_choice('frontend.utenti', 10) 
 +</code> 
 +   
 +In questo caso, grazie a ''trans_choice'' e al secondo parametro passato, possiamo ottenere un messaggio personalizzato anche in base alla quantità definita; nel nostro caso il numero 10 permette di ottenere la stringa "Un bel gruppetto"                                                     
 + 
 + 
 +==== Laravel e la validazione dei dati ====                                  
 + 
 +=== Validazione e controller ===   
 +Il pattern MVC di Laravel prevede che la validazione dei dati deve essere eseguita all'interno dei controller in quanto componenti dedicati all'integrazione Web dell'applicazione. Per questo scopo, il framework, fornisce un trait, ''ValidatesRequest'', che implementa un metodo, ''validate'', che appunto facilita la validazione di request HTTP.   
 +Il metodo accetta la richiesta HTTP corrente e una serie di regole, in automatico si occupa di rispondere all'utente con una notifica di errore in caso di dati non conformi. All'interno della nostra applicazione demo abbiamo già  utilizzato questa modalità  di validazione all'interno dei nostri controller. Riporto un esempio per comodità  preso dall'AuthorController:   
 +<code php> 
 +public function store(Request $request) { 
 +    $this->validate($request,
 +        'firstname' => 'required|min:3|max:40', 
 +        'lastname' => 'required|min:3|max:40' 
 +    ]); 
 +    [....] 
 +
 +</code> 
 +   
 +In questo caso le regole sono semplici: ''firstname'' e ''lastname'' sono campi obbligatori di lunghezza compresa tra 3 e 40 caratteri. L'oggetto ''$request'' invece viene reso disponibile da Laravel stesso, tramite **dependency injection**, grazie alla definizione del tipo dell'oggetto nella firma del metodo.   
 +La definizione delle regole però non è l'unica attività  da svolgere; è necessario anche notificare all'utente gli errori che il sistema ha identificato. In caso di errori il framework redirige l'utente sulla pagina precedente (nella quale solitamente è presente un form) creando una **variabile flash** contenente gli errori. Le variabili flash sono speciali variabili che vengono salvate nella sessione HTTP ma che hanno durata limitata ad una solo richiesta e vengono utilizzate esclusivamente per un passaggio di dati tra due pagine.   
 +Per questo motivo, all'interno della nostra view, sarà  disponibile una variabile di nome ''$errors'' che sarà  un'istanza di ''Illuminate\Support\MessageBag''. Ecco come vengono mostrati gli errori di uno specifico campo all'interno di ''author/form.blade.php'':   
 +<code php> 
 +<div class="form-group {{ $errors->has('firstname') ? 'has-error' : '' }}"> 
 +    {!! Form::label('firstname', 'Firstname') !!} 
 +    {!! Form::text('firstname', null, ['class' => 'form-control']) !!} 
 +    @foreach($errors->get('firstname') as $error) 
 +        <span class="help-block">{{ $error }}</span> 
 +    @endforeach 
 +</div> 
 +</code> 
 +   
 + 
 +=== Altre modalità  di validazione ===   
 +La modalità  implementata in Biblios è la più semplice e quella offerta di default da Laravel. Nel caso ci fosse bisogno di un maggior controllo sul flusso di approvazione dei dati è comunque possibile configurare la validazione ad un livello più basso.   
 +La prima modalità  è quella di creare manualmente il validatore senza utilizzare il trait ''ValidatesRequest''. In questo modo le righe da scriver sono di più ma è possibile personalizzare il comportamento nel caso di errori:   
 +<code php> 
 +public function store(Request $request) 
 +
 +    $validator = Validator::make($request->all(),
 +        'firstname' => 'required|min:3|max:40', 
 +        'lastname' => 'required|min:3|max:40' 
 +    ]); 
 + 
 +    if ($validator->fails()) { 
 +        return redirect('author/form'
 +                    ->withErrors($validator) 
 +                    ->withInput(); 
 +    } 
 + 
 +    [....] 
 +
 +</code> 
 +   
 +Tale modalità, che permette una maggiore riusabilità del codice, prevede la creazione di un oggetto Request personalizzato. Laravel infatti permette di iniettare all'interno dei metodi dei controller non solo oggetti standard ma anche personalizzati. E' infatti possibile definire tipologie di richieste custom, con delle proprie caratteristiche e riutilizzarle anche in controller differenti.   
 +Eventuali oggetti Request vengono salvati all'interno della cartella ''app/Http/Request'' ed è presente un comando per la creazione automatica di questi file:    
 +<code php> 
 +php artisan make:request 
 +</code> 
 +   
 +Le request create in questo modo presentano alcuni metodi già  definiti ma senza comportamento specifico. Il metodo da implementare è ''rules'' che deve restituire l'elenco delle regole attive per la richiesta. Una volta definite sarà  possibile utilizzare l'oggetto sfruttando la dependency injection nei controller. La validazione scatterà a priori e il codice del controller verrà  eseguito solamente se la validazione ha dato esito positivo.   
 + 
 +=== Messaggi di errore ===   
 +I messaggi mostrati sono etichette di testo localizzate gestite dal motore di localizzazione di Laravel. In automatico Laravel utilizza i messaggi contenuti nel file ''resources/lang/validation.php'' me è possibile personalizzarli tramite due approcci:    
 + 1.modificando i file contenenti le risorse per creare messaggi comuni a tutta l'applicazione;  
 + 1.passando un nuovo oggetto al metodo statico ''Validator::make'' per creare messaggi dedicati alla singola istanza del validatore.    
 +Dato che Laravel presenta solamente messaggi tradotti in inglese, può essere comodo aggiungere tra le dipendenze questo [[https://github.com/caouecs/Laravel-lang|progetto]] che presenta messaggi di validazione già  localizzati in 52 diversi idiomi.   
 + 
 +=== Regole di validazione standard e custom ===   
 +Laravel presenta un set abbastanza ricco di regole out-of-the-box, è però possibile implementare logiche e regole personalizzate di validazione all'interno del metodo boot di un service provider in modo che il framework le carichi all'avvio.   
 +Un'eventuale regola (''canDrive'') che controlla che l'età sia maggiore del minimo legale per avere la patente potrebbe essere:   
 +<code php> 
 +[...] 
 +public function boot() 
 +
 +    Validator::extend('canDrive', function($attribute, $value, $parameters, $validator) { 
 +        return $value >= 18; 
 +    }); 
 +
 +[...] 
 +</code> 
 +   
 +Per utilizzala si dovrà richiamarla come se fosse una normale regola Laravel.     
 ===== Laravel: gli ultimi aggiornamenti ===== ===== Laravel: gli ultimi aggiornamenti =====
 +    
 +==== Autenticazione e validazione dei dati con Laravel 5.2 ====                                 
 +I precedenti capitoli della guida avevano come riferimento Laravel 5.1, ma tutte le funzionalità descritte sono ancora valide anche per i rilasci successivi. Questa versione è una **LTS** (''Long Time Support''), ovvero una release destinata ad un supporto della durata di 3 anni; considerando che venne completata nel giugno del 2015 potrebbe essere una buona idea quella di sceglierla per i propri progetti, indipendentemente dalla disponibilità di versioni più recenti (le minor 5.2 e 5.3).  
 +
 +=== Nuovo motore di autenticazione ===  
 +La più grossa novità introdotta in Laravel 5.2 riguarda l'**autenticazione**. E' infatti possibile avere più strategie di autenticazione, mentre nella 5.1 era possibile averne solo una. Per esempio si possono definire diverse utenze (admin e user) e sfruttare due logiche di autenticazione differenti.  
 +Oltre a questa modifica strutturale è stato introdotto un nuovo comando:  
 +<code php>
 +php artisan make:auth
 +</code>
 +   
 +che permette di generare in automatico una serie di view da sfruttare con i controller standard dedicati all'autenticazione. Il comando genera view per tutti gli aspetti del flow di autenticazione e registrazione (login, register, password reset) e configura le rotte, è quindi molto utile per avere una struttura di pagine semplice e funzionale da personalizzare.  
 +
 +=== Binding di modelli implicito ===  
 +La seconda modifica riguarda le rotte ed in particolare il **model binding**, ovvero la possibilità  di avere a disposizione nel controller il modello associato alla rotta senza occuparci personalmente del suo recupero dal database.  Rispetto alla versione precedente, dove era necessario usare il metodo ''Route::model'', Laravel 5.2 è  più "intelligente" e permette  di configurare un binding sfruttando solamente il type hinting di PHP:  
 +<code php>
 +Route::get('/user/{user}', function (User $user) {
 +        return $user;
 +});
 +</code>
 +  
 +
 +=== Gruppi di Middleware e Rate Limiting ===  
 +Sempre riguardo alla gestione delle rotte, un'altra novità  riguarda la possibilità  di raggruppare i middleware in gruppi richiamabili all'interno delle rotte in modo da permettere una maggiore configurabilità. All'interno del file ''App\Http\Kernel.php'' è  possibile definire i gruppi come vettori di classi. Dal punto di vista delle rotte la modifica è trasparente: i gruppi possono essere richiamati come un normale middleware.  
 +Inoltre è stato introdotto un nuovo middleware, ''throttle'', utile nel caso si utilizzino API, per limitare il numero di chiamate dallo stesso IP.  
 +
 +=== Validazione ===  
 +Il motore di validazione di Laravel acquisisce due novità. La prima riguarda la validazione degli array ricevuti tramite parametri della request. Grazie all'utilizzo della **wildcard *** è possibile verificare che tutti gli elementi in una lista rispettino la regola definita. Per esempio con la regola  
 +<code php>
 +'utente.*.nome' => 'required'
 +</code>
 +  
 +ci assicuriamo che ogni oggetto utente abbia il nome valorizzato.   
 +La seconda novità  riguarda la disponibilità  di una nuova meta regola: ''bail'' che permette di ottimizzare il processo di validazione interrompendo le regole successive appena una regola fallisce. Per esempio con la regola  
 +<code php>
 +'user_id' => 'bail|integer|unique:users'
 +</code>
 +  
 +comunichiamo a Laravel di evitare di eseguire la query per controllare l'univocità dell'id se questo non è un intero; senza l'utilizzo di ''bail'' essa verrebbe comunque eseguita.                                                     
 +
 +
 +==== Full text search in Laravel 5.3 ====                                 
 +Dopo aver aggiornato il framework dalla versione 5.1 alla 5.2, è giunto il momento di passare alla 5.3 che è l'ultima versione del framework, pubblicata il 23 agosto del 2016.   
 +
 +=== Laravel Scout ===  
 +La principale novità è rappresentata da **Scout**, un pacchetto addizionale rilasciato dalla community di Laravel in grado di integrare i model del framework  con un motore di **full text search**. 
 +Al momento l'unico driver disponibile è quello per integrarsi con Algolia, un servizio remoto per le ricerche full text, ma grazie alla facile integrazione è possibile implementare il proprio engine o utilizzare quelli disponibili sui repository di [[http://www.html.it/guide/composer-e-packagist-la-guida/|composer]] (ne sono presenti alcuni che utilizzano Elastic  Search, Lucene o Solr).  
 +
 +=== Laravel Passport ===  
 +Un secondo pacchetto addizionale ma ufficiale è **Passport**, utile per implementare rapidamente autenticazioni **OAuth 2**; perfetto per quelle applicazioni sviluppate come API che richiedono un motore di autenticazione efficiente, granulare e soprattutto standard.  
 +
 +=== Mailables e Notification ===  
 +Il motore interno delle email è stato in gran parte rivisto grazie all'introduzione dei **Mailables**, oggetti specializzati che rappresentano un modello dati inviabile via mail. La novità permette di spedire mail sfruttando un pattern più object-oriented del precedente e utilizzando i code standard di Laravel.  
 +Oltre alle modifiche al gestore interno di email, Laravel 5.3 introduce anche un'astrazione dedicata al concetto più ampio di notifiche inviabili non solo via mail, ma anche tramite SMS o messaggi di testo. Per eventuali nuove implementazioni di canali di notifica è stata istituita anche una community dedicata  ad eventuali moduli addizionali: il [[http://laravel-notification-channels.com/|Laravel Notification Channel]].  
 +
 +=== Laravel Echo ===  
 +**Echo** è un pacchetto Javascript perfettamente integrato con i servizi backend in Laravel, utile per implementare un sistema ad eventi client/server.  E' installabile tramite NPM come un normale pacchetto Javascript e offre un'API consistente per inviare ed ascoltare eventi al server sfruttando  la tecnologia **WebSocket**.  
 +
 +=== Variabile $loop ===  
 +Utilizzando la nuova versione del framework avremo a disposizione una nuova variabile ''$loop'' all'interno dei cicli nelle viste blade. Essa contiene informazioni sullo stato dell'iterazione per rendere più semplici alcune operazioni ordinarie. Per esempio possiamo accedere all'indice corrente (tramite la  proprietà ''index'') o allo stato dello step corrente (tramite le proprietà ''first'' e ''last'').  
 +
 +=== Nuova struttura delle cartelle ===  
 +La modifica più apparente è sicuramente quella che ha impattato le cartelle del framework. Le rotte sono state spostate al di fuori della cartella ''app/'' in modo  da essere compatibili agli standard PSR in merito ai namespace e alla struttura di cartelle in un progetto PHP. Inoltre sono state rimosse alcune cartelle di default  vuote che ora verranno create solamente se richieste (per esempio ''Jobs'', ''Events'' o ''Policies'').  
 +
 +=== Modifiche minori ===  
 +Oltre alle modifiche particolarmente impattanti descritte sopra sono state introdotte una serie di migliorie di minor rilevanza:   
 +  * nuovo helper ''cache'' per accedere o modificare i valori in cache senza utilizzare la facade Cache; 
 +  * la possibilità di modificare il paginatore di default di Laravel; 
 +  * modifica ai metodi di Query Builder che ora restituiscono una Collection invece di un semplice array PHP.                                                      
 +
 +
 +==== Slot, notifications, automatic facades e Dusk in Laravel 5.4 ====                                 
 +
 +=== Componenti e Slot in Blade in Laravel 5.4 ===  
 +Una delle  modifiche più rilevanti tra quelle introdotte in Laravel 5.4 riguarda il layer HTML del framework. A partire da questa release sarà  infatti possibile utilizzare i **componenti**, un nuovo costrutto dedicato alla **prototipizzazione dell'HTML**. Grazie ai componenti sarà  possibile creare dei blocchi di markup flessibili grazie al concetto di **slot**.  
 +All'interno di un ''partial blade'' si potrà definire, più o meno come facciamo con i layout, zone all'interno delle quali dovrà  essere inserito il contenuto del componente, grazie alla variabile ''$slot''. Analizziamo il seguente esempio:  
 +<code php>
 +//panel.blade.php
 +<div class="panel">
 +    <div class="panel-body">
 +        {{ $slot }}
 +    </div>
 +</div>
 + 
 +//page.blade.php
 +@component('panel')
 +    I am the panel body
 +@endcomponent
 +</code>
 +  
 +La logica di default prevede un unico slot disponibile all'interno dei componenti, ma se avessimo bisogno di più slot possiamo utilizzare i ''named slot'':  
 +<code php>
 +<div class="panel">
 +    <div class="panel-heading">
 +        {{ $heading }}
 +    </div>
 +    <div class="panel-body">
 +        {{ $slot }}
 +    </div>
 +</div>
 + 
 +@component('panel')
 +    @slot('heading')
 +        I am the heading
 +    @endslot
 +    I am the panel body
 +@endcomponent
 +</code>
 +  
 +
 +=== Notifications ===  
 +Le **Notifications** sono un nuova tipologia di oggetto presente in Laravel e rappresentano appunto una notifica che può essere inviata agli utenti sfruttando diversi canali, per esempio email o SMS.  
 +Grazie a questa classe possiamo astrarre il messaggio dalla tipologia di trasporto utilizzato per rendere quindi il tutto più flessibile e configurabile. Le notifiche si integrano perfettamente con le code Laravel e possono essere create tramite un nuovo e dedicato comando di artisan da linea di comando.  
 +
 +=== Automatic Facades ===  
 +La terza grande novità  non riguarda nuove funzionalità, ma un nuova modalità  di organizzazione del codice e di gestione delle dipendenze. Grazie alle **automatic facades** sarà  possibile trasformare qualsiasi classe, senza ulteriori configurazione, in una classe Facade che può essere utilizzata facilmente in altre classi come una normale Facade.  
 +
 +=== Abbreviazioni nelle collection ===  
 +Grazie ai magic method di PHP è stato possibile aggiungere una nuova funzionalità  alle Collection. Nel caso dovesse servire invocare un metodo per ogni elemento della collection, potremo farlo senza creare una closure da passare al metodo ''each''. Un esempio è senza ombra di dubbio più esplicativo:  
 +<code php>
 + //al posto di:
 +$users->each(function($user) {
 +    $user->enable();
 +});
 +
 +//potremo scrivere
 +$users->each->enable();
 +</code>
 +  
 +
 +=== Aggiornamenti nel motore di routing ===  
 +Laravel 5.4 ha parzialmente modificato la configurazione delle rotte sfruttando una sintassi più fluente sia nella creazione che nell'impostazione di middleware e prefissi:  
 +<code php>
 +Route::name('login')->get('login'), function() { .... });
 +Route::name('logout')->middleware('auth')->get('logout'), function() { .... });
 +Route::name('logout')->middleware('auth')->get('logout'), function() { .... });
 +</code>
 +  
 +
 +=== Laravel Dusk ===  
 +Oltre alle modifiche al core di Laravel è stato introdotto un nuovo modulo chiamato **Dusk**, si tratta di un tool per test ''end-to-end'' che sfrutta un browser con un supporto completo ad applicazioni JavaScript. Con Dusk potremo creare test invocando azioni sulla pagina web come un click su un pulsante o la digitazione di qualche parametro in un form.  
 +Dusk estende componenti che funzionano solamente con pagine statiche, per poter funzionare anche con applicazioni che fanno uso di Javascript. Per installarlo è necessario scaricare una nuova dipendenza di [[http://www.html.it/guide/composer-e-packagist-la-guida/|composer]] ''laravel/dusk'' e, una volta scritto il test, invocare il nuovo comando   
 +<code php>
 +php artisan dusk
 +</code>
 +  
 +
 +=== Laravel Mix ===  
 +Questo aggiornamento introduce anche un cambiamento nella modalità  di compilazione e generazione delle risorse statiche client-side (js, css, ...). **Mix** non utilizza più Gulp, ma include direttametne **Webpack**, un moderno e innovativo motore di compilazione di assets.  
 +
 +=== Anticipazioni su Laravel 5.5 ===  
 +Nonostante sia passato poco dal rilascio della versione 5.4, la comunità  di sviluppatori Laravel è già  in fermento per la prossima versione, la 5.5, soprattutto per una novità già  comunicata ufficialmente dagli autori del framework: la prossima versione infatti richiederà [[http://www.html.it/articoli/php-7-le-principali-novita/|PHP 7.0]] e non funzionerà  con versioni precedenti di PHP..                                                     
 +
 +
  
 +===== Info =====
  
 +^ Corso ^^^
 +|[[http://www.html.it/guide/laravel-la-guida/]]|||
 +^ Autore ^^^
 +|[[http://www.html.it/autore/albertobot/|Alberto Bottarini]]|||
 +^Tavola Release^^^
 +^Lezione^Ultimo \\ Aggiornamento^Allegato^
 +|01. Installazione di Laravel|2 ottobre 2015| |
 +|02. Laravel, il pattern di base: Facade|9 ottobre 2015| |
 +|03. Laravel, struttura di un progetto e configurazioni generali|13 novembre 2015| |
 +|04. Gestire il routing con Laravel|23 ottobre 2015| |
 +|05. I controller e la gestione delle richieste in Laravel|30 ottobre 2015|{{:php:laravel:biblios-3.0.zip|biblios-3.0}}|
 +|06. Definizione delle views e template blade con Laravel|27 novembre 2015|{{:php:laravel:06-view.zip|06-view}}|
 +|07. Eloquent: l'ORM di Laravel|30 dicembre 2015| |
 +|08. Eloquent, le relazioni|8 gennaio 2016| |
 +|09. Eloquent, relazioni uno a molti, molti a molti e polimorfiche|22 gennaio 2016| |
 +|10. Eloquent e Migration in Laravel|19 febbraio 2016| |
 +|11. Eloquent e Seeder in Laravel|11 marzo 2016| |
 +|12. Database, modelli, Factory e seed|8 aprile 2016| |
 +|13. Controller e interfacce per le operazioni CRUD|29 aprile 2016|{{:php:laravel:biblios-5.0.zip|biblios-5.0}}|
 +|14. I middleware in un'applicazione basata su Laravel|13 maggio 2016| |
 +|15. Service Provider in Laravel|20 maggio 2016|{{:php:laravel:biblios-6.0.zip|biblios-6.0}}|
 +|16. Service Container in Laravel|10 giugno 2016| |
 +|17. Gestione Utenti in Laravel|27 maggio 2016| |
 +|18. Login e registrazione utenti|1 luglio 2016| |
 +|19. Pagina privata, amministratori e anagrafica|29 luglio 2016| |
 +|20. Localizzazione e pluralizzazione|2 settembre 2016| |
 +|21. Laravel e la validazione dei dati|23 settembre 2016|{{:php:laravel:biblios-7.0.zip|biblios-7.0}}|
 +|22. Autenticazione e validazione dei dati con Laravel 5.2|4 novembre 2016| |
 +|23. Full text search in Laravel 5.3|26 novembre 2016| |
 +|24. Slot, notifications, automatic facades e Dusk in Laravel 5.4|20 febbraio 2017| |
  
-<spoiler> 
-http://www.html.it/guide/laravel-la-guida/ 
-</spoiler> 
  
  
php/laravel.1493584383.txt.gz · Ultima modifica: 2017/04/30 20:33 da apressato
Torna su
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0