Home Blog Pagina 14

Crea i tuoi Slug con Eloquent Sluggable

0

Questa è una traduzione della pagina relativa al package Eloquent-sluggable.

Prima di presentare questo package, chiariamo alcuni concetti. Cos’è uno slug? È una versione URL-friendly di una stringa. Lo _slugging _è quella operazione che “sanifica” un URL da caratteri particolari come spazi, lettere accentate, apostrofi, ecc. Il risultato finale è una stringa più leggibile.

Vediamo un piccolo esempio:

In un’ottica SEO non è proprio un URL friendly, non è vero? Sarebbe più corretto avere come parte dell’URL il titolo del post. Tuttavia se il post avesse come titolo “My Dinner With André & François”, l’URL risulterebbe:

http://example.com/post/My+Dinner+With+Andr%C3%A9+%26+Fran%C3%A7ois

Probabilmente ancora meno SEO-friendly 🙁

La soluzione è creare uno slug per questo titolo e utilizzarlo quindi come link per accedere al post. A dirla tutta, Laravel ha già un suo metodo: si tratta di Str::slug() e dà come risultato proprio quello di cui abbiamo bisogno:

http://example.com/post/my-dinner-with-andre-francois

Beh, allora? Che senso ha un altro package che fa la stessa cosa? Per rispondere a questa domanda, poniamo il caso che si debba scrivere un post con lo stesso titolo, ma con contenuto diverso. Con il metodo built-in di Laravel avremmo esattamente lo stesso URL. La soluzione, quindi, non sarebbe univoca. Eloquent-Sluggable fa proprio questo: automatizza tutte le procedure per rendere lo slug univoco anche se il titolo del post è identico al precedente.

Vediamo un altro esempio che rende l’idea:

http://example.com/post/my-dinner-with-andre-francois
http://example.com/post/my-dinner-with-andre-francois-1
http://example.com/post/my-dinner-with-andre-francois-2

Installazione e requisiti

Se il package ti ha convinto, vediamo come installarlo. Prima di tutto aggiungilo al file composer.json:

{
“require”: {
“cviebrock/eloquent-sluggable”: “2.*”
},
}

Nota: Eloquent-Sluggable usa i _traits, _dunque la versione PHP adatta per questo package è la 5.4 +. Tuttavia se sei “costretto” ad usare la versione PHP 5.3., utilizza la versione 1.* di questo package e segui le istruzioni nel file README.md.

Dopo aver lanciato _composer update, _aggiorna il file _app/config/app.php _e aggiungi questo nuovo service provider:

‘providers’ => array(

// …

‘CviebrockEloquentSluggableSluggableServiceProvider’,

);

Ok, ci siamo quasi: dalla riga di comando lancia _php artisan config:publish cviebrock/eloquent-sluggable _per creare il file default di configurazione.

Aggiornare tutti gli Eloquent Model

Per usare Eloquent-Sluggable devi implementare l’interfaccia Sluggable nei tuoi model e usare quindi i suoi traits. Prima definisci un array protetto $sluggable in questo modo:

Chiaramente, la tabella corrispondente al model avrà bisogno di una colonna dove salvare lo slug. Puoi farlo manualmente o creare una migrazione da riga di comando attraverso artisan in questo modo:

use CviebrockEloquentSluggableSluggableInterface;
use CviebrockEloquentSluggableSluggableTrait;

class Post extends Eloquent implements SluggableInterface
{

use SluggableTrait;

protected $sluggable = array(
‘build_from’ => ‘title’,
‘save_to’ => ‘slug’,
);

}

Questo comando aggiunge una colonna chiamata slug alla tabella posts. Se vuoi dare un nome diverso, aggiungi un altro parametro al comando. Così:

php artisan sluggable:table posts

Il tuo model, ora, è sluggable!

Utilizzare la Classe

Una volta salvato un post:

$post = new Post(array(
‘title’ => ‘My Awesome Blog Post’
));

$post->save();

recuperare lo slug è piuttosto semplice:

echo $post->slug;

// oppure
echo $post->getSlug();

Una nota interessante è il supporto di Ardent: se ti interessa dai un’occhiata la file README-Ardent.md

Ti faccio notare che se desideri replicare i tuoi model con il metodo Eloquent replicate(), assicurati di “informare” il package che c’è bisogno di un re-slugging. Ecco come:

$new_post = $post->replicate()->resluggify();

Configurazione

Il sistema di configurazione è stato sviluppato per essere molto flessibile.

Si parte da assegnazioni di default per i tuoi model, ma si può gestire il setting per ogni singolo model.

