Categoria:

Da Laravel a Laratweet: guida all’implementazione di applicazioni MVC

13/08/2014 00:00 Pubblicato da
Share on FacebookTweet about this on TwitterGoogle+Share on Reddit

Laravel

Nascono come funghi e si diffondono a macchia d’olio, è la storia dei framework, è la storia di Laravel. Qualche anno fa Laravel sembrava l’ennesimo frawamework PHP nato in un ambiente ostile e aggressivo accompagnato, come d’altronde è successo per molti altri framework, da un futuro incerto.

  Github   Download

Indice

  1. Un po’ di storia
  2. Che cosa è Laravel?
  3. Laratweet
    1. Il progetto: Laratweet
      1. Cosa andremo a realizzare?
      2. Tecnologie
    2. Installazione e configurazione
      1. Installazione di Laravel tramite Composer
      2. Installazione della piattaforma di sviluppo LAMP
      3. Creazione e configurazione di un progetto Laravel
    3. Laratweet: la home page e il layout
      1. index.blade.php – la home page
      2. base.blade.php – il layout
      3. head, header, footer e before_body_close
      4. cover.css
      5. routes.php
    4. Laratweet: i form di login e registrazione
    5. Laratweet: il database
      1. Installazione di php-sqlite
      2. Permessi per il database
      3. Configurare SQLite in Laravel
      4. Creazione della migrazione: Tweet
      5. Creazione della migrazione: Following
      6. Creazione della migrazione: User
      7. Creazione della migrazione: Reply
      8. Definizione del model: Tweet
      9. Definizione del model: Following
      10. Definizione del model: User
    6. Laratweet: i controller
      1. Lo UserController
      2. Il TweetController
    7. Laratweet: pagine di errore
    8. Laratweet: il profilo utente
    9. Laratweet: la lista degli utenti
    10. Laratweet: la timeline
  4. Conclusioni
  5. Altro
    1. Legenda dei colori
    2. Legenda della sintassi e dello stile
    3. Link utili

1) Un po’ di storia

Le nuove release di PHP andavano in contrasto con le idee degli sviluppatori più conservatori, che non volevano assorbire tendenze che, probabilmente, avrebbero portato a rivoluzioni, forse notevoli, nel mondo PHP. Infatti i namespaces e le funzioni anonime (closures) seminavano terrore e odio fra gli amanti della staticità (inteso non in senso informatico). Gli stessi concetti di classe e di interfaccia già avevano provocato le sue vittime. I dilettanti sembravano più disorientati che mai. C’era chi gridava fermamente che era meglio continuare a lavorare con PHP4, altri invece affermavano che PHP era morto da tempo e ancora chi, conoscendo esclusivamente solo un po’ di Java o di C#, sosteneva l’immaturità di PHP e dei suoi derivati.
Intanto quelli del PHP Group sfornavano periodicamente nuove versioni al fine di portare avanti, con un occhio rivolto a non invalidare la loro filosofia, l’evoluzione di un linguaggio che ha segnato la storia nella società dell’informazione e cercare di guadagnare la simpatia e il rispetto di coloro che appartenevano ad altri mondi, spesso sondati in profondità e definiti più sicuri, mondi che probabilmente molti hanno già esplorato (come il sottoscritto lo fece a suo tempo), ovvero i mondi dei linguaggi OOP (un esempio a caso? Java).

Mentre gli strumenti messi a disposizione dal PHP Group fornivano sempre più potenza e flessibilità, le comunità di sviluppatori open source ideavano, concretizzavano o plasmavano sofisticate librerie o raffinati framework, come è successo per Laravel.

Laravel nasce da un’idea di Taylor Otwell nel 2011, due anni dopo il rilascio della versione 5.3 di PHP, in un ambiente in cui i framework CodeIgniter, Zend, Symfony, Kohana e Lithium avevano l’attenzione di molti programmatori. Fra questi framework si distingueva CodeIgniter, apprezzato per la sua semplicità e intuibilità nell’uso, nonché per la sua documentazione facilmente consultabile. Dopo un’ascesa vertiginosa, iniziarono i periodi bui anche per CodeIgniter. Pare che EllisLab, l’azienda che tiene le redini di CodeIgniter (forse ancora per poco), era intenzionata a continuare a garantire la retrocompatibilità con versioni di PHP precedenti alla 5.3. Alcuni sviluppatori non digerirono proprio il termine “retrocompatibilità”, che diventò la goccia che fecce traboccare il vaso. Nacque così la piccola Guerra dei Due Framework, meglio nota come CodeIgniter vs. Laravel. Come in ogni guerra cibernetica, degna di essere tale, sviluppatori (e non) infliggevano colpi al nemico con articoli, commenti, tweet e chi più ne ha più ne metta. I cyber bulli, naturalmente presenti in entrambe le fazioni, usavano spesso il latinorum menzionando delle frasi del tipo «Ipseeeee dixiiiiiit!» (mi raccomando, voce tonante) oppure si avvalevano semplicemente del diritto di non rispondere.

Questa guerra, anche se, secondo alcuni inutile (giustamente), portò al crollo del pericolosissimo CodeIgniter e alla costituzione di una solida base per creare ciò, che secondo alcuni (erroneamente), è il successore di CodeIgniter, ossia Laravel.
Come è successo frequentemente e come continua a succedere, per iniettare un nuovo prodotto sul mercato e per avere un rapido successo si ha bisogno, a grandi linee, di due ingredienti:

  1. la capacità di offrire un prodotto dotato delle caratteristiche che la concorrenza non è stata in grado di ideare, oppure semplicemente rimodellare qualcosa di preesistente dandole apparentemente una nuova forma, in modo tale da convincere l’utente finale dell’unicità e della qualità del prodotto.
  2. individuare un capro espiatorio, di pericolosità medio-bassa e applicare la distruzione di culto dei suoi prodotti (es. destalinizzazione di Nikita Khruščёv, il contesto è diverso ma il metodo è sempre valido).

