Home Blog Pagina 12

Trait o Non Trait? Questo è il dilemma…

0

Fino a pochi minuti fa, per rinfrescarmi un po’ le idee, stavo riguardando alcuni video su Laracasts dedicati ai Design Pattern.

Nello specifico, il video in questione riguardava l’Observer Design Pattern, uno dei più semplici da imparare ed al tempo stesso uno dei più famosi.

Ad un certo punto, il buon Jeffrey Way sforna uno dei suoi ottimi consigli (mi chiedo se gli sia mai capitato di darne di sbagliati): per evitare la duplicazione di codice, usare i trait è sicuramente una buona idea.

Devo ammetterlo: non li ho mai usati più di tanto, se non quasi mai. Così mi sono chiesto: perché non approfondire l’argomento?

Qualche ricerca mi ha portato a leggere svariati articoli, alcuni dei quali (come questo) cercano di dare un’idea complessiva, includendo anche i pro ed i contro.

La cosa molto interessante è proprio il dibattito che si è costruito intorno a questo costrutto, dato che ha coinvolto svariate “scuole di pensiero” riguardo l’ereditarietà multipla, best e bad practice, e così via.

Per cui eccomi qui, a scrivere un articolo per fare un po’ il punto della situazione.

Definizioni, innanzitutto

Cos’è un Trait? Chiediamolo direttamente al manuale di PHP:

Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.

ovvero:

I Trait sono un meccanismo per il riuso del codice in linguaggi ad ereditarietà singola, come PHP. L’obiettivo di un Trait è quello di ridurre alcune delle limitazioni dovute a questa tipologia di ereditarietà, permettendo di definire un determinato set di metodi da riusare in più classi che non sono necessariamente nella stessa gerarchia.

In poche parole: i Trait permettono di definire un insieme di metodi in un’entità a parte. Tale entità può essere quindi “condivisa” da altre classi che non necessariamente hanno lo stesso “genitore” o, comunque, sono nella stessa gerarchia.

Approfondiamo il discorso vedendo un veloce esempio per capire meglio di cosa si tratta.

L’Esempio

In un recente articolo, Philip Brown fornisce un ottimo esempio di uso dei trait.

Supponiamo di avere un insieme di entità (che non si trovano nella stessa gerarchia) che condividono una funzionalità di condivisione. Un po’ come avviene su Facebook: ho testi, foto, video e voglio poterli condividere, tramite un’apposita funzione share().

Un’idea è quella di implementare separatamente i vari metodi:

class Post {

public function share($item)
{
return ‘share this item’;
}

}

class Comment {

public function share($item)
{
return ‘share this item’;
}

}

Tuttavia, la funzione di condivisione è praticamente uguale per ogni singolo item… che senso ha duplicarla N volte tante quante sono le entità in gioco?

Ecco che entrano così in scena i trait:

trait Sharable {

public function share($item)
{
return ‘share this item’;
}

}

Esattamente come per una classe astratta, un trait non può essere istanziato, ma viene “incluso” tramite use nella classe che vuole fare uso dei suoi metodi.

Le due classi appena viste, quindi, diventeranno:

class Post {

use Sharable;

}

class Comment {

use Sharable;

}

Provando ad usare le due classi, adesso, il risultato sarà esattamente lo stesso. Abbiamo quindi scritto lo stesso metodo una volta sola, minimizzando la duplicazione di codice.

Sicuramente una bella comodità.

C’è anche da sottolineare un’altra cosa molto importante:

  • un trait è diverso da un’interfaccia, perché l’interfaccia definisce un “contratto” a cui una classe deve aderire. Il trait invece dona una determinata funzionalità ad una classe;
  • un trait è diverso da una classe astratta, perché esula dai meccanismi dell’ereditarietà. Non c’è bisogno di estendere una classe, basta includere il trait tramite use;

Detta così sembra quasi una manna dal cielo: la risoluzione di tutti i problemi e la promessa di una felicità eterna. Tuttavia…

… non è così per tutti!

No, non lo è.

Alcuni programmatori, infatti, per svariati motivi, hanno deciso di non sostenere l’uso di Trait nei propri progetti.

Uno di questi motivi, sicuramente anche uno dei più validi, è che il Trait rischia facilmente di essere usato male, e di diventare un’altra grande “zozzata”.

Non è un mistero che nella storia di PHP ci sia tanto codice scritto male, che nel corso del tempo ha contribuito in buona parte a “sminuire” il valore stesso del linguaggio.

Inoltre, basta pochissimo ad usare male i trait e creare classi pesanti che infrangono il Single Responsibility Principle. Quindi, massima attenzione.

Quindi? Li uso o non li uso?

Un buon punto di partenza, secondo me, è vedere qualche esempio di “buon uso” dei trait in un’applicazione vera.

Uno dei package consigliati per “esplorare” questo concetto è sicuramente Cashier, di Laravel. Nello specifico, puoi vedere un trait in azione in questo specifico file.

Tu, invece, li usi oppure no?

Sono curioso di sapere cosa ne pensi: se vuoi, fammelo sapere sul forum!

Laravel e Digital Ocean… come installarlo?

0

Nelle ultime ore sto giocando molto con Digital Ocean. Lo trovo un servizio fantastico e ci sto quasi facendo un pensierino per Laravel-Italia.

Ho dato uno sguardo alla guida presente sul sito, dedicata al come installare il nostro framework preferito… e ho deciso di farne una veloce traduzione.

Nello specifico, in questo articolo vedremo come installare Laravel su un webserver Nginx, su Ubuntu 14.04.

Installiamo tutto il necessario

La prima cosa da fare, per poter lavorare con Laravel, è installare tutto lo stack di software necessario. Possiamo farlo senza problemi tramite i default repository di Ubuntu.

Eseguiamo l’update dell’indice, in modo tale da avere una lista aggiornata di tutti i package disponibili. Dopodiché procediamo con l’installazione del software necessario.

sudo apt-get update
sudo apt-get install nginx php5-fpm php5-cli php5-mcrypt git

Con queste due semplici istruzioni, in pochi minuti, ci troveremo Nginx, insieme al PHP e tutti i tool necessari ad eseguire un’applicazione creata con Laravel.

Nota: installeremo anche Git, che verrà usato da Composer per scaricare le varie dipendenze.

Modifica del file php.ini

Abbiamo tutti i componenti necessari: passiamo a sistemare i file di configurazione. Cominciamo con PHP. Roba di pochi secondi.

Apriamo il file di configurazione principale di PHP-fpm, usato da Nginx.

sudo nano /etc/php5/fpm/php.ini

Avremo bisogno di modificare un solo, singolo valore di configurazione. Cerca, precisamente, il parametro cgi.fix_pathinfo. Impostalo su 0, come segue:

cgi.fix_pathinfo=0

A cosa serve? In poche parole spiega a PHP di non provare ad eseguire uno script nel caso il file in questione non venga trovato. È una cosa molto importante a livello di sicurezza: permette di evitare alcuni tipi di attacchi che consentono ad un malintenzionato di eseguire codice tramite una richiesta costruita ad-hoc.

Sistemato il file, salvalo e chiudilo.

Rimane solo da abilitare, tramite esplicita richiesta, l’estensione MCrypt, dalla quale Laravel dipende. Basta molto poco:

sudo php5enmod mcrypt

Ci siamo: riavvia il servizio php5-fpm con il seguente comando:

sudo service php5-fpm restart

Bene: PHP è configurato. Passiamo ad Nginx.

Configurare Nginx e la Web Root

Adesso tocca configurare il web server. L’operazione si svolgerà seguendo due step specifici e distinti.

Il primo consisterà nella configurazione della document root e della struttura delle directory da usare per i file di Laravel. I nostri file verranno infatti messi in una cartella /var/www/laravel.

Al momento attuale, l’unica cartella ad essere già presente è /var. Iniziamo quindi con il creare la struttura desiderata.

sudo mkdir -p /var/www/laravel

Nota: il flag -p serve a creare tutta la struttura in una volta sola.