Di default, la configurazione globale può essere impostata nel file _app/config/packages/cviebrock/eloquent-sluggable/config.php. _Se una configurazione singola non è impostata, il package prenderà come riferimento le impostazioni di default presenti nel file _vendor/cviebrock/(eloquent-sluggable/src/config/config.php. _Ecco tutti i parametri di default:

return array(
‘build_from’ => null,
‘save_to’ => ‘slug’,
‘max_length’ => null,
‘method’ => null,
‘separator’ => ‘-‘,
‘unique’ => true,
‘include_trashed’ => false,
‘on_update’ => false,
‘reserved’ => null,
‘use_cache’ => false,
);

build_from

Questo è un campo o un array di campi dal quale costruire lo slug. Ogni _$model->field è concatenato (con uno spazio separatore) per costruire la stringa sluggable. La stringa può nascere da campi di un db o da qualsiasi altra cosa:

class Person extends Eloquent implements SluggableInterface {

use SluggableTrait;

public static $sluggable = array(
‘build_from’ => ‘fullname’
);

public function getFullnameAttribute() {
return $this->firstname . ‘ ‘ . $this->lastname;
}

}

se _build_from _è vuoto, false o nullo, sarà usato il valore di _$model->__toString()_.

save_to

È il campo del tuo db dove sarà salvato lo slug. Di default, è “slug”. Ma puoi dargli il nome che preferisci:

Schema::create(‘posts’, function($table)
{
$table->increments(‘id’);
$table->string(‘title’);
$table->string(‘body’);
$table->string(‘slug’);
$table->timestamps();
});

max_length

Se assegni un valore positivo intero a questo indice di array, il tuo slug avrà una lunghezza prefissata. Di default, questo valore è nullo e non ha limiti.

N.b. I numeri alla fine della stringa “-1”, “-2”, “-3” non sono inclusi nel conteggio di max_length.

method

Definisce il metodo usato per trasformare la stringa sluggable in un vero e proprio slug.

Tre sono le possibili opzioni:

  1. Quando il metodo è nullo, il package userà il metodo di Laravel _Str::slug() _
  2. Si può richiamare un metodo di una classe. Due i parametri: la stringa da processare e una stringa di separazione. Per esempio: per duplicare il comportamento di default puoi fare così:

‘method’ => array(‘Illuminate\Support\Str’, ‘slug’),

  1. Puoi anche definire il metodo come closure. In questo modo:

‘method’ => function( $string, $separator ) {
return strtolower( preg_replace(‘/[^a-z]+/i’, $separator, $string) );
},

separator

Definisce il separatore usato per costruire lo slug. Il valore di default è il trattino (-).

unique

E’ un valore booleano, utile per indicare se lo slug debba essere univoco tra i model. Per esempio, se hai due blog ognuno dei quali ha un post come titolo “My Blog Post”, avranno entrambi lo slug “my-blog-post” . E questo potrebbe essere un problema. Ma se valorizzi l’indice con on, il secondo model Post restituirà come slug “my-blog-post-1”. Se ci fosse un terzo post con lo stesso titolo, avrà “my-blog-post-2”, e così via.

include_trashed

Questo indice funziona solo se utilizzi il SoftDelete di Laravel. Se imposti questo indice a true il package si preoccuperà di controllare anche tra i record soft deleted. Di default è impostato su false.

on_update

Anche questo è un valore booleano. Se impostato a false (valore di default), gli slug non saranno aggiornati in caso di update del model (ad esempio, se dovessi cambiare il titolo del post, lo slug non cambierebbe).

reserved

Un sorta di black list per la creazione di slug. I motivi possono essere tantissimi: evitare collisioni nella route, nei metodi del controller, ecc. Può essere un array, o una closure che restituisce un array. Di default il valore è null.

use_cache

Quando controlla i valori univoci, il package interroga il db: questo significa che c’è un importante utilizzo del db. Attivando use_cache l’ultimo incremento generato sarà gestito dalla cache e saranno evitate query future. Il valore di default è false: il package non usa la cache. Se stai già usando un sistema di caching che supporta Cache::tags(), è preferibile attivare anche use_cache. E’ sufficiente, quindi, cambiare il valore false in un numero intero positivo che rappresenta i minuti del ciclo di vita della cache per il package (non per l’app di Laravel, naturalmente).

Estendere Sluggable

A volte le opzioni di configurazione non sono sufficienti quando l’applicazione è complessa. La buona notizia è che questo package si può estendere sovrascrivendo i metodi. Dai un’occhiata a _SluggableTrait->sluggify() _per vedere quale sia l’ordine delle operazioni. Puoi anche considerare l’opzione di effettuare un overloading dei seguenti metodi protetti:

needsSlugging()

Verifica se il modello ha bisogno di essere slugged. Restituisce true o false.

getSlugSource()

Restituisce una stringa utile per creare il sorgente dello slug.

generateSlug($source)

Il codice che genera lo slug. _Di solito implementa tutto ciò che è definito nel _method, ma potrebbe far riferimento ad altre librerie esterne. Prende la stringa originaria e la restituisce.

validateSlug($slug)

Valida lo slug e controlla anche se ci sia qualche riferimento nella variabile reserved: la black list di cui abbiamo parlato prima. Restituisce uno slug valido.

makeSlugUnique($slug)

Controlla l’univocità dello slug. Restituisce uno slug univoco.

getExistingSlugs($slug)

Restituisce tutti gli slug simili a quello dato. Dovrebbe restituire un’accoppiata chiave-valore di slug esistenti, dove il valore è rappresentato dallo slug e la chiave dall’id.

setSlug($slug)

Scrive lo slug (generato, valido, e univoco) per gli attributi del model.

Uno sguardo alle API RESTful

0

Traduzione dell’articolo “Laravel 4: A Start at a RESTful API” su Tuts+

L’approccio RESTful è favoloso ma richiede un pò di applicazione. Ci sono molti aspetti di cui dovrai occuparti durante la progettazione e l’implementazione.

Dovrai, ad esempio, occuparti dell’autenticazione, delle transizioni tra uno stato e l’altro (hypermedia/HATEOS), del versioning, dei limiti della velocità di banda e della negoziazione dei contenuti.

Chiaramente in questo articolo non tratteremo tutti questi aspetti ma solo di come si comporta REST a livello base usando Laravel. Realizzeremo alcuni endpoint JSON e un sistema di autenticazione di base imparando alcuni trucchi.

L’applicazione

Costruiremo un semplice sistema che permette di gestire dei collegamenti che l’utente vuole leggere più tardi. L’utente potrà creare, leggere, aggiornare e cancellare gli url. Niente di complesso.

Passiamo ai fatti e iniziamo a realizzare la nostra applicazione.

Installare Laravel 4

Come prima cosa installiamo Laravel 4. Puoi farlo semplicemente seguendo la nostra guida su come installare Laravel oppure da riga di comando seguendo questa guida. Infine posso suggeriti questo video tutorial su Nettuts+.

Dopo l’installazione andiamo a creare la nostra encryption key per la sicurezza delle password. Per farlo puoi usare il seguente comando Artisan posizionandoti sulla root del tuo progetto:

$ php artisan key:generate

Se non vuoi usare Artisan nessun problema, puoi modificare il file app/config/app.php alla voce encryption key:

/*
|————————————————————————–
| Encryption Key
|————————————————————————–
|
| This key is used by the Illuminate encrypter service and should be set
| to a random, long string, otherwise these encrypted values will not
| be safe. Make sure to change it before deploying any application!
|
*/

‘key’ => md5(‘inserisci qui la tua chiave’),

Bene, dopo l’impostazione dell’encryption key andiamo avanti creando il nostro database.

Per semplicità costruiremo solo le tabelle di cui abbiamo bisogno:

  1. Users, con i campi username e password;
  2. URLs, con l’url e la descrizione;

Per creare e popolare il nostro database, useremo il sistema delle migrations.

Configurare il Database

Assumiamo di avere un database MySQL e configuriamo di conseguenza la connessione al database andando a modificare il file app/config/database.php.

‘connections’ => array(

‘mysql’ => array(
‘driver’ => ‘mysql’,
‘host’ => ‘localhost’,
‘database’ => ‘read_it_later’,
‘username’ => ‘your_username’,
‘password’ => ‘your_password’,
‘charset’ => ‘utf8’,
‘collation’ => ‘utf8_unicode_ci’,
‘prefix’ => ”,
),
),

Creazione delle Migration

$ php artisan migrate:make create_users_table –table=users –create
$ php artisan migrate:make create_urls_table –table=urls –create

Con questi comandi creeremo i file di migrazione per le nostre tabelle. Di seguito andiamo a modificare i file per aggiungere le colonne che ci interessano.

Apriamo il file migration per la tabella Users che sarà qualcosa come: app/database/migrations/DATA_create_users_table.php ed editiamolo così:

public function up()
{
Schema::create(‘users’, function(Blueprint $table)
{
$table->increments(‘id’);
$table->string(‘username’)->unique();
$table->string(‘password’);
$table->timestamps();
});
}

Abbiamo specificato uno username, che deve essere unico, una password e il timestamp. Salviamo e andiamo a modificare l’altro file di migration che sarà simile a app/database/migrations/DATA_create_urls_table.php, aggiungendo il metodo up() anche qui:

public function up()
{
Schema::create(‘urls’, function(Blueprint $table)
{
$table->increments(‘id’);
$table->integer(‘user_id’);
$table->string(‘url’);
$table->string(‘description’);
$table->timestamps();
});
}

Molto simile al precedente se non per il fatto che abbiamo creato un link tra le due tabelle attraverso il campo user_id.

Aggiungiamo un utente

Possiamo usare il meccanismo dei seed per creare un utente di esempio.

Procediamo così: creiamo un file all’interno della cartella app/database/seeds con lo stesso nome della tabella su cui effettuare l’inserimento. Nel nostro caso quindi sarà UserTableSeeder.php. Modifichiamolo come di seguito:

delete();

User::create(array(
‘username’ => ‘firstuser’,
‘password’ => Hash::make(‘first_password’)
));

User::create(array(
‘username’ => ‘seconduser’,
‘password’ => Hash::make(‘second_password’)
));
}

}

Successivamente assicuriamoci di eseguire il seeding sul database modificando il file app/database/seeds/DatabaseSeeder.php:

public function run()
{
Eloquent::unguard();

// Add or Uncomment this line
$this->call(‘UserTableSeeder’);
}

Eseguiamo le Migration

Andiamo ora ad eseguire le migration per la creazione delle tabelle e rimpiamo il nostro database con l’operazione di seed. Apriamo la nostra riga di comando e digitiamo:

// Create the two tables
$ php artisan migrate

// Create the sample users
$ php artisan db:seed

Model

Come è noto, Laravel 4 usa Eloquent ORM che permette una facile gestione database. Andiamo quindi a creare un model per ogni tabella. Per quanto riguarda il model User, Laravel ne ha già uno di default e quindi non resta che creare il model Url in app/models/Url.php e modificarlo come segue:

‘auth.basic’, function()
{
return View::make(‘hello’);
}));

Bene, siamo pronti per un primo vero test. Apriamo il nostro terminale e facciamo una richiesta curl. La richiesta dovrà chiaramente puntare al tuo url e quindi sarà simile alla seguente:

$ curl -i localhost/l4api/public/index.php/authtest
HTTP/1.1 401 Unauthorized
Date: Tue, 21 May 2013 18:47:59 GMT
WWW-Authenticate: Basic
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8

Invalid credentials

Come puoi vedere, otterrai uno status code 401 e il conseguente messaggio di “Invalid Credentials”. Questo perché non abbiamo fatto una richiesta con autenticazione. Proviamo ora a inviare una richiesta con username e password in questo modo e vediamo cosa succede:

$ curl –user firstuser:first_password
localhost/l4api/public/index.php/authtest
HTTP/1.1 200 OK
Date: Tue, 21 May 2013 18:50:51 GMT
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8

Hello World!

Il gioco è fatto! Non ci crederai, ma abbiamo già sistemato tutta la parte basilare del nostro lavoro. Riepilogando, in breve, abbiamo:

  • Installato Laravel 4
  • Creato il database
  • Creato i nostri models
  • Creato un model per l’autenticazione

Creazione di richieste funzionali

Se non l’hai ancora fatto, ti consiglio di leggere qualcosa sui RESTful controllers. Questo ti aiuterà a capire i Resourceful Controllers che useremo nel nostro lavoro per realizzare i giusti paradigmi al fine di implementare un API consistente.

Qui puoi farti un’idea di quello che questo tipo di controller è in grado di gestire. Prima di iniziare ti anticipo che puoi eliminare i metodi /resource/create e /resource/{id}/edit poiché non abbiamo bisogno di mostrare form di creazione o modifica.

Creare un Resourceful Controller

Partiamo con la creazione del controller. Quindi apriamo un terminale e digitiamo:

$ php artisan controller:make UrlController

Successivamente andiamo ad impostare la nostra route modificandola in questo modo:

// Route group for API versioning
Route::group(array(‘prefix’ => ‘api/v1’, ‘before’ => ‘auth.basic’), function()
{
Route::resource(‘url’, ‘UrlController’);
});

In queste righe di codice ci sono alcune cose molto interessanti.
1. L’url http://example.com/api/v1/url risponderà alle nostre richieste;
2. Possiamo aggiungere altre route all’interno di questa per espandere la nostra API. Ad esempio possiamo aggiungere l’end-point /api/v1/user;
3. Abbiamo creato un meccanismo di versioning per la nostra API. Questo ci dà l’opportunità di implementare le nuove versioni delle API senza toccare le vecchie versioni. Possiamo semplicemente creare una route v2, e puntare ad un nuovo controller;

Nota: puoi prendere in considerazione teniche più avanzate per gestire il versioning delle API usando ad esempio un Accept header o un sottodominio per puntare a differenti versioni dell’API.

Aggiungere Funzionalità

Modifichiamo il nostro controller app/controllers/UrlController.php:

// Edit this:
public function index()
{
return ‘Hello, API’;
}

Testiamolo:

$ curl -i localhost/l4api/public/index.php/api/v1/url
HTTP/1.1 401 Unauthorized
Date: Tue, 21 May 2013 19:02:59 GMT
WWW-Authenticate: Basic
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8

Invalid credentials.

$ curl –user firstuser:first_password localhost/l4api/public/index.php/api/v1/url
HTTP/1.1 200 OK
Date: Tue, 21 May 2013 19:04:19 GMT
Vary: Accept-Encoding
Content-Type: text/html; charset=UTF-8

Hello, API

Ora abbiamo un resourceful controller con autenticazione perfettamente funzionante e siamo pronti per aggiungere le più svariate funzionalità alla nostra applicazione.

Creare un URL

Modifichiamo app/controllers/UrlController.php:

public function store()
{
$url = new Url;
$url->url = Request::get(‘url’);
$url->description = Request::get(‘description’);
$url->user_id = Auth::user()->id;

$url->save();

return Response::json(array(
‘error’ => false,
‘urls’ => $urls->toArray()),
200
);
}

Dopo questa modifica testiamo il tutto con una richiesta curl. Inviamo una richiesta POST che corrisponderà al metodo store()appena creato.

$ curl -i –user firstuser:first_password -d ‘url=http://google.com&description=A Search Engine’ localhost/l4api/public/index.php/api/v1/url
HTTP/1.1 201 Created
Date: Tue, 21 May 2013 19:10:52 GMT
Content-Type: application/json

{“error”:false,”message”:”URL created”}

Se tutto è andato bene, andiamo ad aggiungere delle url per entrambi i nostri utenti.

$ curl –user firstuser:first_password -d ‘url=http://fideloper.com&description=A Great Blog’ localhost/l4api/public/index.php/api/v1/url

$ curl –user seconduser:second_password -d ‘url=http://digitalsurgeons.com&description=A Marketing Agency’ localhost/l4api/public/index.php/api/v1/url

$ curl –user seconduser:second_password -d ‘url=http://www.poppstrong.com/&description=I feel for him’ localhost/l4api/public/index.php/api/v1/url

Bene, ora andiamo a creare dei metodi per recuperare le URL come di seguito:

public function index()
{
//In precedenza era: return ‘Hello, API’;

$urls = Url::where(‘user_id’, Auth::user()->id)->get();

return Response::json(array(
‘error’ => false,
‘urls’ => $urls->toArray()),
200
);
}

public function show($id)
{
$url = Url::where(‘user_id’, Auth::user()->id)
->where(‘id’, $id)
->take(1)
->get();

return Response::json(array(
‘error’ => false,
‘urls’ => $url->toArray()),
200
);
}

Facciamo il nostro consueto test:

$ curl –user firstuser:first_password localhost/l4api/public/index.php/api/v1/url
{
“error”: false,
“urls”: [
{
“created_at”: “2013-02-01 02:39:10”,
“description”: “A Search Engine”,
“id”: “2”,
“updated_at”: “2013-02-01 02:39:10”,
“url”: “http://google.com”,
“user_id”: “1”
},
{
“created_at”: “2013-02-01 02:44:34”,
“description”: “A Great Blog”,
“id”: “3”,
“updated_at”: “2013-02-01 02:44:34”,
“url”: “http://fideloper.com”,
“user_id”: “1”
}
]
}

$ curl –user firstuser:first_password localhost/l4api/public/index.php/api/v1/url/1
{
“error”: false,
“urls”: [
{
“created_at”: “2013-02-01 02:39:10”,
“description”: “A Search Engine”,
“id”: “2”,
“updated_at”: “2013-02-01 02:39:10”,
“url”: “http://google.com”,
“user_id”: “1”
}
]
}