Laravel si inserì sul mercato con delle features degne di essere definite novità anche per il mondo CodeIgniter e sopratutto, grazie alla “guerra” precedentemente citata, acquisì la sua visibilità in pochissimo tempo. Siti molto autorevoli hanno definito Laravel come il migliore framework PHP sulla piazza. In un articolo di Mashable ad esempio, Laravel viene presentato come un ottimo framework per la realizzazione di applicazioni web di tipo agile. Bisogna tener conto che gli articoli di Mashable, e non solo, a volte sono troppo commerciali ed il loro contenuto talvolta è superficiale ed influenzato dai propri sponsor (di certo questa non credo che sia una novità). Tuttavia, queste tipologie di siti sono in grado di influenzare la massa (lettori, blogger, sviluppatori etc.), creando nuove tendenze o rafforzandole.

Quindi, Laravel non è meglio di CodeIgniter?
Ni. Un framework consente di facilitare l’implementazione di applicativi software. Alcuni di essi sono molto completi, pertanto molte funzionalità, invece di essere implementate da zero, possono essere aggiunte attraverso l’inclusione dei moduli preconfezionati. Bisogna tener presente che i framework più maturi possono avere problemi di performance, ciò è dovuto spesso proprio al numero di features che essi offrono e quindi alla complessità della loro architettura (nonché alla loro configurazione), infatti non a caso (si vedano anche i test più recenti oppure quelli del Giurassico) i framework più poveri di funzionalità presentano performance più alte (banale). Tuttavia un framework leggero comporterebbe dei tempi di realizzazione dell’applicazione molto lunghi, poiché molto probabilmente mancherebbe di molte funzionalità preconfezionate.

2) Che cosa è Laravel?

Dotato di una sintassi elegante ed espressiva, Laravel è un framework destinato alla creazione di applicazioni web. L’obiettivo fondamentale è quello di facilitare la realizzazione di soluzioni laboriose offrendo potenti tool che risolvono i problemi più ricorrenti, come l’autenticazione, il caching, il routing e la sessione. Per offrire strumenti all’avanguardia (come lo IoC container. Probabilmente avrai sentito parlare anche in Spring.), Laravel trae ispirazione dai più noti framework come Ruby on Rails, ASP.NET MVC, Sinatra [e CodeIgniter]. Con Laravel si possono costruire applicazioni web secondo il ben noto pattern Model-View-Controller (MVC). Per Model si intende il modello dei dati, le entità e le relazioni tra esse. La View, ossia la vista, rappresenta l’interfaccia utente, che nel caso di un’applicazione web è un documento HTML. Infine, il Controller contiene la logica applicativa del programma. Sarà questo ultimo ad elaborare le richieste del client, interagendo eventualmente con il Model per produrre la View.

3) Laratweet

Dunque, dopo essermi concesso questo excursus sul background di questo framework, passiamo alla pratica: il progetto Laratweet.

3.1) Il progetto: Laratweet

3.1.1) Cosa andremo a realizzare?

In questa guida indicherò, passo per passo, come implementare un’applicazione web MVC denominata Laratweet utilizzando Laravel. L’applicazione dovrà permettere agli utenti di registrarsi ed autenticarsi al sistema. Ogni utente autenticato potrà seguire altri utenti e pubblicare tweets (ovvero frammenti di testo ognuno avente un massimo di 140 caratteri). Di ogni utente seguito si potranno ottenere gli aggiornamenti tramite la timeline dell’utente autenticato. Un utente può decidere di smettere di seguire un altro utente.
Di seguito viene proposto un prototipo del progetto Laratweet:
Laratweet - pages

3.1.2) Tecnologie

Per la veste grafica verrà utilizzato il front-end framework Bootstrap. Per poter utilizzare i plugins di Bootstrap sarà necessario includere jQuery. Per ciò che riguarda il back-end avremo Laravel 4.2 e SQLite. L’applicazione è stata realizzata e testata su Ubuntu 14.04.

3.2) Installazione e configurazione

3.2.1) Installazione di Laravel tramite Composer

Per utilizzare Laravel è consigliabile installare Composer (per metodi alternativi fare riferimento al sito ufficiale di Laravel). Innanzitutto bisogna scaricare l’eseguibile di Composer scrivendo da terminale:

Subito dopo lo rendiamo accessibile globalmente spostandolo nella directory bin.

Per verificare il corretto funzionamento, basta scrivere:

3.2.2) Installazione della piattaforma di sviluppo LAMP

Probabilmente si ha già la piattaforma di sviluppo software LAMP installata sulla propria macchina, in caso contrario installare tasksel.

Eseguire tasksel e selezionare LAMP server e successivamente premere su OK per procedere con l’installazione e la configurazione di LAMP.

3.2.3) Creazione e configurazione di un progetto Laravel

Siamo pronti a creare un nuovo progetto in Laravel. Spostiamoci nella directory /var/www/html, utilizzando Composer creeremo un nuovo progetto attraverso l’esecuzione del seguente comando:

Verrà creata una cartella denominata laratweet (nella directory in cui ci troviamo) contenente tutti i file della nostra applicazione. Adesso spostiamoci nella root del nostro progetto e diamo i permessi alla directory storage

Per accelerare il processo di sviluppo della nostra applicazione, faremo uso dei Generators. Dopo l’installazione potremmo creare views, models e controllers (e non solo), direttamente da linea di comando. Per poter utilizzare i Generators, bisogna aggiungere nel file laratweet/composer.json la dipendenza del package way/generators

