Fast Workflow in Laravel With Custom Generators
Build Status
This Laravel package provides a variety of generators to speed up your development process. These generators include:
generate:model
generate:view
generate:controller
generate:seed
generate:migration
generate:pivot
generate:resource
generate:scaffold
Installation
Want a 5-minute video overview?
Laravel 5
If you're using Laravel 5, then use this package instead.
Laravel 4.2 and Below
Begin by installing this package through Composer. Edit your project's composer.json file to require way/generators.
"require-dev": {
"way/generators": "~2.0"
}
Next, update Composer from the Terminal:
composer update --dev
Once this operation completes, the final step is to add the service provider. Open app/config/app.php, and add a new item to the providers array.
'Way\Generators\GeneratorsServiceProvider'
That's it! You're all set to go. Run the artisan command from the Terminal to see the new generate commands.
php artisan
Next, update Composer from the Terminal:
composer update --dev
Once this operation completes, the final step is to add the service provider. Open config/app.php, and add a new item to the providers array.
'Way\Generators\GeneratorsServiceProvider'
That's it! You're all set to go. Run the artisan command from the Terminal to see the new generate commands.
php artisan
Usage
Think of generators as an easy way to speed up your workflow. Rather than opening the models directory, creating a new file, saving it, and adding the class, you can simply run a single generate command.
Migrations
Models
Views
Seeds
Pivot
Resources
Scaffolding
Configuration
Migrations
Laravel offers a migration generator, but it stops just short of creating the schema (or the fields for the table). Let's review a couple examples, using generate:migration.
php artisan generate:migration create_posts_table
If we don't specify the fields option, the following file will be created within app/database/migrations.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('posts');
}
}
Notice that the generator is smart enough to detect that you're trying to create a table. When naming your migrations, make them as descriptive as possible. The migration generator will detect the first word in your migration name and do its best to determine how to proceed. As such, for create_posts_table, the keyword is "create," which means that we should prepare the necessary schema to create a table.
If you instead use a migration name along the lines of add_user_id_to_posts_table, in that case, the keyword is "add," signaling that we intend to add rows to an existing table. Let's see what that generates.
php artisan generate:migration add_user_id_to_posts_table
This will prepare the following boilerplate:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddUserIdToPostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function(Blueprint $table) {
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function(Blueprint $table) {
});
}
}
Notice how, this time, we're not doing Schema::create.
Keywords
When writing migration names, use the following keywords to provide hints for the generator.
create or make (create_users_table)
add or insert (add_user_id_to_posts_table)
remove (remove_user_id_from_posts_table)
delete or drop (delete_users_table)
Generating Schema
This is pretty nice, but let's take things a step further and also generate the schema, using the fields option.
php artisan generate:migration create_posts_table --fields="title:string, body:text"
Before we decipher this new option, let's see the output:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('posts');
}
}
Nice! A few things to notice here:
The generator will automatically set the id as the primary key.
It parsed the fields options, and added those fields.
The drop method is smart enough to realize that, in reverse, the table should be dropped entirely.
To declare fields, use a comma+space-separated list of key:value:option sets, where key is the name of the field, value is the column type, and option is a way to specify indexes and such, like unique or nullable. Here are some examples:
--fields="first:string, last:string"
--fields="age:integer, yob:date"
--fields="username:string:unique, age:integer:nullable"
--fields="name:string:default('John Doe'), bio:text:nullable"
--fields="username:string(30):unique, age:integer:nullable:default(18)"
Please make note of the last example, where we specify a character limit: string(30). This will produce $table->string('username', 30)->unique();
It is possible to destroy the table by issuing:
php artisan generate:migration delete_posts_table
As a final demonstration, let's run a migration to remove the completed field from a tasks table.
php artisan generate:migration remove_completed_from_tasks_table --fields="completed:boolean"
This time, as we're using the "remove" keyword, the generator understands that it should drop a column, and add it back in the down() method.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class RemoveCompletedFromTasksTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tasks', function(Blueprint $table) {
$table->dropColumn('completed');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tasks', function(Blueprint $table) {
$table->boolean('completed');
});
}
}
Models
php artisan generate:model Post
This will create the file, app/models/Post.php and insert the following boilerplate:
<?php
class Post extends \Eloquent {
}
Views
The view generator is fairly simple.
php artisan generate:view admin.reports.index
This command will create an empty view, /app/views/admin/reports/index.blade.php. If the provided directory tree does not exist, it will be created for you.
Seeds
Laravel provides us with a flexible way to seed new tables.
php artisan generate:seed users
Set the argument to the name of the table that you'd like a seed file for. This will generate app/database/seeds/UsersTableSeeder.php and populate it with:
<?php
// Composer: "fzaninotto/faker": "v1.3.0"
use Faker\Factory as Faker;
class UsersTableSeeder extends Seeder {
public function run()
{
$faker = Faker::create();
foreach(range(1, 10) as $index)
{
User::create([
]);
}
}
}
This will give you a basic bit of boilerplate, using the popular Faker library. This is a nice way to seed your DB tables. Don't forget to pull in Faker through Composer!
Pivot
When you require a new pivot table, the generate:pivot table expedites the process of creating the appropriate migration.
Simply pass the name of the two tables that require a joining pivot table. For orders and users, you might do:
php artisan generate:pivot orders users
This will create the following migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateOrderUserTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('order_user', function(Blueprint $table) {
$table->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');
}
}
Notice that it correctly sets the table name according to your two provided tables, in alphabetical order. Now, run php artisan migrate to create your pivot table!
Resources
The generate:resource command will do a number of things for you:
Generate a model
Generate index, show, create, and edit views
Generate a controller
Generate a migration with schema
Generate a table seeder
Migrate the database
When triggering this command, you'll be asked to confirm each of these actions. That way, you can tailor the generation to what you specifically require.
Example
Imagine that you need to build a way to display posts. While you could manually create a controller, create a model, create a migration and populate it with the schema, and then create a table seeder...why not let the generator do that?
php artisan generate:resource post --fields="title:string, body:text"
If you say yes to each confirmation, this single command will give you boilerplate for:
app/models/Post.php
app/controllers/PostsController.php
app/database/migrations/timestamp-create_posts_table.php (including the schema)
app/database/seeds/PostsTableSeeder.php
Scaffolding
The scaffolding generator is similar to generate:resource, except it will add some beginning boilerplate to these files, as a convenience.
For instance, when running generate:scaffold post, your controller boilerplate will be:
<?php
class PostsController extends \BaseController {
/**
* Display a listing of posts
*
* @return Response
*/
public function index()
{
$posts = Post::all();
return View::make('posts.index', compact('posts'));
}
/**
* Show the form for creating a new post
*
* @return Response
*/
public function create()
{
return View::make('posts.create');
}
/**
* Store a newly created post in storage.
*
* @return Response
*/
public function store()
{
$validator = Validator::make($data = Input::all(), Post::$rules);
if ($validator->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');
}
}
Please note that you're encouraged to modify this generated controller. It simply provides a starting point.
Configuration
You may want to modify your templates - how the generated files are formatted. To allow for this, you need to publish the templates that, behind the scenes, the generators will reference.
php artisan generate:publish-templates
This will copy all templates to your app/templates directory. You can modify these however you wish to fit your desired formatting. If you'd prefer a different directory:
php artisan generate:publish-templates --path=app/foo/bar/templates
When you run the generate:publish-templates command, it will also publish the configuration to app/config/packages/way/generators/config/config.php. This file will look somewhat like:
<?php
return [
/*
|--------------------------------------------------------------------------
| Where the templates for the generators are stored...
|--------------------------------------------------------------------------
|
*/
'model_template_path' => '/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')
];
Also, while you're in this file, note that you can also update the default target directory for each generator.
Shortcuts
Because you'll likely type these commands over and over, it makes sense to create aliases.
# Generator Stuff
alias g:m="php artisan generate:model"
alias g:c="php artisan generate:controller"
alias g:v="php artisan generate:view"
alias g:s="php artisan generate:seed"
alias g:mig="php artisan generate:migration"
alias g:r="php artisan generate:resource"
These can be stored in, for example, your ~/.bash_profile or ~/.bashrc files.
way/generators
Re: way/generators
https://github.com/laracasts/Laravel-5- ... s-Extended
Laravel 5 Extended Generators
Build Status
If you're familiar with my Laravel 4 Generators, then this is basically the same thing - just upgraded for Laravel 5.
L5 includes a bunch of generators out of the box, so this package only needs to add a few things, like:
make:migration:schema
make:migration:pivot
make:seed
With one or two more to come.
Usage
Step 1: Install Through Composer
composer require laracasts/generators --dev
Step 2: Add the Service Provider
You'll only want to use these generators for local development, so you don't want to update the production providers array in config/app.php. Instead, add the provider in app/Providers/AppServiceProvider.php, like so:
public function register()
{
if ($this->app->environment() == 'local') {
$this->app->register('Laracasts\Generators\GeneratorsServiceProvider');
}
}
Step 3: Run Artisan!
You're all set. Run php artisan from the console, and you'll see the new commands in the make:* namespace section.
Examples
Migrations With Schema
Pivot Tables
Database Seeders
Migrations With Schema
php artisan make:migration:schema create_users_table --schema="username:string, email:string:unique"
Notice the format that we use, when declaring any applicable schema: a comma-separate list...
COLUMN_NAME:COLUMN_TYPE
So any of these will do:
username:string
body:text
age:integer
published_at:date
excerpt:text:nullable
email:string:unique:default('foo@example.com')
Using the schema from earlier...
--schema="username:string, email:string:unique"
...this will give you:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function(Blueprint $table) {
$table->increments('id');
$table->string('username');
$table->string('email')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
When generating migrations with schema, the name of your migration (like, "create_users_table") matters. We use it to figure out what you're trying to accomplish. In this case, we began with the "create" keyword, which signals that we want to create a new table.
Alternatively, we can use the "remove" or "add" keywords, and the generated boilerplate will adapt, as needed. Let's create a migration to remove a column.
php artisan make:migration:schema remove_user_id_from_posts_table --schema="user_id:integer"
Now, notice that we're using the correct Schema methods.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveUserIdFromPostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function(Blueprint $table) {
$table->dropColumn('user_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function(Blueprint $table) {
$table->integer('user_id');
});
}
}
Here's a few other examples of commands that you might write:
php artisan make:migration:schema create_posts_table
php artisan make:migration:schema create_posts_table --schema="title:string, body:text, excerpt:string:nullable"
php artisan make:migration:schema remove_excerpt_from_posts_table --schema="excerpt:string:nullable"
Now, when you create a migration, you typically want a model to go with it, right? By default, we'll go ahead and create an Eloquent model to go with your migration. This means, if you run, say:
php artisan make:migration:schema create_dogs_table --schema="name:string"
You'll get a migration, populated with the schema...but you'll also get an Eloquent model at app/Dog.php. Naturally, you can opt out of this by adding the --model=false flag/option.
Foreign Constraints
There's also a secret bit of sugar for when you need to generate foreign constraints. Imagine that you have a posts table, where each post belongs to a user. Let's try:
php artisan make:migration:schema create_posts_table --schema="user_id:integer:foreign, title:string, body:text"
Notice that "foreign" option (user_id:integer:foreign)? That's special. It signals that user_id` should receive a foreign constraint. Following conventions, this will give us:
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
As such, for that full command, our schema should look like so:
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('title');
$table->text('body');
$table->timestamps();
);
Neato.
Pivot Tables
So you need a migration to setup a pivot table in your database? Easy. We can scaffold the whole class with a single command.
php artisan make:migration:pivot tags posts
Here we pass, in any order, the names of the two tables that we need a joining/pivot table for. This will give you:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostTagPivotTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('post_tag', function(Blueprint $table)
{
$table->integer('post_id')->unsigned()->index();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->index();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('post_tag');
}
}
Notice that the naming conventions are being followed here, regardless of what order you pass the table names.
Database Seeders
php artisan make:seed posts
This one is fairly basic. It just gives you a quick seeder class in the "database/seeds" folder.
<?php
use Illuminate\Database\Seeder;
// composer require laracasts/testdummy
use Laracasts\TestDummy\Factory as TestDummy;
class PostsTableSeeder extends Seeder {
public function run()
{
// TestDummy::times(20)->create('App\Post');
}
}
Laravel 5 Extended Generators
Build Status
If you're familiar with my Laravel 4 Generators, then this is basically the same thing - just upgraded for Laravel 5.
L5 includes a bunch of generators out of the box, so this package only needs to add a few things, like:
make:migration:schema
make:migration:pivot
make:seed
With one or two more to come.
Usage
Step 1: Install Through Composer
composer require laracasts/generators --dev
Step 2: Add the Service Provider
You'll only want to use these generators for local development, so you don't want to update the production providers array in config/app.php. Instead, add the provider in app/Providers/AppServiceProvider.php, like so:
public function register()
{
if ($this->app->environment() == 'local') {
$this->app->register('Laracasts\Generators\GeneratorsServiceProvider');
}
}
Step 3: Run Artisan!
You're all set. Run php artisan from the console, and you'll see the new commands in the make:* namespace section.
Examples
Migrations With Schema
Pivot Tables
Database Seeders
Migrations With Schema
php artisan make:migration:schema create_users_table --schema="username:string, email:string:unique"
Notice the format that we use, when declaring any applicable schema: a comma-separate list...
COLUMN_NAME:COLUMN_TYPE
So any of these will do:
username:string
body:text
age:integer
published_at:date
excerpt:text:nullable
email:string:unique:default('foo@example.com')
Using the schema from earlier...
--schema="username:string, email:string:unique"
...this will give you:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function(Blueprint $table) {
$table->increments('id');
$table->string('username');
$table->string('email')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
When generating migrations with schema, the name of your migration (like, "create_users_table") matters. We use it to figure out what you're trying to accomplish. In this case, we began with the "create" keyword, which signals that we want to create a new table.
Alternatively, we can use the "remove" or "add" keywords, and the generated boilerplate will adapt, as needed. Let's create a migration to remove a column.
php artisan make:migration:schema remove_user_id_from_posts_table --schema="user_id:integer"
Now, notice that we're using the correct Schema methods.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveUserIdFromPostsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function(Blueprint $table) {
$table->dropColumn('user_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function(Blueprint $table) {
$table->integer('user_id');
});
}
}
Here's a few other examples of commands that you might write:
php artisan make:migration:schema create_posts_table
php artisan make:migration:schema create_posts_table --schema="title:string, body:text, excerpt:string:nullable"
php artisan make:migration:schema remove_excerpt_from_posts_table --schema="excerpt:string:nullable"
Now, when you create a migration, you typically want a model to go with it, right? By default, we'll go ahead and create an Eloquent model to go with your migration. This means, if you run, say:
php artisan make:migration:schema create_dogs_table --schema="name:string"
You'll get a migration, populated with the schema...but you'll also get an Eloquent model at app/Dog.php. Naturally, you can opt out of this by adding the --model=false flag/option.
Foreign Constraints
There's also a secret bit of sugar for when you need to generate foreign constraints. Imagine that you have a posts table, where each post belongs to a user. Let's try:
php artisan make:migration:schema create_posts_table --schema="user_id:integer:foreign, title:string, body:text"
Notice that "foreign" option (user_id:integer:foreign)? That's special. It signals that user_id` should receive a foreign constraint. Following conventions, this will give us:
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
As such, for that full command, our schema should look like so:
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('title');
$table->text('body');
$table->timestamps();
);
Neato.
Pivot Tables
So you need a migration to setup a pivot table in your database? Easy. We can scaffold the whole class with a single command.
php artisan make:migration:pivot tags posts
Here we pass, in any order, the names of the two tables that we need a joining/pivot table for. This will give you:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostTagPivotTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('post_tag', function(Blueprint $table)
{
$table->integer('post_id')->unsigned()->index();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->integer('tag_id')->unsigned()->index();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('post_tag');
}
}
Notice that the naming conventions are being followed here, regardless of what order you pass the table names.
Database Seeders
php artisan make:seed posts
This one is fairly basic. It just gives you a quick seeder class in the "database/seeds" folder.
<?php
use Illuminate\Database\Seeder;
// composer require laracasts/testdummy
use Laracasts\TestDummy\Factory as TestDummy;
class PostsTableSeeder extends Seeder {
public function run()
{
// TestDummy::times(20)->create('App\Post');
}
}