Ok ci siamo quasi. Consentiamo ora all’utente di cancellare un’ URL

public function destroy($id)
{
$url = Url::where(‘user_id’, Auth::user()->id)->find($id);

$url->delete();

return Response::json(array(
‘error’ => false,
‘message’ => ‘url deleted’),
200
);
}

Ora possiamo cancellare un’URL semplicemente effettuando una richiesta DELETE

$ curl -i -X DELETE –user firstuser:first_password localhost/l4api/public/index.php/api/v1/url/1
HTTP/1.1 200 OK
Date: Tue, 21 May 2013 19:24:19 GMT
Content-Type: application/json

{“error”:false,”message”:”url deleted”}

Infine, consentiamo all’utente di effettuare l’ update di un’url

public function update($id)
{
$url = Url::where(‘user_id’, Auth::user()->id)->find($id);

if ( Request::get(‘url’) )
{
$url->url = Request::get(‘url’);
}

if ( Request::get(‘description’) )
{
$url->description = Request::get(‘description’);
}

$url->save();

return Response::json(array(
‘error’ => false,
‘message’ => ‘url updated’),
200
);
}

Testiamo il tutto con la seguente richiesta:

$ curl -i -X PUT –user seconduser:second_password -d ‘url=http://yahoo.com’ localhost/l4api/public/index.php/api/v1/url/4
HTTP/1.1 200 OK
Date: Tue, 21 May 2013 19:34:21 GMT
Content-Type: application/json

{“error”:false,”message”:”url updated”}

Lavoro completato!

Con questo articolo ho posto solo le basi per un API completa e funzionante. Spero ti possa essere d’aiuto per costruire qualcosa di tuo tuo.

Facciamo un riepilogo di ciò che abbiamo implementato:

  1. Installazione di Laravel
  2. Creazione del database usando il sistema delle migrations e il seeding
  3. Utilizzo di Eloquent ORM models
  4. Autenticazione con il filtro Basic Auth
  5. Impostazione delle route con gestione del versioning per l’ API
  6. Abbiamo utilizzato l’approccio RESTful (resourceful controllers) per gestire le funzionalità della nostra API

Quali sono i prossimi passi?

Nello sviluppare la nostra applicazione abbiamo tralasciato alcuni aspetti per motivi pratici. Tu puoi continuare a far crescere la tua API aggiungendo ad esempio:
1. La validazione dei dati (Validazione).
2. La gestione degli errori per le richieste. Ad esempio puoi ricevere delle risposte in HTML (Laravel Error Handling)
3. Gestione degli header http (Laravel’s Request Class).
4. Dai uno sguardo anche a API Craft Google Group
5. Gestire la cache (different types caching) e come il Validation Caching può aumentare le prestazioni della tua API.
6. Unit test
7. Dai uno sguardo a questo ebook Apigee’s great API resources

Velocizzare il proprio workflow con Generators

0

Inutile negarlo: Laravel velocizza di molto il workflow a cui siamo abituati. A volte, però, ci sono delle azioni che dobbiamo ripetere, che ci piaccia o meno: la creazione di questo o quel model, o di un controller magari.

Jeffrey Way ha pensato di risolvere il problema creando Generators, un interessante insieme di comandi Artisan che, se ben usati, ci levano di torno un bel po’ di noie.

Un esempio pratico?

Creare un model: diventa semplicissimo sapendo che basta un’istruzione come questa.

php artisan generate:model MyModel

Comodo vero? Vediamo insieme come funziona.

Installazione

Installare il package Generators è un gioco da ragazzi. Aggiungiamo la dipendenza al file composer.json del nostro progetto.

Richiamiamo composer per effettuare l’update:

Il passo successivo è aggiungere il service provider del package all’elenco presente in app/config/app.php. La riga da aggiungere è

“require-dev”: {
“way/generators”: “2.*”
}

Per verificare la corretta riuscita dell’installazione basta usare il comando

php artisan

e controllare se esistono i nuovi comandi nella lista presentata.

Cosa posso fare con Generators?

Le possibilità, con Generators, sono molte. Ecco un elenco di tutto ciò che è possibile creare in modo automatizzato:

  • Migration
  • Model
  • View
  • Seed
  • Pivot
  • Resource
  • Scaffolding

Vediamo insieme un po’ la sintassi ed un esempio per ognuno di questi comandi.

Migration

Generators offre una marea di possibilità e di opzioni per creare al volo la migration più adatta alle proprie esigenze.

php artisan generate:migration create_comments_table

La scelta del nome non è del tutto casuale. Tramite “create_” e “_table” nel nome stiamo chiedendo a Generators di compilare per noi il file.

Ecco il risultato:

increments(‘id’);
$table->timestamps();
});
}

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

}

Tramite l’uso del flag “–fields”, tra l’altro, è possibile specificare queli campi inserire nella tabella.

php artisan generate:migration create_comments_table –fields=”title:string, body:text”

Il risultato stavolta sarà il seguente:

increments(‘id’);
$table->string(‘title’);
$table->text(‘body’);
$table->timestamps();
});
}

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

}

Generators permette inoltre di definire un po’ tutti gli aspetti di un singolo campo. Ecco alcuni esempi presi direttamente dalla documentazione che danno un’idea più precisa delle possibilità che ci vengono offerte:

–fields=”first:string, last:string”;
–fields=”age:integer, yob:date”;
–fields=”username:string:unique, age:integer:nullable”;
–fields=”name:string:default(‘John’), username:string(30):unique”;

C’è da dire, inoltre, che non si sta sempre a creare tabelle: le action da effettuare possono essere diverse. Generators tiene conto della cosa e permette:

  • Creazione (esempio: create_users_table);
  • Aggiunta di un campo (esempio: add_user_id_to_posts_table);
  • Rimozione di un campo (esempio: remove_user_id_from_posts_table);
  • Cancellazione (esempio: delete_users_table);

Model

Altrettanto semplice è la creazione di un model Eloquent. Non bisogna fare altro che usare il comando apposito

php artisan generate:model Comment

per avere, come risultato, un file Comment.php pronto:

increments(‘id’);
$table->integer(‘order_id’)->unsigned()->index();
$table->foreign(‘order_id’)->references(‘id’)->on(‘orders’)->onDelete(‘cascade’);
$table->integer(‘user_id’)->unsigned()->;index();
$table->foreign(‘user_id’)->references(‘id’)->on(‘users’)->onDelete(‘cascade’);
$table->timestamps();
});
}

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

}

Nota, inoltre, che la tabella viene creata correttamente con i nomi delle entità ordinati alfabeticamente.

Insomma, una comodità non indifferente. Adesso però facciamo un passo avanti, con la generazione di resource.

Resource

Il comando generate:resource, a differenza degli altri visti finora, farà una serie di azioni ben distinte:

  • Creazione di un model;
  • Generazione di varie view (index, show, create ed edit);
  • Creazione di un controller;
  • Creazione di una migration con relativo schema;
  • Generazione di un table seeder;

Immagina di avere la necessità di realizzare, al volo, tutto quello che riguarda l’elaborazione di una serie di post nella tua applicazione. Basta usare un comando come

php artisan generate:resource post –fields=”title:string, body:text”

per risparmiare un sacco di tempo e ritrovarti, neanche un secondo dopo, questi file già pronti:

  • app/models/Post.php
  • app/controllers/PostController.php
  • app/database/migrations/timestamp-create_post_table.php
  • app/database/seeds/PostsTableSeeder.php