Successivamente da linea di comando eseguire

Inoltre, bisogna aggiungere un nuovo service provider nell’array providers del file di configurazione app/config/app.php:

Per accertarsi della corretta configurazione e per conoscere tutti i comandi, eseguire da linea di comando:

Apriamo il nostro IDE preferito (io mi sono abituato con PHPStorm) e selezioniamo come root del progetto la directory laratweet. Attiviamo il debug nel file di configurazione /app/config/app.php impostando debug su true

3.3) Laratweet: la home page e il layout

Se appriamo il browser e andiamo al seguente link http://localhost/laratweet/public dovrebbe comparire la pagina di benvenuto di Laravel ("You have arrived.").

3.3.1) index.blade.php – la home page

Il prossimo passo sarà la creazione di una home page in cui vengono spiegati gli obiettivi dell’applicazione e consente all’utenza di registrarsi. Dalla home page si potrà accedere anche alla pagina di registrazione al sistema. Da terminale, spostiamoci nella root del progetto (laratweet), e andiamo a creare la pagina index.blade.php

Se avessimo voluto creare il file in una sottodirectory di views avremmo dovuto specificare le subdirectory separate da punti in questo modo:

Se la sottodirectory non fosse esistita, sarebbe stata creata in automatico.
Il nuovo file generato avrà l’estensione .blade.php. L’engine di templating di Laravel farà il parsing dei file con tale estensione per individuare eventuali comandi blade ed eseguirli.

Nel nuovo file laratweet/app/views/index.blade.php andiamo a incollare il seguente codice

La view in questione eredita le proprietà di un’altra view, la base.blade.php presente in views/layouts. Il simbolo punto (.) dell’argomento layouts.base sta a indicare uno slash (/). Da come si può notare non bisogna specificare l’estensione del file (.blade.php o .php). Tale view genitore, da come vedremo dopo, fornisce lo scheletro della nostra pagina.
Con le keyword di apertura e chiusura @section('body') e @stop stiamo specificando che abbiamo intenzione di riscrivere una sezione appartenente alla view genitore. In questo caso il nome della sezione è body.
Le due parentesi graffe di apertura e quelle di chiusura ({{ ... }}) permettono di stampare ciò che si trova al loro interno senza effettuare l’escaping. Esse corrispondono ad

In Laravel le view subiscono un preprocessamento che consiste nella conversione delle istruzioni di tipo Blade in istruzioni PHP. Quando l’utente richiede per la prima volta una determinata risorsa, Laravel decodifica la view e le view da cui questa ne dipende, per poi salvarle, assegnandole come nome l’impronta del nome della view, in app/storage/views (è uno dei tanti motivi per cui storage necessita dei permessi di scrittura).
La funzione asset(string path_relativo) genera la URL a partire dal percorso relativo fornito in input. Useremo la funzione asset() per generare URI di risorse (come un’immagine, un file .css o un file .js), mentre per referenziare un controller useremo la funzione url(nome_controller).

3.3.2) base.blade.php – il layout

Da linea di comando, andiamo a creare il layout del sito che verrà ereditato dalle altre pagine che andremo a definire.

Apriamo il file appena creato (app/views/layouts/base.blade.php) e sostituiamo il suo contenuto con

Da come si può notare, il titolo della pagina viene generato dinamicamente ({{ $title }}). Il valore della variabile title verrà passato direttamente dal controller responsabile per questa view. Se si dimentica di trasferire $title alla view, Laravel genererà un’eccezione. Ciò significa, che ogni pagina che estenderà base, dovrà ricevere anche il valore di $title dal suo handler.
Subito dopo incontriamo il keyword @include, il quale indica, in questo caso, l’inclusione dell’head. Il file head.blade.php contiene tutte le informazioni che dovrebbe possedere la mia pagina HTML nella sezione head. Nell’head vi saranno i meta tag e i riferimenti ai file .css.
Successivamente abbiamo un altro @include, questa volta dell’header della pagina, che consiste nel menu principale affiancato dal nome del progetto.
@yield('body'), invece, sta a indicare l’esistenza di una sezione denominata body non dotata di contenuto. Saranno le view che estenderanno la base a poter definire la sezione body. Si poteva definire anche un contenuto predefinito per il body racchiudendolo tra @section('body') e @show, in questo modo se la view figlio non ridefiniva tale sezione veniva mostrato il contenuto della view genitore.
Con la parola chiave @show stiamo indicando che la sezione e ridefinibile da parte di una view figlia.

3.3.3) head, header, footer e before_body_close

Adesso, andiamo a creare i file views/includes/head.blade.php, views/includes/header.blade.php, views/includes/footer.blade.php e /includes/before_body_close.blade.php sempre tramite php artisan

e andiamo a definire il loro contenuto nel seguente modo:

Nella riga 3 si può osservare che l’URI del brand del sito, in questo caso Laratweet, cambia in base al valore restituito dal metodo Auth::check(). Infatti se il valore ritornato è true, l’utente è loggato al sistema quindi il link generato sarà quello per la pagina che mostrerà tutti gli utenti registrati al sistema. In alternativa, il link sarà quello della home page.
Blade offre una sintassi per le strutture di controllo molto simile a quella già presente in PHP. La loro funzione è quella di rendere il codice più chiaro, infatti invece di utilizzare la sintassi alternativa per le strutture di controllo di PHP

si può utilizzare quella di Blade

