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.