Scaffolding

Il generatore di scaffolding è leggermente più sofisticato di generate:resource, dato che oltre a fare quello che il comando appena visto già fa provvede ad aggiungere un po’ di materiale aggiuntivo.

Torniamo all’esempio precedente, provando il comando:

php artisan generate:scaffold post

Il controller risultante PostController sarà simile al seguente:

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

Post::create($data);

return Redirect::route(‘posts.index’);
}

/**
* Display the specified post.
*
* @param int $id
* @return Response
*/
public function show($id)
{
$post = Post::findOrFail($id);

return View::make(‘posts.show’, compact(‘post’));
}

/**
* Show the form for editing the specified post.
*
* @param int $id
* @return Response
*/
public function edit($id)
{
$post = Post::find($id);

return View::make(‘posts.edit’, compact(‘post’));
}

/**
* Update the specified resource in storage.
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);

$validator = Validator::make($data = Input::all(), Post::$rules);

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

$post->update($data);

return Redirect::route(‘posts.index’);
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return Response
*/
public function destroy($id)
{
Post::destroy($id);

return Redirect::route(‘posts.index’);
}

}

Nota: ovviamente dovrai modificare il controller in base alle tue necessità… ma come inizio non è assolutamente indifferente.

Configurazione

Generators non si ferma qui. Potresti avere, infatti, la necessità di personalizzare i template che vengono usati in fase di generazione automatica. Tramite il comando

php artisan generate:publish-templates

i vari template usati da Generators vengono così copiati all’interno della cartella app/templates. Puoi anche specificare una directory di destinazione diversa, così:

php artisan generate:publish-templates –path=app/foo/bar/templates

Verrà copiato, inoltre, anche il file di configurazione che indica i vari path.

Ecco un esempio:

‘/Users/jeffreyway/Desktop/generators-testing/app/templates/model.txt’,

‘scaffold_model_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/scaffolding/model.txt’,

‘controller_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/controller.txt’,

‘scaffold_controller_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/scaffolding/controller.txt’,

‘migration_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/migration.txt’,

‘seed_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/seed.txt’,

‘view_template_path’ => ‘/Users/jeffreyway/Desktop/generators-testing/app/templates/view.txt’,

/*
|————————————————————————–
| Where the generated files will be saved…
|————————————————————————–
|
*/
‘model_target_path’ => app_path(‘models’),

‘controller_target_path’ => app_path(‘controllers’),

‘migration_target_path’ => app_path(‘database/migrations’),

‘seed_target_path’ => app_path(‘database/seeds’),

‘view_target_path’ => app_path(‘views’)

];

Anche qui ovviamente massima libertà: puoi adattare i percorsi alla struttura del tuo progetto come meglio credi.

Conclusioni

Generators di Jeffrey Way è davvero una bella svolta e può farti risparmiare un sacco di tempo. Anche io, personalmente, lo sto usando ed è diventato praticamente uno standard nei miei ultimi progetti. Sia che si parli di operazioni piccole e isolate (creazione di un model o di un controller), sia che si debba creare una resource da zero.

Usare Eloquent al di fuori di Laravel

0

Traduzione dell’articolo “Use Laravel’s Eloquent ORM outside of Laravel

Studiando Laravel ed il suo rapporto con i Database la prima cosa che mi viene in mente è la semplicità, quasi ridicola, dell’uso di Eloquent ORM. Un Object Relational Mapping, in breve, permette di mappare le entità da usare nella propria business logic, le loro relazioni e, come logica conseguenza, di lavorare in maniera agile scrivendo codice di qualità superiore.

Tante volte mi sono chiesto: “e se volessi usare Eloquent in altri progetti? Senza dover necessariamente installare Laravel?”

Non sempre, infatti, si ha la possibilità di usare Laravel in un progetto, magari già avviato. Puoi stare tranquillo: si può fare!

Laravel, come ben saprai, è modulare. Al momento della sua realizzazione è stato diviso in più pacchetti stand-alone da poter scaricare ed assemblare in base alle necessità. Uno di questi package è illuminate/database. Proprio quello di cui abbiamo bisogno!

Includerlo nel proprio progetto è molto semplice: innanzitutto hai bisogno di Composer. Crea quindi un file composer.json nella cartella del tuo progetto e aggiungici

Ora avvia il comando composer install in modo tale da installare le varie dipendenze specificate (nel nostro caso, Eloquent e il pacchetto illuminate/database, appunto).

Siamo ad un solo passo dal poter usare Eloquent: manca infatti un adeguato include delle varie dipendenze e l’inizializzazione dei parametri necessari (configurazione del database e boot di Eloquent).

Qui il codice di bootstrap.

addConnection(array(
‘driver’ => ‘mysql’,
‘host’ => ‘localhost’,
‘database’ => ‘test’,
‘username’ => ‘test’,
‘password’ => ‘l4m3p455w0rd!’,
‘charset’ => ‘utf8’,
‘collation’ => ‘utf8_unicode_ci’,
‘prefix’ => ”
));

$capsule->bootEloquent();

È fatta: non hai bisogno d’altro. Tutto quello che devi fare, da questo momento in avanti, è creare i tuoi model come hai sempre fatto e includere, dove necessario, il file di setup del database.

name = “The Best Book in the World”;
$book->author = “Ed Zynda”;

// Salviamo tutto sul database!
$book->save();

È fatta: non hai bisogno d’altro. Tutto quello che devi fare, da questo momento in avanti, è creare i tuoi model come hai sempre fatto e includere, dove necessario, il file di setup del database.

Insomma, niente di troppo complesso. Per saperne di più su cosa puoi fare con Eloquent, dai un’occhiata qui.

Astrarre il File System con Flysystem

0

Quante volte avere a che fare con il file system (soprattutto in progetti in cui la scalabilità è d’obbligo) può diventare fastidioso?

Flysystem è qui per risolvere il problema: un layer di astrazione che permette di lavorare allo stesso modo con i propri file in locale e in remoto (supporta FTP, Dropbox, Amazon S3 ed altri).

Layer di astrazione perché, per lavorare con un certo tipo di file system, basterà impostare adeguatamente alcune opzioni di configurazione. Nel momento in cui si avrà la necessità di fare uno switch basterà cambiare queste impostazioni: il codice del nostro progetto, invece, rimarrà invariato.

Interessante, vero?

La cosa ancora più interessante, inoltre, è scoprire che Flysystem cerca anche di uniformare tutti questi “tipi” diversi di file system. Non si parla solo di avere un API univoca: in situazioni in cui le cartelle non esistono (Amazon S3) alcune feature vengono addirittura emulate.

In questo articolo di overview vedremo velocemente come installarlo e come usarlo.

Installazione

Installare Flysystem è di una semplicità quasi disarmante.

Se usi composer basta aggiungere il nome del package tra le dipendenze del tuo progetto.

“require”: {
“league/flysystem”: “0.2.*”
}
}

Nulla, ovviamente, ti vieta di registrare una funzione di autoload nel caso non volessi usare alcun tool di dependency management.

spl_autoload_register(function($class) {
if ( ! substr($class, 0, 17) === ‘League\Flysystem’) {
return;
}

$location = DIR . ‘path/to/league/flysystem/src/’ . str_replace(‘\’, ‘/’, $class) . ‘.php’;

if (is_file($location)) {
require_once($location);
}
});