Per ulteriori informazioni sulle strutture di controllo si faccia riferimento alla documentazione ufficiale.
A partire dalla riga 7 del file header.blade.php viene definito il menu dell’applicazione web. Se l’utente è autenticato verrà generato il menu utente. Per indicare all’utente la pagina in cui si trova, si effettua un controllo sull’URI della richiesta (Request::is('/') che accetta una route) e si aggiunge la classe .active se vi è una corrispondenza. Alla riga 15 stiamo utilizzando la classe Auth per recuperare informazioni sull’utente loggato, in questo caso stiamo prendendo il nome utente per la generazione del link del profilo utente (Auth::user()->username).

Si potrebbe semplificare il codice creando due layout: uno destinato per la home page, la pagina di login e registrazione e l’altro invece per gli utenti loggati (ma non lo vogliamo fare).
Definiamo il footer ed il codice da includere subito dopo il footer:

3.3.4) cover.css

Successivamente andiamo a definire meglio l’interfaccia grafica creando il file laratweet/public/css/cover.css

3.3.5) routes.php

Per poter visualizzare la nuova home page bisogna modificare il file routes.php situato in laratweet/app e definire i controller che processeranno le richieste degli utenti. Tale file contiene tutti i percorsi dell’applicazione web. Le richieste degli utenti vengono passate al corretto handler del controller in base alle specifiche del file routes.php.
Quindi sostituiamo il suo contenuto con

Qui stiamo dicendo di dirigere tutte le richieste http://miosito.com/user/* allo UserController e quelle di tipo http://miosito.com/tweet/* al TweetController. L’ultima istruzione invece crea la view index.blade.php passandole come parametro title che potrà essere acceduto dalla view come $title.
Naturalmente potevamo definire le informazioni da restituire direttamente nel file routes.php, tuttavia questo non è MVC.
Qui di seguito vengono mostrati dei metodi per definire i percorsi e alcune delle possibili risposte:

Andando al seguente link http://localhost/laratweet/public/ accederemmo alla home page del sito.

Laravel-Laratweet-Home

3.4) Laratweet: i form di login e registrazione

Le pagine di login e registrazione estenderanno sempre base.blade.php e ridefiniranno la sezione body.
Da linea di comando andiamo a creare le nuove view:

Pagina di login

Nei file appena creati andiamo a sostituire il loro contenuto:

In Laravel, per definire un form, si possono utilizzare due metodi: il primo consiste nella stesura del codice HTML, mentre il secondo metodo ci consente di utilizzare la classe Form che genererà in automatico i tag HTML.
Per inserire il tag di apertura di un form bisogna chiamare il metodo statico open della classe Form e passarli un array che contiene i nomi degli attributi e i rispettivi valori del tag che verrà generato. Il metodo di apertura del form deve essere seguito dal metodo di chiusura, ossia Form::close(). Il primo argomento dei metodi Form::text() e Form::password() corrisponderà al valore dell’attributo name in HTML. Mentre Form::submit() accetta come primo parametro il valore dell’attributo value (insomma, il nome del pulsante per intenderci). Gli array delle componenti del form (Form::text(), Form::password(), Form::submit()) contengono gli attributi HTML e i rispettivi valori.
In corrispondenza della riga 12, il secondo parametro (quello successivo a ‘username’) rappresenta il valore di default per quel tag, ovvero corrisponde all’attributo value del tag input, che andremmo a utilizzare intensamente nella pagina di registrazione.
Ad ogni utente, anche quello non loggato, viene associata una chiave di sessione. Dato che il controller responsabile dell’autenticazione, in caso di login fallito o altre tipologie di errore, salverà un messaggio in sessione per poi effettuare un redirecting alla pagina di login, è necessario controllare ed eventualmente mostrare all’utente tale messaggio. Ciò è possibile farlo sfruttando i metodi Session::has('miaVar') e Session::get('miaVar').
L’immagine subito dopo è la pagina di login appena creata.

Laravel-Laratweet-Login

Pagina di registrazione

Il valore dell’errorMessage potrebbe essere recuperato dalla sessione, nel caso in cui esista, oppure dal controller tramite il passaggio di variabili, oppure potrebbe succedere che non abbiamo nessun messaggio di errore. Nella pagina di registrazione bisogna tener traccia dei valori precedentemente inseriti dall’utente per evitare che egli debba inserirli nuovamente ad ogni registrazione fallita. Quindi si fa uso del metodo Input::old('nome-associato-al-tag') che recupera il valore precedentemente inserito dall’utente. Tale comportamento è possibile, come lo vedremo dopo, solo se il controller che rimanda l’utente nuovamente alla pagina di registrazione fa uso del metodo withInput() quando crea o effettua la redirezione alla view.
La pagina di registrazione:

Laravel-Laratweet-Register

3.5) Laratweet: il database

Per memorizzare utenti e tweet abbiamo bisogno di uno schema e di un DBMS. Faremo uso di SQLite, un SQL database engine. Laravel è già pronto per lavorare con SQLite, bisognerà solo cambiare qualche impostazione e i dati verranno salvati nel file app/database/production.sqlite. Lo schema di un database è una delle parti più importanti di un’applicazione in quanto ne dipende tutta la sovrastruttura, quindi prendersi tutto il tempo necessario per la progettazione del database.

La seguente immagine rappresenta il Modello Entità-Relazione (ERD – Entity–Relationship Diagrams), ovvero la la struttura del nostro database. Da come si può osservare l’architettura è molto semplice, avremo una tabella denominata Users che conterrà le informazioni dell’utente, come username, password, bio, etc. Ogni utente può seguire zero o più utenti (Followings), indi un utente può essere seguito da zero a n utenti. Un utente registrato al sistema può pubblicare uno o più tweets. Un tweet può essere pubblicato come risposta ad un altro tweet (Replies).

Laratweet ERD v.1.1