Adesso che abbiamo un luogo “fisico” per i nostri file, possiamo passare alla modifica del file di configurazione di Nginx. Nello specifico, modificheremo la parte relativa ai server block.

Apriamo il file di configurazione dei siti disponibili:

sudo nano /etc/nginx/sites-available/default

Subito dopo l’installazione, il file sarà pieno di sezioni commentate. Tuttavia, la struttura basilare dovrebbe essere questa:

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /usr/share/nginx/html;
index index.html index.htm;

server_name localhost;

location / {
try_files $uri $uri/ =404;
}
}

La prima cosa da fare è cambiare la document root da usare. Laravel è stato installato in var/www/laravel. Agiamo di conseguenza.

Ricordiamo, comunque, che la directory esposta dal server non sarà quella principale, ma la subdirectory /public.

Quindi, modifichiamo così il file.

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /var/www/laravel/public;
index index.php index.html index.htm;

server_name localhost;

location / {
try_files $uri $uri/ =404;
}
}

Occorre, adesso, impostare la direttiva server_name che indica l’attuale nome di dominio del server. Se non ne hai uno, usa l’indirizzo IP che ti è stato assegnato.

Dobbiamo inoltre modificare come Nginx gestisce le richieste. L’elemento da modificare è la direttiva try_files.

L’idea di fondo è semplice: ogni richiesta deve essere gestita come se si stesse cercando un file. Se il file non viene trovato, allora si passa a gestire la richiesta come se fosse un parametro query per index.php.

La procedura può essere rappresentata così:

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /var/www/laravel/public;
index index.php index.html index.htm;

server_name server_domain_or_IP;

location / {
try_files $uri $uri/ /index.php?$query_string;
}
}

Infine, dobbiamo procedere con la creazione di un blocco ulteriore, che gestisca l’esecuzione di ogni singolo file PHP. Cercherà di eseguire il file, oppure gestirà la richiesta come parametro query per il file index.php.

Impostiamo le varie direttive fastcgi_* in modo tale che i percorsi vengano riconosciuti a dovere.

Infine, imposteremo il parametro SCRIPT_FILENAME in modo tale da permettere a PHP di rintracciare i file in modo corretto.

A lavoro ultimato, il file di configurazione dovrebbe apparirti così:

server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root /var/www/laravel/public;
index index.php index.html index.htm;

server_name server_domain_or_IP;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ .php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

Salva e chiudi. Ci siamo. Rimane solo da riavviare Nginx:

sudo service nginx restart

… e anche questa è fatta!

Installiamo Composer e Laravel

Siamo agli sgoccioli: tutto quello che manca, infatti, è installare Laravel e Composer.

Chiaramente, ci occuperemo prima di installare il gestore di dipendenze, per poi passare al framework come tocco finale.

Muoviamoci in una directory dove abbiamo i permessi di scrittura (la home, ad esempio) e scarichiamo lo script di installazione dal sito di Composer.

cd ~
curl -sS https://getcomposer.org/installer | php

Verrà creato un file composer.phar nella directory, che può essere tranquillamente eseguito da linea di comando.

Tuttavia, è anche vero che sarebbe ottimale poterlo eseguire da qualsiasi directory… perché non muoverlo in una cartella accessibile globalmente?

Provvediamo, tramite il comando mv.

sudo mv composer.phar /usr/local/bin/composer

Anche Composer è pronto. Installiamo Laravel, finalmente!

Ricorda che dobbiamo mettere i file di cui abbiamo bisogno nella cartella /var/www/laravel directory.

Di conseguenza, il comando da usare sarà…

sudo composer create-project laravel/laravel /var/www/laravel

Al momento in cui scriviamo la versione di Laravel è la 4.*.

Nota di Francesco: Anche con Laravel 5 non ci dovrebbero essere troppe difficoltà. In caso di sostanziali cambiamenti scriverò un altro articolo.

A questo punto, i file saranno stati scaricati nella cartella che abbiamo specificato. Tuttavia, sono ancora “posseduti” dall’account root. Bisogna quindi modificare alcuni permessi e ownership, in modo tale da poter servire i vari contenuti senza problemi.

sudo chown -R www-data /var/www/laravel
sudo chmod -R 775 /var/www/laravel/app/storage

Dopo aver eseguito questi ultimi due comandi, l’installazione sarà completa al 100%. Come verifica, accedi alla pagina di benvenuto visitando:

http://server_domain_or_IP

Buon divertimento la tua Droplet 😉

Serie di Video Tutorial su Laravel 4, In Italiano

0

Iniziamo il nuovo anno con una chicca piuttosto interessante.

Qualche giorno fa, infatti, sono stato contattato da Alessandro di WebYourMind, un ragazzo appassionato di sviluppo (e di Laravel) per una segnalazione che farà piacere a molti di voi.

Su YouTube è infatti disponibile, già da qualche mese, una serie di video tutorial dedicati al nostro framework preferito. Il progetto è ancora in fase di sviluppo, e ci sono svariate lezioni da aggiungere a quelle già presenti.

Non temete però: i realizzatori ci hanno promesso che verrà finita.

Nel momento in cui scrivo, la serie copre solo le basi del framework. Sono presenti, in tutto, quattro capitoli sui dieci promessi.

È vero, tra poco sta per essere rilasciato Laravel 5, ma sono sicuro può essere comunque molto interessante mettere le mani in pasta con una guida del genere.

Buono studio a tutti!

ActivityLog, un package interamente dedicato al logging!

0

Spesso, nella nostra applicazione, abbiamo bisogno di tracciare e notificare le attività degli utenti: ad esempio chi ha effettuato il login, chi ha inserito un determinato contenuto, chi ha modificato qualcosa. Sarebbe comodo memorizzare queste azioni registrando anche “quando” sono avvenute, insieme ad altre informazioni.

Per venire incontro a questa esigenza ti presento ActivityLog, un package che ti permette di registrare con facilità i log per le diverse azioni degli utenti nel database e visualizzarle ad esempio nella dashboard dell’amministratore.

Installazione

Installazione, registrazione del service provider e aliasing

Per installare ActivityLog assicurati di aggiungere all’interno del composer.json la riga regulus/activity-log tra i require così:

“require”: {
“regulus/activity-log”: “0.3.0”
},

Esegui quindi da riga di comando l’istruzione composer update.

Composer installerà il package ActivityLog. Non ti rimane che registrare il service provider nel file app/config/app.php, nell’ array providers:

‘RegulusActivityLogActivityLogServiceProvider’,

Aggiungi questa riga nell’array aliases:

‘Activity’ => ‘RegulusActivityLogActivity’,

Migration e Seed del Database

Per eseguire la migration (una singola tabella DB), esegui il comando artisan:

php artisan migrate –package=regulus/activity-log

Pubblicazione del File di Configurazione

Se vuoi personalizzare la configurazione di ActivityLog, è necessario pubblicare il file di configurazione. Esegui dalla riga di comando:

php artisan config:publish regulus/activity-log

Ora potrai modificare il file di configurazione in app/config/packages/regulus/activity-log.

Uso Base

Registrare le Azioni degli Utenti

Activity::log([
‘contentId’ => $user->id,
‘contentType’ => ‘User’,
‘action’ => ‘Create’,
‘description’ => ‘Created a User’,
‘details’ => ‘Username: ‘.$user->username,
‘updated’ => $id ? true : false,
]);

Grazie al codice appena visto verranno registrate le azioni dell’utente correntemente loggato. L’indirizzo IP verrà salvato in automatico e il flag “developer” sarà impostato se l’utente corrente avrà una variabile di sessione “developer” settata su true.

Una piccola ottimizzazione che ti propongo è quella di scatenare un evento che esegue Activity::log() ogni volta che lo desideri, magari parametrizzandolo opportunamente.

Prendiamo ad esempio l’azione di login. Ogni volta che l’utente viene autenticato puoi lanciare l’evento in questo modo:

$logevent = Event::fire(‘logactivity.regaction’,array(‘utente’,’login’,’accesso utente’));

E registrare il listener così:

Event::listen(‘logactivity.regaction’, function($contentType, $action, $description)
{
Activity::log(array(
‘contentId’ => Auth::user()->id,
‘contentType’ => $contentType,
‘action’ => $action,
‘description’ => $description,
‘details’ => Auth::user()->nome.’ ‘.Auth::user()->cognome.’ – ‘.Auth::user()->email
));
});

Semplicemente quindi, ti basterà inserire una riga di codice per ogni azione da registrare.

Ogni soluzione alternativa è ben accetta. Segnalacela.

Per oggi è tutto. Alla prossima!

LaracastsFlash, per informare al meglio gli utenti della nostra applicazione!

0

Ti ritrovi spesso nella posizione di dover informare gli utenti, in risposta a qualche azione o evento particolare?

Oggi vedremo insieme un nuovo strumento a nostra disposizione, il package laracastsflash.

Installazione

Per prima cosa aggiungi il package al file composer.json, ed esegui composer update:

“require”: {
“laracasts/flash”: “~1.0”
}

Successivamente, dopo aver eseguito da terminale il comando composer update, aggiungiamo il service provider all’interno dell’array providers del file app.php:

‘providers’ => [
‘LaracastsFlashFlashServiceProvider’
];

Per convenienza, inoltre, aggiungi la facades associata al package così:

‘aliases’ => [
‘Flash’ => ‘LaracastsFlashFlash’
];

Uso

Supponiamo di aver creato un controller per gestire le registrazioni degli utenti al nostro sito.

All’interno del metodo store, prima di eseguire il redirect, aggiungiamo:

class RegisterController {
public function store()
{
Flash::message(‘Welcome Aboard!’);

return Redirect::home();
}
}

Oltre al metodo Flash::message hai a disposizione altri metodi. Vediamoli:

Flash::info(‘Message’)
Flash::success(‘Message’)
Flash::error(‘Message’)
Flash::warning(‘Message’)

Ed un metodo speciale (lo vedrai in azione a fine articolo):

Flash::overlay(‘Modal Message’, ‘Modal Title’)

Ogni metodo visto, memorizza in sessione, le seguenti chiavi:

  • flash_notification.message – Il messaggio che vogliamo mostrare all’utente
  • flash_notification.level – Una stringa rappresentante il tipo di avviso (utile per applicare una classe css al codice HTML)

Nota: Servendosi di Twitter Bottstrap ‘flash_notification.level’ assumerà i seguenti valori: alert-info, alert-success, alert-danger e alert-warning, che rappresentano le classi di default per la visualizzazione di box di alert.

Una volta memorizzato nella sessione il messaggio, siamo pronti a visualizzarlo all’interno delle nostre view.

Il template utilizzato di default è il seguente:

@if (Session::has(‘flash_notification.message’))

{{ Session::get(‘flash_notification.message’) }}

@endif

Nota: questo package è ottimizzato per Twitter Bootstrap.

Poichè i messaggi di avviso sono comuni in un applicazione web, che interagisce con gli utenti, anziché riscrivere ogni volta il codice appena visto, puoi usare (o modificare) il template che questo package offre.

Basta includerlo nelle view in questo modo:

@include(‘flash::message’)

Non stai usando Bootstrap ? Ahia! Allora non puoi usare questo package…

… scherzo! Se non ancora usi Twitter Bootstrap, puoi modificare i layouts dei messaggi.

Per farlo digita da console :

php artisan view:publish laracasts/flash

In questo modo avrai a disposizione le views utilizzate, e potrai facilmente modificarne il codice html. Ad maiora!

Esempio

Vediamo insieme un esempio pratico di utilizzo di questo package.

Creiamo una view per la registrazione di utenti al nostro sito. Aggiungiamo un campo per l’username e l’email, ed uno per la password, in questo modo:

{{ Form::open() }}




{{ Form::close() }}

Il nostro controller avrà un metodo destinato alla gestione della registrazione:

public function register()
{
// validazione dati
$validator = Validator::make(Input::all(), [‘username’ => ‘required’, ‘email’ => ‘required’, ‘password’ => ‘required]);

if ($validator->fails())
{
// Impostare il messaggio di errore
return Redirect::back()->withInput()->withErrors($validator);
}

// Impostare il messaggio di registrazione effettuata
return Redirect::back();
}

Ora, come ti ho spiegato ad inizio articolo, dobbiamo inserire il nostro messaggio per l’utente, prima del redirect.

Per prima cosa aggiungi il messaggio in caso la validazione fallisca:

if ($validator->fails())
{
// Impostare il messaggio di errore
Flash::error(‘Attenzione i dati inseriti non sono validi !’);

return Redirect::back()->withInput()->withErrors($validator);
}

Non abbiamo ancora finito. C’è da sistemare il caso in cui i dati inseriti sono corretti.

Hai due scelte in questo caso.

Puoi usare il metodo Flash::message o Flash::info oppure Flash::success.

// Impostare il messaggio di registrazione effettuata
Flash::success(‘Yuppy! Benvenuto nella mia fantastica applicazione!’);

return Redirect::back();

Sistemato il nostro controller, andiamo a modificare la nostra view.

Aggiungiamo il template (per evitare ripetizioni di codice HTML), in questo modo:

@include(‘flash::message’)

{{ Form::open() }}




{{ Form::close() }}

Ti dirò di più, non abbiamo ancora finito. È rimasto un altro metodo da esaminare in dettaglio. Sto parlando di Flash::overlay.

L’utilizzo di questo metodo prevede obbligatoriamente l’uso di jquery e delle librerie js di Twitter Boostrap.

Tutto quello che dovrai fare sarà aggiungere questa riga di codice nel tuo template.

Et voilà! Il gioco è fatto. Abbiamo il nostro bel modal che ci avvisa se qualcosa è andata male oppure no.

Spero che questo package possa esserti utile: se hai qualche osservazione, feedback o semplice parere commenta qui sotto!

LaracastsPresenter

0

LaracastsPresenter

Può capitare alle volte di dover inserire all’interno delle nostre view, del codice che richiede l’esecuzione di alcune operazioni.
Ad esempio, visualizzare la lista di utenti iscritti al nostro sito, con nome e cognome di ognuno, oppure visualizzare un avatar caricato dai nostri utenti, ecc ecc.
In questo scenario, hai diverse soluzioni per gestire queste situazioni:

  • Forzare l’inserimento del codice all’interno della view
  • Inserire il codice all’interno dei nostri model

Tuttavia, esiste una terza alternativa. L’uso dei Presenter.
Cominciamo a realizzare una piccola applicazione, per studiare le funzionalità di questo package.

Le tabelle

Cominciamo dalla creazione della tabella dei videogame. Usiamo il comando artisan ‘php artisan migration:make create_videogames’:

/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(‘videogames’, function(Blueprint $table)
{
$table->increments(‘id’);
$table->string(‘title’);
$table->string(‘description’);
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop(‘videogames’);
}

Passiamo alla tabella dei voti, che andrà a rappresentare la relazione molti a molti tra videogame ed utenti:

/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create(‘user_videogame’, function(Blueprint $table)
{
$table->increments(‘id’);
$table->integer(‘user_id’)->unsigned()->index();
$table->foreign(‘user_id’)->references(‘id’)->on(‘users’)->onDelete(‘cascade’);
$table->intger(‘videogame_id’);
$table->foreign(‘videogame_id’)->references(‘id’)->on(‘videogames’)->onDelete(‘cascade’);
$table->float(‘rating’);
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop(‘ratings’);
}

Prima di proseguire, non dimenticarti di eseguire le migration. Per farlo basta usare il comando ‘php artisan migrate’.

I models

class Videogame extends Eloquent {

protected $fillable = array(‘title’, ‘description’);

public function voters($id)
{
return $this->belongsToMany(‘User’);
}

}

Nota: Il metodo belongsToMany della classe Eloquent viene usato per rappresentare la relazione molti a molti, in questo caso quella tra utenti e videogame.

##I Controllers

Ora passiamo al controller dei videogames:

class VideogamesController extend BaseController {

public function __construct()
{
$this->beforeFilter(‘auth’, [‘only’ => [‘postRatings’]]);
}

public getIndex()
{
$videogames = Videogame::all();

return View::make(‘videogames.index’, compact(‘videogames’));
}

public function postRatings($id)
{
// Salvataggio voto
$videogame = Videogame::findOrFail($id);

// registro il voto dell’utente assieme alla valutazione data per il videogame
return $videogame->voters()->attach(Auth::id(), [‘ratings’ => Input::get(‘rating’));
}

}

La registrazione del voto verrà effettuata aggiornando la tabella pivot user_videogame, aggiungendo il valore di rating inserito dall’utente.

La View

Creiamo una view in cui verrà mostrata la lista dei videogames, con il relativo form per la votazione:

    @foreach ($videogames as $videogame)

  • {{ $videogame->title }}

    {{ $videogame->description }}

    {{– Visualizzazione della media voto del videogame –}}

    {{ Form::open([‘route’ => [‘videogames.rating’, $videogame->id]]) }}

    {{ Form::close() }}

  • @endforeach

A questo punto dobbiamo far visualizzare il voto medio per ogni videogame. Abbiamo due alternative:

  • Inserire il calcolo in un metodo all’interno del model
  • Inserire il calcolo della media voto direttamente nella view

Ora, perchè “sporcare” i nostri model o le nostre view aggiungendoci del codice in eccesso ? Possiamo fare diversamente ?
Certo ! Ed è qui che entra in gioco LaracastsPresenter.

Le routes

Impostiamo le route necessarie per il nostro esempio in questo modo:

Route::get(‘videogames’, [
‘as’ => ‘videogames.index’,
‘uses’ => ‘VideogamesController@getIndex’
]);

Route::post(‘videogames/{videogame}/rating’, [
‘as’ => ‘videogames.rating’,
‘uses’ => ‘VideogamesController@postRatings
]);

Package

Installiamo il package. Digita da terminale ‘composer require laracastspresenter’, inserendo come versione la 0.1.*, premi invia ed attendi l’installazione.
Una volta terminata, siamo pronti ad usare i nostri presenter.

Uso

Per prima cosa crea il tuo primo presenter per i videogame in questo modo:

use LaracastsPresenterPresenter;

class VideogamePresenter extends Presenter {

public function averageRating()
{
if ($this->entity->voters->count())
{
return $this->entity->voters()->sum(‘rating’) / $this->entity->voters->count();
}

return 0;
}

/**
* Ritorna una stringa con il numero di votanti per il videogame
*
*@return string
*/
public function numberOfVoters()
{
return ‘‘ . $this->entity->voters->count() . ‘‘;
}

}

Il metodo averageRating, calcola il voto medio del singolo videogame (una semplice divisione tra il totale di tutti voti e il numero di votanti).

Nota: Dalla classe VideogamePresenter per accedere alle relazioni del model Videogame, basta usare $this->entity.

Successivamente all’interno model Videogame aggiungi il trait LaracastsPresenterPresentableTrait, che farà in modo di istanziare automaticamente il presenter del modello Videogame, in questo modo:

use LaracastsPresenterPresentableTrait;

class Videogame extends Eloquent {
use PresentableTrait;

protected $presenter = ‘VideoGamePresenter’;

protected $fillable = array(‘title’, ‘description’);

public function voters()
{
return $this->belongsToMany(‘User’);
}

/**
* Ritorna la lista di utenti eliminando le ripetizioni
*/
public function users()
{
return $this->belongsToMany(‘User’)->distinct();
}

}

Ed è fatta! Vediamo come cambia il codice nella nostra view dei videogame:

    @foreach ($videogames as $videogame)

  • {{ $videogame->title }}

    {{ $videogame->description }}

    {{– Visualizzazione della media voto del videogame –}}
    media voto : {{ $videogame->present()->averageRating }}/5

    {{ Form::open([‘route’ => [‘videogames.rating’, $videogame->id]]) }}

    {{ Form::close() }}

  • @endforeach

La chiamata al metodo averageRating si effettua con il metodo present(),
che ritorna una nuova istanza dell’oggetto VideogamePresenter o l’istanza precedentemente memorizzata.
Perchè non aggiungere un presenter anche ad User ?
Magari per visualizzare la lista dei votanti per ogni videogame e, per ogni utente visualizzare la rispettiva username ed email.

Modifichiamo la clase User, aggiungendo il trait PresentableTrait:

use LaracastsPresenterPresentableTrait;

class User extends Eloquent {

use PresentableTrait;

protected $presenter = ‘UserPresenter’;

/**
* Lista dei giochi votati dall’utente
*
*/
public function videogames()
{
return $this->belongsToMany(‘Videogame’);
}
}

Ed infine crea la classe UserPresenter:

use LaracastsPresenterPresenter;

class UserPresenter extends Presenter {

/**
* Visualizza il nome completo dell’utente con username ed email
*
* @return string
*/
public function fullName()
{
return $this->username . ‘ – ‘ . $this->email;
}

}

A questo punto, non ti rimane che mostrare la lista dei votanti per il videogame:

    @foreach ($videogames as $videogame)

  • {{ $videogame->title }}

    {{ $videogame->description }}

    {{– Visualizzazione della media voto del videogame –}}
    media voto : {{ $videogame->present()->averageRating }}/5 su {{ $videogame->present()->numberOfVoters }}

    {{ Form::open([‘route’ => [‘videogames.rating’, $videogame->id]]) }}

    {{ Form::close() }}

      @foreach ($videogame->users as $user)

    • {{ $user->present()->fullName }}
    • @endforeach

  • @endforeach

Ed è tutto anche per questo package.

Spero che questo package possa esserti utile: se hai qualche osservazione, feedback o semplice parere commenta qui sotto!

Former, un potente form builder per Laravel – Seconda Parte

0

Anatomia di Former

Lo so, ti occorre un pò di pazienza per imparare tutte queste classi. Un buon modo per iniziare può essere quello di elencare specificando di cosa si occupano:

  • Former: è la classe principale e si occupa delle configurazioni e delle interazioni tra le varie componenti di un form
  • FormerServiceProvider: è il Service Provider per Laravel 4
  • Helpers: un set di helpers statici a supporto delle varie librerie
  • Dispatch: intercetta la chiamata che viene fatta alla Former facade rimandandola alla classe di competenza
  • LiveValidation: gestisce la validazione dei campi e la traduzione delle regole negli attributi
  • Populator: è un contenitore di valori che Former sfrutta per fare il get/set degli stessi
  • Traits:
  • Checkable: metodi e proprietà relativi a radiobutton e checkbox
  • Field: metodi e proprietà relativi ai campi
  • FormerObject: oggetto che estende le caratteristiche di cui sopra, gestisce attributi dinamici

  • Framework: metodi e proprietà comuni ai vari framework

  • Interfaces: metodi required dei vari framework
  • FieldInterface
  • FrameworkInterface
  • Framework : queste classi generano il corretto markup in base al framework in uso
  • Nude
  • TwitterBootstrap
  • ZurbFoundation
  • Form: le seguenti classi gestiscono il markup di una form
  • Actions: gestisce le azioni dei pulsanti submit
  • Elements: gestisce i vari elementi del form che non sono azioni (legende, ecc..)
  • Form: gestisce l’apertura e la chiusura dei form e altri metodi correlati
  • Group: si occupa del wrap e dello stato dei campi, del recupero degli errori e altro
  • Fields: una serie di classi ognuna delle quali gestisce un tipo di campo
  • Button
  • Checkbox
  • File
  • Hidden
  • Input
  • Radio
  • Select
  • Textarea
  • Uneditable

  • Facades : Alcuni entry points che facilitano l’esperienza attraverso i vari ambiaenti

  • Agnostic : la facade di base usata da Former al di fuori di ogni framework
  • FormerBuilder :Metodi comuni e blocchi da usare per tutte le facade
  • Illuminate : la facade di Laravel 4, aggancia Former ad alcuni componenti (localizzazione etc)
    LaravelThree : la facade di Laravel 3, aggancia Former ad alcuni componenti (localizzazione etc)
    Legacy : Un set di A set of classi redirector che unificano l’interfaccia tra Laravel 3 e 4
  • Config
  • Redirector
  • Session
  • Translator

Descrizione dei metodi

FormerFormer
E’ la classe principale e costituisce la tua interfaccia per tutto in Former. Chiaramente Former ti da la possibilità di interagire con le sue sottoclassi e quindi non solo puoi usare i suoi metodi ma anche quelli delle sottoclassi.

Option

E’ un set di opzioni utili a modificare il comportamento di Former

Former::config(‘translate_from’, [string]) (‘validation.attributes’)

Di default, Former tenta di tradurre labels, legend e help text. Prima effettua un tentativo di traduzione delle stringhe in automatico poi controlla che il testo sia presente da un’altra parte. Puoi impostare questa variabile che di default è settata a 'validation.attributes.mykey'.

Former::config(‘required_class’, [string]) (‘required’)

Una classe da aggiungere ai campi impostati come obbligatori

Former::config(‘default_form_type’, [horizontal|vertical|inline|search]) (‘horizontal’)

Di default quando chiami Former::open, una fallback form type viene assegnata al form – dice di che tipo è il form. Può essere uno dei valori o null se non vuoi usare le classi di Bootrap per i form.

Former::config(‘fetch_errors’, [boolean]) (true)

Ogni volta che chiamo il metodo open, se è settato a true, Former controllerà nell’array Session la presenza dell’oggetto Message che il metodo ->with_errors() della classe Redirect avrebbe dovuto creare. Ciò significa che se chiami Redirect::to()->with_errors() quando la validazione fallisce, Former assocerà automaticamente gli errori visualizzandoli accanto ai campi corrispondenti senza dover scrivere ulteriore codice.

Former::config(‘automatic_label’, [boolean]) (true)

Permette all’utente di attivare o meno le label automatiche. Quando è attivo, se crei un campo di nome foo senza specificare la label, Former assumerà che foo sia la label per quel campo. In sostanza Former tenterà di tradurla e di usarla come label. Se il campo non è attivo nessuna label verrà assegnata al campo.

Former::config(‘live_validation’, [boolean]) (true)

In questo caso Former cercherà di usare le regole del Validator di Laravel come attributi con l’opzione live_validation.

Former::config(‘push_checkboxes’, [boolean]) (true)

In questo caso i checkboxes devono essere sempre presenti nei dati in POST: sia se checked o no.

Helpers

Former::populate([array|Eloquent])

Popola i campi con un array di valori o con un oggetto Eloquent

Former::withErrors([Validator])

Dopo il fallimento di una validazione Former effettua il fetch della variabile $errors dalla Session e imposta come non corretti i campi corrispondenti visualizzando l’errore. Se ti trovi all’interno del controller puoi passare l’oggetto $validator a Former per ottenere lo stesso comportamento.

Former::withRules([array])

Consente di passare una serie di regole Laravel a Former, provando ad applicarle su attributi HTML come pattern, maxlength, ecc..

Former::framework([bootstrap|zurb|null])

Seleziona il tipo di framework CSS Former deve usare per la sua sintassi dandoti più o meno accesso ai metodi disponibili: ad esempio non puoi usare il metodo Bootstrap ->blockHelp se stai usando Zurb, ecc…

$error = Former::getErrors([string])

E’ l’equivalente di $error = isset($errors) ? $errors->first('field') : null.

Form builders

Former::legend([string])

Apre un tag Bootstrap di tipo `

` nel form – la stringa passata potrebbe essere un indice di traduzione e Former tenterà di tradurla.

Former::open()

Il metodo `open` è praticamente identico a quello di Laravel e per questo puoi controllare nella documentazione di Laravel. In aggiunta supporta dei magic methods per la retrocompatibilità:

Former::horizontal_open()
Former::secure_open()
Former::open_for_files()
Former::secure_vertical_open_for_files()

Puoi disporli a tuo piacimento poiché il loro comportamento è indipendente (non fare cose come `secure_files_open_for_vertical` poiché non avrebbe alcun senso)

Former::close()

Semplicemente stampa il tag di chiusura del form: `

`

Former::actions([string, …])

Crea un tag `

` per fare un wrap dei tuoi buttons (submit, back, reset, ecc…). Per fare l’output di più buttons non devi far altro che specificare più argomenti

// Button class from Bootstrapper
Former::actions( Button::submit(‘Submit’), Button::reset(‘Reset’) )

**Field builders**

La classe che userai per i due terzi del tuo tempo:

Former::[classes]_[field]

Questo metodo effettuerà un’analisi ogni volta che chiami un metodo sconosciuto e tenterà di creare un campo con esso. Lo decompone come `[classes]_[field]` o solo come `[field]`. Puoi chiamare tutte le classi Bootstrap che operano sui campi da span1 a span12 e da mini a xxlarge.

**Form/Field**

Questa classe è quella che entra in azione quando crei un campo. Il metodo sotto sarà accessibile solo dopo la creazione di un campo. Ecco un esempio per chiarire:

// Qui usi Former
Former::populate($project)
// Qui usi la classe Field in Former
Former::text(‘foo’)

Una classe smette di essere un campo quando quel campo viene stampato a video. Ciò significa che puoi fare questo:

$textField = Former::text(‘foo’);
$textField->class(‘myclass’)

Ma non questo:

echo Former::text(‘foo’)
Former::class(‘myclass’)

Perché i campi sono come piccoli uccelli e una volta che volano via non puoi più occuparti di loro.

**Interazione con gli attributi**

Former::text(‘foo’)->addClass([string])

Aggiunge una classe al campo corrente senza sovrascriverla diversamente da `->class()` che sovrascrive ogni attributo esistente – come ogni attributo setter.

Former::text(‘foo’)->forceValue([string])

Setta il valore del campo. Sarà sovrascritto dal dato in POST ma sovrascriverà chiamate da `Former::populate`.

Former::text(‘foo’)->value([string])

Setta il valore degli attributi. Gli attributi che contendono trattini verranno sostituiti da underscore. Quindi dovrai chiamare `data_foo(‘bar’)` per avere `data-foo=”bar”`.

Former::text(‘text’)->setAttribute([string], [string])

Puoi usarla come fallback per i magic method se vuoi impostare un attributo con un underscore

Former::text(‘foo’)->setAttributes([associative array])

Ti permette di fare un setting massivo di coppie di attributi usando un array. Di seguito degli esempi per fare la stessa cosa:

Former::text(‘foo’)->class(‘foo’)->foo(‘bar’)
Former::text(‘foo’)->setAttributes(array( ‘class’ => ‘foo’, ‘foo’ => ‘bar’ ))

Il secondo non è il metodo più pulito ma è utile se vuoi impostare lo stesso attributo per un gruppo di campi creando un array con gli attributi.

Former::text(‘foo’)->label([string])

Imposta l’etichetta di un campo come stringa. Se stai usando Bootstrap questo ha un significato specifico in quanto all’etichetta creata verrà assegnata la classe control-label in automatico.

Former::text(‘foo’)->addGroupClass(‘bar’)

Aggiunge una classe specifica al control-group di livello superiore

**Helpers**

$textField = Former::text(‘foo’)->require()
$textField = $textField->isRequired() // Ritorna “true”

Controlla se un campo è stato impostato come required.

**FormerCheckable**

Checkable è un subset di Field e quindi ogni metodo disponibile per Field sarà disponibile anche per Checkable che in più offre un paio di metodi relativi a radio button e checkbox.

Former::radios(‘foo’)->inline()
Former::checkboxes(‘foo’)->stacked()

Imposta i radio button e/o checkbox in line oppure in verticale (stacked).

Former::checkbox(‘foo’)->text(‘bar’)

Se vuoi mostrare solo un checkbox/radio con il relativo testo

Former::checkbox(‘foo’)->check()
Former::radio(‘foo’)->check()

Former::checkboxes(‘foo’)->checkboxes(‘foo’, ‘bar’)->check(‘foo_0’)

Former::radios(‘foo’)->checkboxes(‘foo’, ‘bar’)->check(0)

Il metodo check ti consente di verificare un elemento singolo oppure un elemento in una lista di elementi. Per un singolo elemento puoi chiamare il metodo `chec()` senza argomenti mentre invece, quando lo chiami per un elemento all’interno di un gruppo, dovrai specificare nell’argomento di quale elemento si tratta. Il comportamento sarà diverso tra radio e checkbox. Il perché è semplice: i checkbox possono essere differenziati per il loro nome mentre i radio possono essere differenziati solo per il loro valore. Quindi per un checkbox dovrai specificare il nome mentre per un radio dovrai specificare il valore.

**FormerControlGroup**

Metodi ed Helper relativi al gruppo dei controlli di Bootstrap. Se imposti da subito l’opzione `$useBootstrap` a false, questa classe e i relativi metodi non saranno accessibili.

Former::text(‘foo’)->state([error|warning|info|success])

Imposta lo stato del gruppo di controlli ad una particolare classe Bootstrap.

Former::text(‘foo’)->inlineHelp([string])
Former::text(‘foo’)->blockHelp([string])

Aggiunge al campo un testo di help di tipo inline/block. Per un campo potrai chiamarli entrambi ma ognuno potrà essere chiamato una sola volta: se chiami due volte `inlineHelp`, l’ultima chiamata sovrascriverà la precedente.

Former::text(‘foo’)->append([string, …])
Former::text(‘foo’)->prepend([string, …])

Antepone al campo corrente un elemento icons/text/buttons. Queste funzioni usano `func_get_args()` e quindi puoi ad esempio fare questo:

Former::text(‘foo’)->prepend(‘@’, ‘$’)

**FormerFieldsInput**

Tutte le classi relative agli input-type.

Former::text(‘foo’)->useDatalist([array])
Former::text(‘foo’)->useDatalist([Query], [string], [string (id)])
Crea un tag `` e lo collega al campo in modo da creare un mix select/text.

**FormerFieldsSelect**

Tutte le classi relative alle select. (select, multiselect, etc)

Former::select(‘foo’)->options([array], [selected])

Popola un campo `Molto semplicemente: selezioni il nome di un cliente e avrai come valore il suo ID. Il secondo parametro serve a preselezionare un elemento: se nell’esempio precedente avessimo aggiunto `->options($clients, 3)` avremmo ottenuto come preselezionato ‘Clémence’.

Former::select(‘foo’)->select(3)

Alias per il metodo `->value()`, seleziona un option

Former::select(‘foo’)->fromQuery([array], [string], [string (id)])

Popola una `

Validiamo i nostri dati con Validation di Laracasts!

0

La validazione dei dati è una parte essenziale per qualsiasi applicazione web. Se conosci le basi di laravel, saprai che esiste un sistema molto semplice di validazione che utilizza la classe Validator.

Il package “laracasts/validation” ti offre un modo alternativo, e ben strutturato per il controllo dell’input.

Scopriamolo insieme, in questo articolo.

Installazione del Package

Installiamo il package tramite composer, aggiungendo questa stringa nel campo require:

“require”: {
“laracasts/validation”: “~1.0”
}

Successivamente, dopo aver eseguito da terminale il comando composer update, aggiungiamo il service provider all’interno dell’array providers del file app.php.

‘LaracastsValidationValidationServiceProvider’

Utilizzo

Immagina di dover validare i dati degli utenti che effettuano un login. Per prima cosa, crea una classe LoginForm, in cui andrai ad inserire le tue regole di validazione, in questo modo:

use LaracastsValidationFormValidator

class LoginForm extends FormValidator {
/**
* Validation rules for logging in
*
* @var array
*/
protected $rules = [
‘username’ => ‘required’,
‘password’ => ‘required’
];

}

Il passo successivo è di includere questa nuova classe all’interno del nostro controller, o comunque dove tu abbia bisogno di eseguire la validazione.

use MyAppFormsLogin as LoginForm;
use LaracastsValidationFormValidationException;

protected $loginForm;

public function __construct(LoginForm $loginForm)
{
$this->loginForm = $loginForm;
}

public function store()
{
$input = Input::all();

try
{
$this->loginForm->validate($input);

// login user, do whatever, redirect
}
catch (FormValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->getErrors());
}

}

Se la validazione va a buon fine, verrà ritornato true. Altrimenti verrà lanciata un’eccezione FormValidationException.

A questo punto hai due scelte: la prima è quella di intercettare l’eccezione all’interno del tuo controller come nell’esempio, con il blocco try catch.

La seconda è di usare un intercettazione globale, inserendo questo semplice codice nel file global.php:

App::error(function(LaracastsValidationFormValidationException $exception, $code)
{
return Redirect::back()->withInput()->withErrors($exception->getErrors());
});

Come ben saprai… (perché lo sai, vero?) global.php contiene degli handlers globali per intercettare gli errori. Quindi se la validazione fallisce, l’utente verrà reindirizzato nella pagina del form.

Ora non rimane che validare i dati, usando il metodo validate:

$this->registrationForm->validate(Input::all());

Ed voilà, il gioco è fatto.

Spero che questo package possa esserti utile: se hai qualche osservazione, feedback o semplice parere commenta qui sotto!

Note Conclusive

Questo package non sarà necessario in Laravel 5.0.

Eliminare correttamente un elemento di una lista con un metodo e jQuery

0

Quante volte ti sei trovato davanti alla creazione di un bottone che al click dovesse eliminare quel determinato id, in quella determinata tabella?

Sicuramente più di una volta. Sicuramente ti sarai chiesto: “come posso fare per far comparire un popup per avere la conferma che l’utente voglia realmente eliminare quel determinato elemento?”

Bene! Oggi ti voglio spiegare come fare.

// Generare un token CSRF e metterlo all’interno di un attributo data-delete personalizzato
public function buttonDelete()
{
$format = ‘‘;
$link = URL::route(‘accounts.groups.delete’, [‘id’ => $this->resource->id]);
$token = csrf_token();
$title = “Delete the group”;
return sprintf($format, $link, $token, $title);
}

// Funzione jQuery che intercetta gli eventi click su elementi aventi un attributo data-delete
$(‘[data-delete]’).click(function(e){
e.preventDefault();
// Se l’utente conferma l’eliminazione
if (confirm(‘Do you really want to delete the element ?’)) {
// URL route
var url = $(this).prop(‘href’);
// Token
var token = $(this).data(‘delete’);
// Creo un elemento form
var $form = $(‘

‘, {action: url, method: ‘post’});
// Aggiungo un input con type=”hidden” e value=”delete”
var $inputMethod = $(‘‘, {type: ‘hidden’, name: ‘_method’, value: ‘delete’});
// Aggiungo il token all’input
var $inputToken = $(‘‘, {type: ‘hidden’, name: ‘_token’, value: token});
// Aggiungo gli input al form, lo nascondo, lo aggiungo al , INVIO!
$form.append($inputMethod, $inputToken).hide().appendTo(‘body’).submit();
}
});

Ti è servito? Usi un metodo che secondo te è migliore?

Dicci la tua!

Former, un potente form builder per Laravel – Prima Parte

0

Oggi ti presento Former, un package in PHP per Laravel che ti permette di gestire i form in modo incredibilmente semplice.

Former fa tanto lavoro al posto tuo: si occupa della ripopolazione dei campi, della validazione, della gestione dei grouped field e si distingue per l’integrazione con framework CSS quali Bootstrap e Foundation.

Introduzione

Lo scopo di Former è quello di ripensare in maniera elegante il processo di creazione dei form trasformando ogni campo in un proprio “oggetto” con attributi e metodi. In pratica una cosa del genere:

Former::horizontal_open()
->id(‘MyForm’)
->secure()
->rules([‘name’ => ‘required’])
->method(‘GET’)

Former::xlarge_text(‘name’)
->class(‘myclass’)
->value(‘Joseph’)
->required();

Former::textarea(‘comments’)
->rows(10)->columns(20)
->autofocus();

Former::actions()
->large_primary_submit(‘Submit’)
->large_inverse_reset(‘Reset’)

Former::close()

In riferimento all’esempio, se chiami un metodo che non esiste, Former assumerà che tu stia tentando di settare un attributo e quindi lo creerà. Scrivendo ->rows(10) definirai un attributo che indica il numero di righe.

Se invece vuoi definire un metodo che contiene dei trattini puoi farlo utilizzando l’underscore nel nome del metodo: con ->data_foo('bar') definisci l’attributo data-foo="bar".

Ora ti starai chiedendo: e se voglio definire un attributo con underscore? Fugo subito i tuoi dubbi: setAttribute('data_foo', 'bar') ed è fatta.

Iniziamo

Concetti di base

Former va concepito come un helper per le tue view. Questo significa che puoi utilizzare i suoi metodi all’interno delle stesse così:

method(‘GET’) ?>
required() ?>

Se utilizzi un template engine come Twig o simili, puoi usare Former all’esterno delle tue view in questo modo:

$form = Former::open()->method(‘GET’);
$form .= Former::text(‘name’)->required();
$form .= Former::close();

Installazione

La procedura è semplicissima. Aggiungi la seguente riga al file composer.json:

“anahkiasen/former”: “dev-master”

Aggiungi il service provider di Former alla lista providers nel file app/config/app.php:

‘Former’ => ‘FormerFacadesFormer’,

Installazione con il Package Installer

Semplicemente, lancia il seguente comando Artisan:

artisan package:install anahkiasen/former:dev-master

Installazione fuori dal framework

Per installare il package in un progetto esterno al framework usa comunque Composer, non scordandoti però di aggiungere, dove necessario, il

use FormerFacadesFormer;

Features

Integrazione con Bootstrap e Foundation

Finora potrai esserti chiesto se questa non sia altro che una variante della classe Form già inclusa in Laravel. Dov’è la sua potenzialità? La risposta è semplice: Former si integra con vari framework e permettendoti di riconoscere, ad esempio, se stai definendo un form orizzontale o verticale inserendolo direttamente all’interno dei tag giusti per l’inclusione nel form.

Un esempio? Il codice:

Former::select(‘clients’)->options($clients, 2)
->help(‘Pick some dude’)
->state(‘warning’)

genera questo html (con Bootstrap):


Pick some dude

Former usa come Framework di default Bootstrap ma puoi scegliere di cambiarlo con il metodo Former::framework(). Al momento Former supporta le seguenti opzioni 'TwitterBootstrap','ZurbFoundation' and 'Nude' (per non usare framework)

/ /disabilita la sintassi Bootstrap
Former::framework(‘Nude’);

// Rabilita la sintassi Bootstrap
Former::framework(‘TwitterBootstrap’);

Ecco un esempio con Foundation:

Former::framework(‘ZurbFoundation’);
Former::four_text(‘foo’)->state(‘error’)->help(‘bar’)

e il relativo output:



Bar

Collegamento con il Validatore di Laravel

Bene, negli esempi visti prima hai fatto un bel passo avanti: non dovrai più chiamare la funzione Form::control_group() e sarai più spedito nella costruzione del form. Ma ora ti starai chiedendo: “come faccio per la validazione? dovrò comunque validare a mano tutti i campi”.

Buone notizie: non dovrai. Il metodo withErrors() di Former accorre in tuo aiuto.

Former non solo si occupa di fare il wrapping dei tuoi campi all’interno dei control group, ma controlla anche l’oggetto Message verificando se un campo contiene o meno errori ed evidenziandolo, eventualmente, con l’attributo .help-inline. Vediamo come.

Ecco due esempi dopo una validazione non andata a buon fine:

Se renderizzi una view dopo una validazione fallita (senza redirect):

if($validation->fails()) {
Former::withErrors($validation);
return View::make(‘myview’);
}

Se fai un redirect dopo una validazione fallita:

if($validation->fails()) {
return Redirect::to(‘login’)
->with_errors($validation);
}

Avrai notato come nell’ultimo esempio non chiami Former. Il perché è presto detto. Ogni volta che costruisci un form con Former, questo si occuperà di controllare se nell’array Session è presente l’oggetto errors e, in caso affermativo, lo userà senza richiedere altro. Puoi disabilitare la possibilità di fetching automatico degli errori impostando l’opzione seguente: Former::config('fetch_errors', false).

Popolare i Form

Popolare un form con Former è semplice, basta usare il metodo Former::populate. Puoi farlo in due modi. Il primo è quello di passare un array di valori:

//Popolerà il campo ‘name’ con il valore ‘value’
Former::populate( array(‘name’ => ‘value’) )

Il secondo è quello di passare un Eloquent model. Se ad esempio hai un model “Client” puoi operare così:

Former::populate( Client::find(2) )

Former riconosce il model e lo popola con i suoi attributi. Supponi che il model abbia l’attributo name impostato a Foo e l’attributo firstname impostato a Bar. Bene, Former non farà altro che ripopolare i campi name e firstname rispettivamente con i valori Foo e Bar.

In alternativa puoi anche ripopolare un campo dopo aver ripopolato l’intero form (è il caso delle relazioni ad esempio) operando così:

Former::populate($project)
Former::populateField(‘client’, $project->client->name)

Per il resto ripopolare un form è cosa banale grazie al comando: -&gt;value('something'). Per generare una lista di option per una <select> chiama il metodo Former::select('foo')-&gt;options([array], [facultative: selected value]). Puoi anche usare il risultato di una query (Eloquent o Fluent) per popolare gli option di una select:
Former::select(‘foo’)->fromQuery(Client::all(), ‘name’, ‘id’)
Il secondo argomento rappresenta il testo dell’option mentre il terzo rappresenta il valore (di default il valore è id). Ma Former può fare molto di più. Supponi di passare un model Eloquent alla tua select senza aver specificato il secondo e il terzo parametro. Former tenterà di recuperare la chiave usando il metodo Eloquent get_key() e userà il metodo __toString() per bindare le variabili. Guarda questo esempio:
class Client extends Eloquent
{
public static $key = ‘code’;
public function __toString()
{
return $this->name;
}
}
Former::select(‘clients’)->fromQuery(Client::all());
Sicuro e secondo il paradigma “stay DRY”. Il seguente codice è equivalente ma molto più oneroso: usa tutte le chiavi di default del model Client e come output l’attributo name per la label delle option.

  Foo


@foreach(Client::all() as $client)
@if(Input::get(‘foo’, Input::old(‘foo’)) == client->code)@else@endif
@endforeach
Former è anche in grado di popolare dei campi coinvolti in una relazione. Un esempio vale più di mille parole (a meno che il vostro esempio non superi le mille parole).

Former::populate(Client::find(2))

// Sarà popolato con $client->name
Former::text(‘name’)

//Sarà popolato con $client->store->name
Former::text(‘store.name’)

// Puoi scegliere il livello di profondità che vuoi
Former::text(‘customer.name.adress’)

// Sarà popolato con la data di tutte le date di reservation di Client
Former::select(‘reservations.date’)

// Stessa cosa di ^
Former::select(‘reservations’)->fromQuery($client->reservations, ‘date’)

// Se stai usando un testo e non una select, invece di elencare i modelli della relazione come opzioni li concatenerà
Former::text(‘customers.name’) // Mostrerà “name, name, name”

// Puoi rinominare un campo successivamente per una più facile gestione dell’Input
Former::text(‘comment.title’)->name(‘title’)

Datalist

Un’altra cosa che Former può fare è creare dei Datalist.

Sai cosa sono? Hai presente quando a volte vuoi far scegliere all’utente qualcosa da una selezione ma nello stesso tempo vuoi anche dargli la possibilità di scriverlo se quello che vuole non c’è nella lista? Bene, quello è un Datalist e crearlo con Former è molto semplice:

Former::text(‘clients’)->useDatalist($clients)

//Puoi usare un Query object, stessa sintassi poi per fromQuery()
Former::text(‘projects’)->useDatalist(Project::all(), ‘name’)

Puoi anche (se ne hai bisogno) assegnare un id al datalist appena creato in questo modo: Former::text('foo')-&gt;list('myId')-&gt;useDatalist(). In questo modo genererai il corrispondente <datalist> e lo linkerai tramite id a quel campo. Ciò significa che il tuo text input sarà popolato dai valori del tuo array fino a quando l’utente non inserisce ciò che vuole.

Live Validation

Bene, andiamo avanti. Come molti di voi sapranno, oggi praticamente tutti i browser moderni supportano la validazione lato client con il solo utilizzo di attributi html. È il caso di attributi come pattern, required, max/min ecc…. Quando validi un form lato server hai il tuo array $rules in cui definisci le regole di validazione. Non sarebbe fantastico trasferire quelle regole automaticamente anche lato client in modo da non dover ridefinire due volte le stesse cose?

Former fa proprio questo e con estrema facilità. Ecco un esempio:

Former::open()->rules(array(
‘name’ => ‘required|max:20|alpha’,
‘age’ => ‘between:18,24’,
‘email’ => ‘email’,
‘show’ => ‘in:batman,spiderman’,
‘random’ => ‘match:/[a-zA-Z]+/’,
‘birthday’ => ‘before:1968-12-03’,
‘avatar’ => ‘image’,
));

Quello che Former fa è creare l’html con gli attributi in base alle regole che abbiamo definito sopra. Non ci sono molte regole per ora ma la cosa è in via di sviluppo. Ecco come diventa il codice di sopra lato client:







Inoltre puoi sempre aggiungere regole personalizzate usando espressioni Regex:

Former::number(‘age’)->min(18)
Former::text(‘client_code’)->pattern(‘[a-z]{4}[0-9]{2}’)

Bello vero?! E non finisce qui. Poiché Bootstrap riconosce la validazione in tempo reale, prova a fare un test scrivendo qualcosa che non faccia match con la regola alpha del campo nome e vedrai come si evidenzierà in rosso. Proprio come quando viene assegnata la classe error.

Non ti rimane che aprire il tuo Chrome/Firefox/o-quel-che-è e vedere come ogni volta si aprirà un piccolo pop up che dirà cose come: “Devi riempire quel campo” oppure “L’email non è nel formato giusto, mi credi stupido o cosa?”

Puoi anche impostare manualmente lo stato di un control group (disponibile solo per Bootstrap e Foundation) usando uno degli attributi messi a disposizione come: success, warning, error and info.

Former::text(‘name’)->state(‘error’)

Gestione dei File

In Former come in Laravel, puoi creare un campo file semplicemente così: Former::file.

Cosa c’è di nuovo in questo caso? Beh, puoi creare campi file multipli semplicemente così Former::files generando il seguente html corrispondente: <input type="&quot;file&quot;" name="&quot;foo[]&quot;" multiple="">.

Uno dei metodi speciali è -&gt;accept() che ti permette di:

// Usare uno shortcut per accettare tipi di file (image, video o audio)
Former::files(‘avatar’)->accept(‘image’)

// Usare un’estensione che verrà converita in MIME da Laravel
Former::files(‘avatar’)->accept(‘gif’, ‘jpg’)

//O usare direttamente un MIME
Former::files(‘avatar’)->accept(‘image/jpeg’, ‘image/png’)

Puoi settare la grandezza del file esprimendola in bit o byte:

Former::file(‘foo’)->max(2, ‘MB’)
Former::file(‘foo’)->max(400, ‘Ko’)
Former::file(‘foo’)->max(1, ‘TB’)

Questo tipo di comandi creerà un campo hidden MAX_FILE_SIZE con il valore corretto in bytes.

Checkbox e Radio Button

I checkbox e i radio button sono di una noia mortale. Soprattutto quando ne devi creare molti. Con Former è tutto un pò più semplice.

// Creare un checkbox
Former::checkbox(‘checkme’)

// Creare un checkbox con testo e checkarlo
Former::checkbox(‘checkme’)
->text(‘YO CHECK THIS OUT’)
->check()

// Creare 4 checkbox connessi
Former::checkboxes(‘checkme’)
->checkboxes(‘first’, ‘second’, ‘third’, ‘fourth’)

// Creare checkbox connessi inline
Former::checkboxes(‘checkme’)
->checkboxes($checkboxes)->inline()

// Ciò che è valido per un checkbox vale anche per i radio button
Former::radios(‘radio’)
->radios(array(‘label’ => ‘name’, ‘label’ => ‘name’))
->stacked()

// Puoi definire checkbox e radio stacked o inline chiamando i relativi metodi
Former::inline_checkboxes(‘foo’)->checkboxes(‘foo’, ‘bar’)
Former::stacked_radios(‘foo’)->radios(‘foo’, ‘bar’)

//Impostare quali checkbox sono checkati o no in un solo comando
Former::checkboxes(‘level’)
->checkboxes(0, 1, 2)
->check(array(‘level_0’ => true, ‘level_1’ => false, ‘level_2’ => true))

// Fine tune checkable elements
Former::radios(‘radio’)
->radios(array(
‘label’ => array(‘name’ => ‘foo’, ‘value’ => ‘bar’, ‘data-foo’ => ‘bar’),
‘label’ => array(‘name’ => ‘foo’, ‘value’ => ‘bar’, ‘data-foo’ => ‘bar’),
))

Un aspetto importante: Former ti offre un’opzione per forzare il pushing dei checkbox. Cosa vuol dire?

Si tratta di quando i tuoi checkbox appaiono nell’array POST anche se non sono checked. E’ un comportamento non molto naturale. Per questo Former ti da la possibilità di cambiare il valore di un checkbox non checked nell’array POST attraverso l’opzione unchecked_value.

Quando crei dei molti campi checkabili attraverso i metodi checkboxes/radios(), per orgnuno di loro verrà utilizzato il nome che hai specificato legato ad un numero seriale tramite un underscore, ecco un esempio: <input type="&quot;checkbox&quot;" name="&quot;checkme_2&quot;"> Il campo verrà anche ripopolato nel caso fosse stato “checkato”.

Helper per la Localizzazione

Former ti aiuta anche nel caso tu stessi lavorando su un progetto multilingua.

Quando crei un campo, se non hai specificato una label, Former utilizza il nome di dafault e in maniera automatica tenterà anche di tradurlo. Questo vale per le label dei checkbox, gli help text e le legend dei form. Vediamo alcuni esempi:

// Questo…
Former::label((‘validation.attributes.name’))
Former::text(‘name’, (‘validation.attributes.name’))
Former::text(‘name’)->inlineHelp(
(‘help.name’))
Former::checkbox(‘rules’)->text(
(‘my.translation’))

{{ __(‘validation.attributes.mylegend’) }}
// ...è lo stesso di questo

Former::label(‘name’)
Former::text(‘name’)
Former::text(‘name’)->inlineHelp(‘help.name’)
Former::checkbox(‘rules’)->text(‘my.translation’)
Former::legend(‘mylegend’)

Non male vero? Former prima tenterà di tradurre la stringa da solo, my.text ritornerà __('my.text'), e in caso di fallimento cercherà in un posto alternativo che puoi impostare attraverso la variabile Former::config('translate_from', [boolean]) (di default validation.attributes). Ricorda: deve essere un array.

Note sulle impostazioni dei Valori dei Campi

  • i dati in POST hanno la precedenza su tutto il resto – se un utente digita qualcosa in un campo è anche probabile che è quello che si aspetta di vedere quando questo deve essere ripopolato;
  • poi ci sono i campi impostati usando il metodo -&gt;forceValue() – è un caso particolare del metodo -&gt;value() che forza un valore in un campo indipendentemente da ciò che accade;
  • successivamente ci sono i campi settati con il metodo Former::populate(). È il metodo usato per popolare un campo e, in caso di editing dello stesso, può essere sovrascritto da forceValue;
  • l’ultimo in ordine di priorità è il classico metodo -&gt;value() – è usato per popolare con valori di default un campo e viene sovrascritto da tutti gli altri e dai dati in POST;

Conclusioni

Per oggi basta: abbiamo analizzato le varie feature di Former e fatto un giro completo. Vuoi saperne di più? Aspetta la prossima settimana: entreremo più nel dettaglio.