La scelta è fondamentalmente tua. Una volta effettuata l’installazione non c’è bisogno di fare altro: si può passare direttamente alla configurazione del file system che vuoi usare.

Configurazione

Per lavorare con i diversi tipi di file system si deve inizializzare la classe corrispondente. Al momento in cui scrivo le opzioni sono le seguenti:

  • File system locale;
  • AWS S3;
  • Rackspace;
  • Dropbox;
  • FTP;
  • SFTP;
  • Zip;
  • WebDAV;

Negli esempi che seguono useremo l’oggetto $filesystem. Una volta inizializzato si potrà usare allo stesso modo per ogni configruazione, come vedremo nel capitolo successivo.

File system locale

use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterLocal as Adapter;

$filesystem = new Filesystem(new Adapter(DIR.’/path/to/root’));

Amazon AWS S3

In questo caso viene usato l’AWS PHP SDK.

use AwsS3S3Client;
use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterAwsS3 as Adapter;

$client = S3Client::factory(array(
‘key’ => ‘[your key]’,
‘secret’ => ‘[your secret]’,
));

$filesystem = new Filesystem(new Adapter($client, ‘bucket-name’, ‘optional-prefix’));

Rackspace

Flysystem usa Rackspace tramite il package Rackspace PHP Opencloud.

use OpenCloudOpenStack;
use OpenCloudRackspace;
use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterRackspace as Adapter;

$client = new OpenStack(Rackspace::UK_IDENTITY_ENDPOINT, array(
‘username’ => ‘:username’,
‘password’ => ‘:password’,
));

$store = $client->objectStoreService(‘cloudFiles’, ‘LON’);
$container = $store->getContainer(‘flysystem’);

$filesystem = new Filesystem(new Adapter($container));

Dropbox

use DropboxClient;
use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterDropbox as Adapter;

$client = new Client($token, $appName);
$filesystem = new Filesystem(new Adapter($client, ‘optional/path/prefix’));

FTP

use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterFtp as Adapter;

$filesystem = new Filesystem(new Adapter(array(
‘host’ => ‘ftp.example.com’,
‘username’ => ‘username’,
‘password’ => ‘password’,

/** optional config settings */
‘port’ => 21,
‘root’ => ‘/path/to/root’,
‘passive’ => true,
‘ssl’ => true,
‘timeout’ => 30,
)));

SFTP

In questo caso viene usata la libreria PHPSecLib per la gestione delle varie operazioni.

use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterSftp as Adapter;

$filesystem = new Filesystem(new Adapter(array(
‘host’ => ‘example.com’,
‘port’ => 21,
‘username’ => ‘username’,
‘password’ => ‘password’,
‘privateKey’ => ‘path/to/or/contents/of/privatekey’,
‘root’ => ‘/path/to/root’,
‘timeout’ => 10,
)));

Zip

Flysystem permette anche di lavorare con un archivio zip. In questo caso la sintassi da usare è la seguente.

use LeagueFlysystemFilesystem;
use LeagueFlysystemAdapterZip as Adapter;

$filesystem = new Filesystem(new Adapter(DIR.’/path/to/archive.zip’));

WebDAV

In caso di bisogno Flysystem ti permette di lavorare anche con WebDAV. Il package SabreDAV si occupa della logica sottostante.

$client = new SabreDAVClient($settings);
$adapter = new LeagueFlysystemAdapterWebDav($client);
$filesystem = new LeagueFlysystemFilesystem($adapter);

Insomma: la scelta non è niente male. Ricorda, inoltre, che l’oggetto di partenza con cui lavorerai sarà sempre e solo $filesystem.

Flysystem in azione

Ora che abbiamo visto come installarlo e configurarlo, vediamo come usare Flysystem per tutte le operazioni più comuni che coinvolgono i file.

Cominciamo dai task più semplici: lettura di un file, creazione, modifica e cancellazione.

Leggere un file

$contents = $filesystem->read(‘filename.txt’);

Creare un file

$filesystem->write(‘filename.txt’, ‘contents’);

Modificare un file

$filesystem->update(‘filename.txt’, ‘new contents’);

Cancellare un file

$filesystem->delete(‘filename.txt’);

Nel caso non si voglia fare distinzione fra create e update (lasciando così l’onere del controllo al sistema) si può usare il metodo put.

$filesystem->put(‘filename.txt’, ‘contents’);

Tramite il metodo has si può verificare l’esistenza di un file.

$exists = $filesystem->has(‘filename.txt’);

Per rinominare un file, invece, il metodo da usare è rename.

$filesystem->rename(‘filename.txt’, ‘newname.txt’);

Creare una cartella

Creare una cartella è semplice: si usa createDir.

$filesystem->createDir(‘nested/directory’);

Flysystem, inoltre, crea automaticamente tutte le cartelle necessarie in caso stiamo scrivendo in corrispondenza di un path non esistente. Ad esempio, in caso d’uso di

$filesystem->write(‘path/to/filename.txt’, ‘contents’);

Le cartelle

  • path
  • path/to

verranno create automaticamente in caso non dovessero essere già presenti.

Cancellare una cartella

$filesystem->deleteDir(‘path/to/directory’);

Ottenere il mimetype

$mimetype = $filesystem->getMimetype(‘filename.txt’);

Ottenere i timestamp

$timestamp = $filesystem->getTimestamp(‘filename.txt’);

Ottenere la dimensione di un file

$size = $filesystem->getSize(‘filename.txt’);

Visibilità

Un altro aspetto molto interessante che si può gestire con Flysystem è la visibilità di un file, che di base consiste nell’astrazione dei vari permessi.

Un file può essere pubblico o privato. Vediamo innanzitutto come gestire la visibilità di un file al momento della sua creazione:

use LeagueFlysystemAdapterInterface;

$filesystem->write(‘db.backup’, $backup, [
‘visibility’ => AdapterInterface::VISIBILITY_PRIVATE),
]);

// oppure

$filesystem->write(‘db.backup’, $backup, [‘visibility’ => ‘private’]);

Il terzo parametro del metodo write accetta, nell’array, un elemento visibility il cui valore può essere una semplice stringa o un membro dell’interfaccia AdapterInterface. Ovviamente è possibile gestire senza problemi anche la visibilità di file già esistenti:

if ($filesystem->getVisibility(‘secret.txt’) === ‘private’) {
$filesystem->setVisibility(‘secret.txt’, ‘public’);
}

Come se non fosse già abbastanza puoi specificare il valore di visibilità da usare di default in fase di configurazione:

$filesystem = new LeagueFlysystemFilesystem($adapter, $cache, [
‘visibility’ => AdapterInterface::VISIBILITY_PRIVATE
]);

Lista dei contenuti di una cartella

Ottenere la lista dei file in una cartella è semplice:

$contents = $filemanager->listContents();

Il “$contents” risultante consisterà in un array multidimensionale, contenente tutti i metadati dei file conosciuti in quel momento. Di default riceverai in output il path ed il tipo del file. In base all’adapter usato, inoltre, potresti ricevere anche altre informazioni.

Ecco un esempio:

foreach ($contents as $object) {
echo $object[‘basename’].’ is located at’.$object[‘path’].’ and is a ‘.$object[‘type’];
}

Di default Flysystem non legge ricorsivamente all’interno delle sottocartelle. Se dovessi averne bisogno basta specificare true come secondo parametro aggiuntivo del metodo.

$contents = $flysystem->listContents(‘some/dir’, true);

Hai bisogno dei percorsi? Basta usare listPaths.