Legenda dei simboli
N – nullable
U – unique
Primary Key (PK) – Primary Key (PK)
Foreign Key (FK) – Foreign Key (FK)

Gli attributi created_at e updated_at, come vedremo dopo, verranno creati automaticamente da Laravel con una semplice istruzione. L’attributo remember_token servirà a Laravel per mantenere la sessione dell’utente registrato. La tabella Followings avrà un constraint di tipo unique che coinvolgerà le due foreign keys follows_user_id e user_id, ciò eviterà di avere coppie di FK uguali. Lo stesso discorso vale per le due chiavi esterne di Replies.

3.5.1) Installazione di php-sqlite

Utilizzeremmo come DBMS, SQLite. Prima però, bisogna installare il suo driver:

3.5.2) Permessi per il database

Laravel utilizzerà il file production.sqlite presente nella directory app/database/. Perché questo file possa essere modificato è necessario dare i permessi di scrittura sia al file che alla directory che lo contiene (database).

3.5.3) Configurare SQLite in Laravel

Ci rimane di configurare il file database.php della directory app/config. Cambiamo il valore del nome della connessione predefinita per indicare che abbiamo intenzione di lavorare con SQLite:

3.5.4) Creazione della migrazione: Tweet

La definizione dello schema del database in Laravel avviene tramite le migration. Una classe di migrazione definisce la struttura di una tabella e deve estendere la classe Migration. Per descrivere la struttura di una tabella è necessario definire il metodo up() della classe di migrazione. Oltre al metodo up() va specificato anche il metodo down() che provvede al dropping della tabella.
Da linea di comando andiamo a creare la migrazione della tabella Tweets:

Andiamo in app/database/migrations e sostituiamo il suo contenut con

Le due variabili, $tableName e $tableNameFK non hanno un significato particolare per Laravel. Facciamo uso della classe Schema e del metodo statico create() per definire le proprietà della tabella. Il metodo create() accetta come primo parametro il nome della tabella e come secondo parametro una funzione anonima, questa ultima contiene le specifiche delle colonne della tabella. In particolare, la prima colonna contiene l’id del record che è di tipo intero incrementale ed implicitamente anche una primary key, la seconda e la terza colonna definiscono le proprietà di user_id, in particolare tale attributo dovrà essere un intero unsigned e foreign key che punta all’attributo id della tabella Users. La colonna text è di tipo varchar ed ha una lunghezza massima di 140 caratteri. Per quanto riguarda lo status, invece del varchar(10) viene usato l’enum. Il metodo timestamps() genera i due attributi created_at e updated_at di tipo timestamp ed infine softDeletes() genera l’attributo deleted_at (timestamp).
Il metodo down() verrà chiamato per distruggere la tabella (se questa è stata creata precedentemente).

3.5.5) Creazione della migrazione: Following

La tabella Following dovrà contenere le informazioni su chi segue chi.

Definiamo le proprietà della tabella

Nel metodo up() sia user_id che follows_user_id sono degli interi senza segno e chiavi esterne. Inoltre ogni coppia di user_id e follows_user_id è unique.

3.5.6) Creazione della migrazione: User

La tabella User conterrà tutte le informazioni sull’utenza di Laratweet. Sempre da linea di comando andiamo a creare una nuova migrazione:

Definiamo le proprietà della tabella:

In Laravel tutti i campi sono NOT NULL. Per definire colonne nullable basta utilizzare il metodo nullable(). L’attributo remember_token servirà a Laravel per mantenere la sessione dell’utente. La password deve avere 60 caratteri poiché faremo uso di una funzione hash per generare l’impronta.

3.5.7) Creazione della migrazione: Reply

La tabella Replies conterrà una coppia di ID di tweet. Il primo tweet ID (tweet_id) rappresenterà la risposta al secondo tweet ID (is_replay_to_id).
Questa parte dell’applicazione non verrà implementata completamente.

Definiamo le proprietà della tabella

3.5.8) Definizione del Model: Tweet

Il model è quell’entità che fornisce i dati al Controller che a sua volta gli trasferisce alla View. Andiamo a definire il model denominato Tweet.

Si otterrà così una nuova classe nella directory app/models che dovrà contenere il seguente codice:

I model in Laravel estendono la classe Eloquent e permettono di interagire con una tabella. Eloquent ORM, inclusa in Laravel, fornisce una semplice implementazione di ActiveRecord per lavorare con i database. In questa guida farò un uso molto limitato delle funzionalità di Eloquent ORM. Utilizzerò invece la classe DB che ci fornisce tutti gli strumenti per creare query alla vecchia maniera ed eseguirle in modo sicuro (inoltre le interrogazioni SQL sono portabili).
Il model Tweet fa uso della classe SoftDeletingTrait che ci consente di avere delle cancellazioni soft dei record della tabella Tweets, in altre parole invece di cancellare definitivamente i record, verrà aggiunta una data di eliminazione (deleted_at) e il record sarà considerato ufficialmente cancellato. La variabile protetta $table, opzionale, consente di specificare il nome della tabella a cui il model fa riferimento. Come comportamento predefinito, Laravel aggiunge una s finale al nome del modello ottenendo così il nome della tabella a cui fare riferimento. L’array $fillable invece contiene tutti i nomi delle colonne che possono essere utilizzate per il mass assignment (vulnerabilità mass assignment) ossia le colonne che possono essere modificate dall’utente (l’array che invece dovrà contenere tutti i nomi delle colonne non mass-assignable è $guarded che è sempre di tipo protected).

3.5.9) Definizione del Model: Following

Il prossimo modello è il Following che è associato alla tabella Followings:

Il modello è definito nel seguente modo:

