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!