$paths = $filemanager->listPaths();

foreach ($paths as $path) {
echo $path;
}

Insomma, anche qui le opzioni sono tante.

Scrivere tramite stream

$stream = fopen(‘/path/to/database.backup’, ‘r+’);
$flysystem->writeStream(‘backups/’ . strftime(‘%G-%m-%d’) . ‘.backup’, $stream);

Scrivere tramite stream specificando direttamente la visibilità del file

$flysystem->writeStream(‘backups/’ . strftime(‘%G-%m-%d’) . ‘.backup’, $stream, ‘private’);

Update di uno stream con specifica dei contenuti

$flysystem->updateStream(‘backups/’ . strftime(‘%G-%m-%d’) . ‘.backup’, $stream);

Leggere da uno stream

$stream = $flysystem->readStream(‘something/is/here.ext’);
$contents = stream_get_contents($stream);
fclose($stream);

Creare o sovrascrivere un file usando uno stream

$putStream = tmpfile();
fwrite($putStream, $contents);
rewind($putStream);
$filesystem->putStream(‘somewhere/here.txt’, $putStream);
fclose($putStream);

Caching

Per incrementare ancora di più le performance, Flysystem ha un suo sistema di caching interno. In questo sistema tutti i vari dati e metadati vengono normalizzati e memorizzati, con il risultato di applicazioni più veloci e performanti nel tempo.

I metodi per lavorare con la cache, al momento, sono i seguenti:

  • Cache locale;
  • Memcached;
  • Redis;
  • Noop;

Per attivare la cache nel proprio adapter basta agire in fase di creazione dell’istanza dell’adapter stesso. Vediamo come, nel dettaglio.

Cache locale

use LeagueFlysystemFilesystem;
use LeagueFlysystemCacheMemory as Cache;

$filesystem = new Filesystem($adapter, new Cache);

Memcached

use LeagueFlysystemFilesystem;
use LeagueFlysystemCacheMemcached as Cache;

$memcached = new Memcached;
$memcached->addServer(‘localhost’, 11211);
$filesystem = new Filesystem($adapter, new Cache($memcached, ‘storageKey’, 300));

Redis

Per lavorare con Redis viene usato Predis.

use LeagueFlysystemFilesystem;
use LeagueFlysystemCachePredis as Cache;

$filesystem = new Filesystem($adapter, new Cache);

// Or supply a client
$client = new PredisClient;
$filesystem = new Filesystem($adapter, new Cache($client));

Noop

use LeagueFlysystemFilesystem;
use LeagueFlysystemCacheNoop as Cache;

$filesystem = new Filesystem($adapter, new Cache);

Conclusioni

Flysystem è sicuramente un ottimo package che promette molto bene. Se dovessi avere problemi nel suo uso o vuoi lasciare un feedback fai pure tra i commenti di seguito, facci sentire la tua!

Estendere Blade – Switch

0

Qualche giorno fa, lavorando ad alcuni progetti, mi sono ritrovato ad avere la necessità di usare uno switch in alcune view.

Ho dato uno sguardo alla documentazione ufficiale: niente. Ho fatto così una ricerca leggermente più approfondita, per trovare questa request di qualche mese fa. Con una risposta abbastanza lapidaria, Taylor liquidava temporaneamente la cosa con un “Not going to implement at this time”.

Più chiaro di così…

Certo, prima di continuare c’è qualche osservazione da fare: non sempre lo switch è sinonimo di codice elegante. Ricordando uno dei primi capitoli di “Laravel Testing Decoded“, di Jeffrey Way, quando ci sono troppi switch la cosa comincia a puzzare. C’è poco isolamento delle responsabilità, e così via.

Ad ogni modo nella vita di tutti i giorni, magari per una demo o per un qualcosa da realizzare velocemente, uno switch può sempre servire. Inoltre, da un punto di vista personale estetico, preferisco uno switch ad un if (else if, else if…), else.

Detto questo, vediamo come implementare lo switch per Blade.

Estendere Blade

Personalizzare Blade per i propri bisogni è davvero semplice. Come probabilmente già sai, Laravel “compila” le view realizzate con Blade in view elaborate e pronte ad essere usate.

Per creare un’estensione basta lavorare con il metodo Blade::extend().

Blade::extend(function($view, $compiler)
{
// la view contiene il codice, appunto, della view
return $view;
});

Il meccanismo di base è molto semplice. Il metodo extend prende in input una closure, che a sua volta presenta due argomenti: il primo, $view, è il codice della $view attualmente in fase di elaborazione. L’oggetto $compiler, invece, è il compilatore di Blade.

Su $view si può fare ogni tipo di operazione del caso, da un semplice str_replace _fino al _preg_replace.

La closure deve ritornare l’oggetto $view elaborato.

Lo switch, questo sconosciuto

La base di partenza per “costruire” il nostro switch è sicuramente la sua pagina sulla documentazione ufficiale. La sintassi che userò sarà quella alternativa:

Non c’è un motivo particolare per questa scelta: preferenza personale e nulla di più. La cosa si può fare tranquillamente anche con la sintassi più tradizionale, con le parentesi graffe.

Dando un’occhiata alla pagina sulla sintassi alternativa delle strutture di controllo, inoltre, veniamo a sapere che un costrutto del genere


Non funzionerebbe. Lo switch ed il suo primo case, infatti, devono trovarsi nello stesso blocco.

Occorre qualcosa del genere:

Un elemento da tenere a mente.

Scrittura del codice

L’obiettivo è creare un costrutto per Blade di questo tipo:

Value:

@switch($value)
@case(1)

Il valore è uno.

@break

@case(2)

Il valore è due.

@break

@default

Il valore non è uno, ma neanche due.

@break
@endswitch

I “pezzi” del nostro switch, quindi, saranno:
* Il blocco @switch (più il primo @case);
* Il singolo @case;
* Il @break;
* Il @default;
* L’@endswitch conclusivo;

Con le idee chiare in testa possiamo scrivere il codice:

Blade::extend(function($value, $compiler)
{
$value = preg_replace(‘/(?<=s)@switch((.))(s)@case((.*))(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@endswitch(?=s)/’, ‘‘, $value);

$value = preg_replace(‘/(?<=s)@case((.*))(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@default(?=s)/’, ‘‘, $value);
$value = preg_replace(‘/(?<=s)@break(?=s)/’, ‘‘, $value);

return $value;
});

Et voilà!

Per concludere, ecco alcune osservazioni riguardo possibili domande che ci si può porre:
* Non ho usato l’oggetto $compiler perché ho preferito lavorare direttamente sulla $view, senza passare per un altro oggetto. Ho voluto fare tutto tramite preg_replace, direttamente;
* I vari blocchi (s*) sono stati messi ai loro posti per rilevare eventuali spazi e ritorni a capo. In questo modo il codice rimane ordinato anche quando compilato da Blade a PHP vero e proprio;
* Ogni miglioramento è ben accetto. Se hai qualche suggerimento lascia pure un commento e ne parliamo insieme!

Edit: Grazie a kylekatarnis su Github per il feedback.

Elenco dei CMS creati con Laravel

0

Ti trovi così bene con Laravel che vorresti crearci un CMS? Beh, non sei il solo ad averci pensato.

In questo articolo riportiamo, brevemente, una lista di tutti i CMS finora creati con Laravel. Se ne conosci altri e vorresti suggerirli lascia un commento!

Stabili

In Sviluppo

Articolo in aggiornamento continuo. Ultimo aggiornamento 13/05/2014

Autenticazione su più tabelle con MultiAuth

0

Il sistema di autenticazione è uno dei componenti più interessanti (e potenti) di Laravel. Permette di gestire tutta la procedura di accesso e non solo, dato che presenta anche delle routine di recupero delle credenziali già pronte. Tanto da arrivare al livello, a volte, di dover scrivere solo due o tre righe di codice.

Anche un sistema del genere, però, ha i suoi limiti: qualche giorno fa, su un forum, un ragazzo chiedeva informazioni su come usare più tabelle per memorizzare i dati degli utenti. Una tabella per gli amministratori, una tabella per gli utenti, e così via.

Oggi non mi metterò a pontificare su quale pratica è giusta e quale è sbagliata: sappiamo bene che le necessità cambiano di progetto in progetto.

Quello che faremo in questo articolo sarà scoprire, insieme, il package ollieread/multiauth.

Come spiega anche l’autore del package, non si tratta di un rimpiazzo al 100%: è più un qualcosa che si frappone nel mezzo, un layer, o per essere più precisi una sorta di Factory Class.

Permette quindi di usare diverse accoppiate model/tabella. Come se non bastasse, inoltre, permette di associare ad ognuna di queste combinazioni un driver diverso. Quindi, per assurdo, se avessimo gli amministratori su SQL Server e gli utenti su MySQL… beh, nessun problema.

Vediamo innanzitutto come aggiungerlo al nostro progetto.

Installazione

Installare multiauth è davvero semplice: basta procedere con Composer.

Aggiungiamo la seguente dipendenza al nostro progetto:

“require”: {
“ollieread/multiauth”: “dev-master”
}

Al momento in cui scrivo la versione stable è la 3.2.3. Aggiorniamo il nostro progetto tramite _composer update, quindi provvediamo a sostituire l’AuthServiceProvider con

“OlliereadMultiauthMultiauthServiceProvider”

nel file app/config/app.php, tra gli elementi dell’array providers.

Dopodiché passiamo al file app/config/auth.php. Questa è la configurazione di default che dovresti già trovare:

return array(

‘driver’ => ‘eloquent’,

‘model’ => ‘User’,

‘table’ => ‘users’,

‘reminder’ => array(

‘email’ => ‘emails.auth.reminder’,

‘table’ => ‘password_reminders’,

‘expire’ => 60,

),

);

Ovviamente non ci serve più: deve essere rimpiazzata con quella di cui abbiamo bisogno. Supponiamo quindi di avere la necessità di due tipologie diverse di utenti:
* Utenti (User);
* Amministratori (Administrator);

Ecco quale sarà il contenuto del file di configurazione risultante:

return array(

‘multi’ => array(
‘administrator’ => array(
‘driver’ => ‘eloquent’,
‘model’ => ‘Account’
),
‘user’ => array(
‘driver’ => ‘eloquent’,
‘model’ => ‘Administrator’
)
),

‘reminder’ => array(

‘email’ => ‘emails.auth.reminder’,

‘table’ => ‘password_reminders’,

‘expire’ => 60,

),

);

Inutile dire che puoi aggiungere tutte le tipologie di utenti di cui hai bisogno.

Procedura di Autenticazione

L’uso del package è semplicissimo, considerando che consiste fondamentalmente nell’aggiunta di un’istruzione in più in fase di chiamata di qualsiasi metodo.

Ad esempio, se fino ad ora nel nostro codice abbiamo un’istruzione quale

Auth::attempt(array(
‘email’ => $attributes[‘email’],
‘password’ => $attributes[‘password’],
));

adesso non dobbiamo fare altro che aggiungere, subito dopo “Auth::“, il nome dell’entità di cui abbiamo bisogno.

Vediamo i due esempi riprendendo in considerazione le due entità viste prima.

Auth::user()->attempt(array(
‘email’ => $attributes[‘email’],
‘password’ => $attributes[‘password’],
));

Auth::administrator()->attempt(array(
‘email’ => $attributes[‘email’],
‘password’ => $attributes[‘password’],
));

Anche le altre istruzioni rimangono identiche, seguendo la stessa filosofia:

Auth::user()->check();
Auth::administrator()->check();

L’unica eccezione riguarda il metodo da usare per ottenere i dati dell’utente loggato attualmente: per evitare, infatti, la ripetizione

Auth::user()->user();

è stato introdotto il metodo “get()“, più generico, comodo e meno propenso all’ambiguità.

Auth::user()->get();
Auth::administrator()->get();

Davvero molto interessante, inoltre, è il metodo impersonate(), che consente ad un utente di un’altra categoria di “simulare” l’accesso con un’altra tipologia di utente.

Auth::administrator()->impersonate(‘user’, 1, true);

In questo caso, l’amministratore corrente sta “impersonando” l’utente dall’id uguale ad 1. Il terzo parametro è un flag “remember me” per ricordare l’accesso. Di default è impostato su false.

Password Reminder

Non solo login: il package di autenticazione di Laravel, infatti, include anche tutta una serie di utility e metodi dedicati al recovery delle credenziali utente. Chiaramente, multiauth non poteva rimanere a piedi sotto questo punto di vista.

Configurazione

Nel caso decidessimo di lavorare anche con questo insieme di funzionalità, la prima cosa da fare è sostituire il _ReminderServiceProvider _con il seguente:

OlliereadMultiauthRemindersReminderServiceProvider

Provvediamo quindi ad installare la tabella dei reminder tramite Artisan:

php artisan multiauth:reminders-table

… e siamo pronti!

**Nota: **al momento in cui scrivo non esiste l’equivalente del comando reminder-controller. Lo sviluppatore ha accennato, tuttavia, di volerlo implementare in un futuro prossimo.

Utilizzo

L’utilizzo del package in tal senso è praticamente lo stesso, seguendo la stessa procedura vista prima per l’accesso ed il check.

L’invio del reminder va implementato con il metodo “remind()”, appunto:

Password::administrator()->remind(Input::only(‘email’), function($message) {
$message->subject(‘Recupero Credenziali’);
});

ed il reset con il metodo omonimo.

Password::administrator()->reset($credentials, function($user, $password) {
$user->password = Hash::make($password);
$user->save();
});

Va ricordato comunque che l’url generato in questo caso dovrà essere diverso: l’istruzione da inserire nella view del reminder sarà la seguente.

{{ URL::to(‘password/reset’, array($type, $token)) }}

Tale istruzione genererà un link simile al seguente:

http://myhost.dev/password/reset/administrator/27eb8fe5fe666b3b8d0521156bbf53266dbca572

Il penultimo segmento indica il tipo di utente, l’ultimo il token da usare.

Tale URL corrisponderà ovviamente ad una route specifica di questo genere:

Route::any(‘/password/reset/{type}/{token}’, ‘Controller@method’);

Note sui Filtri

Come giustamente lo sviluppatore ricorda, nel file dei filtri _filters.php _ci sono dei filtri che fanno uso del metodo Auth::guest(). Ricorda di modificarli adeguatamente e, se ne avessi bisogno, trovi un gist all’indirizzo https://gist.github.com/ollieread/8303638.

Conclusioni

Non nego di aver usato un paio di volte questo package che mi ha semplificato enormemente la vita. Potrebbe servire anche a te, magari, e ho pensato di scriverci su un articolo. Tu che ne pensi, potrebbe esserti utile?

Per qualsiasi feedback non esitare a commentare!