Qui stiamo indicando di non voler i due campi updated_at e created_at per la tabella Following. Nel caso in cui volessimo mantenere anche uno storico sui momenti in cui un utente ha iniziato a seguire per la prima volta un altro utente e quando ha smesso per poi riprendere, potremmo sfruttare i campi created_at, per capire quando ha seguito per la prima volta un utente, deteled_at (quindi soft deletes), per tenere traccia di quando ha smesso di seguire, oppure updated_at per determinare il momento in cui ha ripreso a seguire il medesimo utente.

3.5.10) Definizione del Model: User

Il model più imponente è lo User. Laravel arriva già con il model User configurato, quindi non bisogna generare la classe tramite php artisan ma bensì apportare qualche modifica su di essa.

Possiamo definire metodi nel model per poi richiamarli dal controller tramite chiamate statiche. I parametri delle query vengono indicati con il simbolo del punto interrogativo (?) mentre l’array degli argomenti, che vanno a sostituire i punti interrogativi, va passato come secondo parametro (valido per i metodi select(), delete(), update() e insert() della classe DB). La parametrizzazione delle query è necessaria per renderle immuni ad attacchi di tipo SQL Injection.

Qui stiamo recuperando le informazioni dell’utente passato come parametro ($username). Dato che il valore passato come parametro corrisponde al nome utente, bisogna ricavare il suo Users.id attraverso una query annidata.
Restituisce la lista dei profili di ogni utente iscritto al sistema. Prima di restituire i dati, il DBMS dovrà ordinarli in base allo username in modo ascendente. Naturalmente bisognerà aggiungere anche un LIMIT XY per evitare di recuperare tutti gli utenti registrati al sistema e di implementare un sistema di paginazione.
Con getAllTweetsByUserId(...) recuperiamo tutti i tweet dello Users.id passato come parametro e il suo username. Successivamente, i risultati vengono ordinati in modo decrescente in base all’id del tweet.

Questa query effettua l’inserimento di un nuovo record nella tabella Followings. Visto che il metodo riceve come parametri due username (quello dell’utente intenzionato a seguire e quello dell’utente da seguire) è necessario ricavare lo Users.id di entrambi. Pertanto viene effettuata una query che agisce sulla stessa tabella (Users) restituendo gli id dei due utenti passati come parametro.
Elimina la riga che ha come user_id, l’id dell’username $me passato come parametro e come follows_user_id, l’id dell’utente $other passato come parametro.

Conta il numero di righe in cui compare la combinazione di ($usernameA, $usernameB) nella tabella Followings. Dato che non abbiamo gli userId bisogna effettuare delle sottoquery per recuperarli.
Recupera tutti i tweet degli utenti che fanno parte della lista amici dello username passato come parametro. Con la sottoquery più interna si recupera lo userId del nome utente passato come parametro ($myUsername). Tale userId viene utilizzato per recuperare la lista degli utenti che egli segue (query annidata intermedia). Infine, la query più esterna recupera tutti i tweet degli utenti che fanno parte della lista delle persone che l’utente $myUsername segue.

Questo metodo non viene utilizzato, tuttavia potrebbe ritornare utile per i successivi aggiornamenti dell’applicazione. L’obiettivo è quello di recuperare le informazioni principali di ogni follower in base allo $username passato come parametro. Partendo dalla query più interna: viene recuperato lo userId dell’utente passato come parametro, il quale verrà utilizzato per recuperare la lista degli utenti che seguono tale userId. Una volta ottenuta la lista dei followers, vengono recuperate le informazioni di ogni follower con la query più esterna.

La migrazione

Siamo pronti per procedere con la migration, ovvero la creazione delle tabelle all’interno del DB.

Il comando migrate genererà le tabelle. Con il parametro force non verranno richieste conferme per procedere.

3.6) Laratweet: i controller

I controller accolgono le richieste dal client e generano una view eventualmente sfruttando i dati forniti dai model. In Laravel, i controller vanno definiti in app/controllers.

3.6.1) Lo UserController

Da linea di comando generiamo la classe del controller:

e definiamo lo UserController nel seguente modo:

Si presti attenzione ai nomi dei metodi (essi sono RESTful): il get, post o any iniziali indicano il metodo di richiesta del metodo (ossia GET, POST, GET o POST). Dopo il metodo di richiesta abbiamo il nome del metodo della classe che consente anche di identificare la risorsa. Tra parentesi invece troviamo i parametri che vengono passati tramite URL. In altri termini, immaginiamo di avere la risorsa profilo di un utente. Per poter avere tale risorsa l’utente dovrebbe andare su http://www.example.com/profile/{nome_utente} (quindi richiesta di tipo GET). Laratweet, in base alla configurazione del file routes.php, chiamerà il metodo public function getProfile($nome_utente). Lo stesso comportamento vale per le richieste di tipo POST.

Adesso andremmo ad analizzare i metodi più significativi della classe UserController.

Qui stiamo definendo due condizioni: la prima, csrf, indica l’applicazione del controllo csrf per prevenire attacchi di tipo CSFR. Il secondo parametro invece indica i metodi di richiesta a cui applicare tale controllo. La riga successiva al filtro csrf, ovvero quella in cui abbiamo $this->beforeFilter('auth', ... ), impone l’autenticazione agli utenti visitatori per tutte le pagine ad eccezione di quelle presenti nel sottoarray except (sarebbe illogico andare nella pagina di registrazione e venire rispediti sulla pagina di login).
Adesso è necessario specificare la pagina di login alla quale l’utente ospite verrà redirezionato. Pertanto andiamo a definire meglio il filtro auth situato nel file di configurazione app/filters.php.

Le richieste di tipo AJAX otterranno il codice di stato 401 (Unauthorized) invece quelle non AJAX riceveranno come risposta un redirect (HTTP 302 Found) alla pagina di login.

Il primo metodo della classe UserController è il getIndex().

Andando alla pagina http://localhost/laratweet/public/user si verrà rediretti alla pagina del profilo utente (HTTP 302 Found).

All’indirizzo http://localhost/laratweet/public/user/login il server restituirà la view login, alla quale passerà anche una variabile (title) e il rispettivo valore. Il metodo make restituisce direttamente la pagina(HTTP 200 OK). Laravel andrà a prendere il file login.blade.php o login.php dalla cartella app/views.

Al fine di validare l’input inserito dall’utente e in caso di errori, di restituirli un messaggio con il relativo messaggio, sfruttiamo il metodo Validator::make() che come primo argomento riceve tutti i campi del form con i rispettivi valori ricevuti dal client e come secondo argomento le regole di validazione (ulteriori informazioni). Le regole di validazione vanno definite all’interno di un array(chiave => valore), dove la chiave rappresenta il nome del tag mentre il valore indica le regole che vanno applicate su quel campo. Se la validazione non va a buon fine (ossia if ($validator->fails())), aggiungiamo all’array $exceptArr la stringa password e controlliamo se il campo username ha fornito il messaggio di errore, in caso affermativo lo aggiungiamo al medesimo array. Tale array servirà al metodo withInput() il quale fornirà alla view i valori inseriti precedentemente dall’utente ad eccezione di quelli presenti nell’array $exceptArr. Quindi se i dati in input non sono validi, l’utente viene rediretto al controller user/login con un messaggio di errore(errorMessage) che conterrà il primo messaggio di errore che ha incontrato il validator ($validator->messages()->first())e con i dati di input dell’utente ad eccezione della password ed eventualmente dell’username.
Alla riga 18 viene fatto un tentativo di autenticazione attraverso il metodo attempt di Auth. Il primo parametro accetta un array con i dati per l’autenticazione, mentre il secondo parametro, opzionale, accetta un booleano che indica se si vuole mantenere la sessione in modo permanente, fino a quando l’utente non effettuerà il logout manualmente. Da notare che il secondo argomento è un true. Ciò implica la necessità di aggiungere il campo remember_token nella tabella Users (quindi va aggiunto nel file di migrazione responsabile della creazione della tabella User). Inoltre, l’utente potrebbe non apprezzare il fatto di rimanere loggato per un tempo indeterminato. Sarebbe opportuno implementare un “Remember me” nel form del login in modo da poter consentire all’utenza di scegliere.

Una soluzione all’implementazione della funzionalità remember me potrebbe essere la seguente.
Nel file contenente il form, vado a definire una checkbox:

oppure se volessimo utilizzare la classe Form:

true serve per generare l’attributo checked.
Nel metodo del controller invece avrò qualcosa di simile:

Ritorniamo al metodo postLogin(), che stavamo analizzando prima. Nel caso in cui l’username o la password non sono corretti, l’utente verrà rediretto sempre sulla pagina di login, però questa volta con un messaggio di errore in cui gli viene indicato di controllare meglio i dati di input.
L’ultima istruzione (Redirect::intended(profilo_utente)) redirige l’utente alla pagina alla quale ha tentato di accedere precedentemente (il login è stato effettuato con il metodo Auth::attempt(...)).

Il metodo responsabile della registrazione dell’utente, postRegister(), effettua la validazione dei dati, se questi sono corretti, prosegue con la memorizzazione di un nuovo utente. Voglio ricordare che nel model User abbiamo definito svariati metodi ma non quello che si occupa dello storage dei dati dell’utente, come ad esempio il metodo save(). Il model, come abbiamo visto precedentemente, estende la classe Eloquent che mette a disposizione usa serie di metodi. Fra questi metodi abbiamo anche il metodo save().
Alla riga 20 viene istanziato il model User al quale dopo gli vengono assegnati i valori di input dell’utente e si tenta un salvataggio nel DB, se lo storing dei dati non va a buon fine si redireziona l’utente alla pagina di registrazione con un messaggio di errore e l’input che ha inserito precedentemente (withInput(...)) al fine di evitare che inserisca gli stessi dati, corretti, nuovamente.
Il passo successivo è il tentativo di autenticazione e se questo fallisce si mostra sempre un messaggio di errore. Se invece la procedura di registrazione con successiva autenticazione va a buon fine, l’utente viene redirezionato al suo profilo. Il percorso user/profile farà invocare il metodo getProfile() della classe UserController il quale, come vedremo dopo, farà un ulteriore redirect poiché non troverà il nome dell’utente nell’URL (si osservi il controllo che viene effettuato alla riga 3 del codice sottostante).

Il metodo viene invocato in seguito ad una richiesta di tipo GET e restituisce il profilo dell’utente avente come username quello passato come parametro. Se il nome utente è vuoto, l’utente viene redirezionato sul proprio profilo. Il passo successivo è il recupero dei dati del profilo utente passato in input (User::getProfileByUsername($username);), se il DB restituisce un array vuoto, viene mostrata la pagina 404, risorsa non trovata. Prendiamo l’unico profilo restituito all’indice 0 (qui sicuramente esiste) e verifichiamo se l’utente in questione è seguito dall’utente autenticato al sistema. In caso affermativo settiamo $youAreFollowing a true (servirà successivamente nella view). Dopo, recuperiamo tutti i tweets dell’utente per poi passarli alla view profile assieme al titolo della pagina, al booleano youAreFollowing, al profilo ed infine al nome utente.

Solitamente, un operazione come quella di following di un utente andrebbe fatta tramite chiamate AJAX, ma noi vogliamo usare il metodo back di Redirect. Questo metodo permette di ritornare alla pagina dalla quale è partita la richiesta. In questo caso io mi troverò sulla pagina del profilo utente, premendo sul pulsante Follow (POST), verrà salvato un record di follow nel database e verrò rediretto sul profilo dell’utente che ho iniziato a seguire.

Basta un Auth::logout() e il token di identificazione dell’utente viene invalidato.

3.6.2) Il TweetController

Andiamo a generare il controller:

Sostituiamo il contenuto del file:

Il controller in questione espone solo un metodo, quello del posting di un tweet, che risponde alle richieste di tipo post.

3.7) Laratweet: pagine di errore

Per definire le pagine di errore (403 – accesso negato, 404 – pagina non trovata, 500 – errore interno di server), bisogna recarsi nella directory app/start/ e aggiungere al file global.php il seguente codice

Per ogni pagina di errore bisogna definire la rispettiva view. Quindi, sempre tramite la solita procedura:

creaiamo le nostre view nella directory errors di views.
In seguito andiamo a definire il loro contenuto:

3.8) Laratweet: il profilo utente

Andiamo a definire la view responsabile della visualizzazione del profilo dell’utente.
Generiamo la view:

Ridefiniamo il suo contenuto nel seguente modo:

Come commenti, nella riga 5, abbiamo una chiamata al metodo check di Auth che ritorna true se l’utente si è autenticato. Questo è un altro modo per proteggere le view da utenti di tipo guest (attenzione, se si decide di abilitare tale controllo, togliere anche i commenti della riga 78).
Visto che il profilo che si sta visitando non necessariamente è il profilo dell’utente autenticato, il controller fornisce alla view la variabile $profile che contiene tutte le informazioni sul nome utente passato come parametro al metodo getProfile() del controller UserController. Con l’istruzione {{ !empty($profile->img_uri) ? $profile->img_uri:asset('img/no_photo_128.png') }} si controlla se l’utente ha l’URI dell’immagine del profilo, in caso negativo viene stampata quella dell’immagine di default.
Successivamente viene stampato il nome utente ({{{ '@'.$profile->username }}}). Invece delle due parentesi graffe di apertura e quelle di chiusura, ne stiamo utilizzando ben tre. Quando si ha a che fare con dati che hanno avuto origine dal client, prima di inviarli all’utente bisogna fare il loro escaping, un malintenzionato infatti, potrebbe sfruttare tale vulnerabilità per fare attacchi di tipo XSS.
Aggiungendo il controllo @if ($profile->username===Auth::user()->username) verifichiamo se l’utente della URL corrisponde a quello in sessione, se tale condizione è vera, l’utente logato potrà pubblicare un tweet nel suo profilo.
In seguito, se abbiamo dei tweets in sessione (@if (Session::has('tweets') ? $tweets = Session::get('tweets') : $tweets)), inizializziamo la variabile $tweets assegnandole quello della sessione (naturalmente è sconsigliato scrivere il codice in questo modo). Subito sotto vi è un’istruzione Blade, la @foreach, che utiliziamo per iterare sull’array ed estrarre i dati. Per trasformare il timestamp in “quanto tempo fa” utilizziamo la classe Carbon.
Il profilo utente si presenterà nel seguente modo:

Laravel-Laratweet-Profile

Laravel-Laratweet-Profile-2

Laravel-Laratweet-Profile-3

3.9) Laratweet: la lista degli utenti

L’utente di Laratweet potrà trovare nuove persone da seguire accedendo alla lista utenti.

Qui stiamo iterando sulla lista utenti $users ricevuta dal controller. Per ogni utente generiamo il link del suo profilo e definiamo una bio di default se l’utente in questione non ha ancora una bio.

Laravel-Laratweet-People

3.10) Laratweet: la timeline

L’utente di Laratweet potrà consultare tutti i tweet delle persone che segue tramite la pagina Timeline.

Nella view vengono stampati i tweet forniti dal controller.

Laravel-Laratweet-Timeline

4) Conclusioni

Laravel si dimostra un framework molto valido per la creazione di applicazioni web di tipo agile.
Pregi:

  1. Di facile apprendimento
  2. Permette la stesura di codice leggibile
  3. Facile installazione e configurazione
  4. Una community in forte crescita

Difetti:

  1. L’obiettivo delle classi helper delle view, come Form, è quello di generare elementi html well-written, che rispettano lo standard, e rendere il codice più leggibile. Il primo punto viene soddisfatto pienamente, tuttavia rimane la questione della chiarezza del codice. Infatti l’uso di array come parametro per le funzioni rende la lettura più difficile e per ciò che riguarda la compattezza, da come si può osservare nel codice della pagina login.blade.php, non si hanno dei grossi miglioramenti nell’usare i metodi della classe Form.
  2. Documentazione ufficiale a volte troppo superficiale

5) Altro

5.1) Legenda dei colori

Prestare molta Attenzione! – prestare molta attenzione.

Attenzione! – suggerisce che bisogna prestare particolare attenzione ma non troppa.

Suggerimento – soluzione alternativa oppure informazione che potrebbe essere di una certa utilità.

Codice – segmento di codice, percorso o termine che si vuole semplicemente evidenziare in una particolar maniera.

5.2) Legenda della sintassi e dello stile

[ testo ] – lettura opzionale.
[ testo ] – link.
testo – parola strana o semplicemente si tratta di un neologismo.

  1. La community italiana Laravel
  2. Tabella comparativa Laravel vs CodeIgniter
  3. Arguing on the Internet di Phil Sturgeon
  4. The “Framework” is Dead, Long live the Framework di Phil Sturgeon
  5. History of Laravel PHP framework, Eloquence emerging

  Github   Download

21/07/2017 10:14

Leave a Reply

Your email address will not be published. Required fields are marked *