# Lumen generators [![Build Status](https://travis-ci.org/webNeat/lumen-generators.svg?branch=master)](https://travis-ci.org/webNeat/lumen-generators) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/webNeat/lumen-generators/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/webNeat/lumen-generators/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/838624c3-208d-4ba5-84aa-3afc76b093bb/mini.png)](https://insight.sensiolabs.com/projects/838624c3-208d-4ba5-84aa-3afc76b093bb) [![License](https://poser.pugx.org/laravel/framework/license.svg)](https://github.com/webNeat/lumen-generators/blob/master/LICENSE) A collection of generators for [Lumen](http://lumen.laravel.com) and [Laravel 5](http://laravel.com/). ## Contents - [Why ?](#why) - [Installation](#installation) - [Quick Usage](#quick-usage) - [Detailed Usage](#detailed-usage) - [Model Generator](#model-generator) - [Migration Generator](#migration-generator) - [Pivot Table Generator](#pivot-table-generator) (Since version 1.1.0) - [Controller Generator](#controller-generator) - [Routes Generator](#routes-generator) - [Resource Generator](#resource-generator) - [Multiple Resources From File](#multiple-resources-from-file) - [Testing](#testing) - [Development Notes](#development-notes) - [Contributing](#contributing) ## Why ? I installed Lumen and wanted to use it to create a REST API (since this is the main usage of Lumen). But I didn't find commands which will speed up my workflow. That's why I created this package and included useful commands to build a RESTful API. This packages was mainly built to be used with Lumen, but it should work fine with Laravel 5 too. ## Installation Add the generators package to your composer.json by running the command: `composer require wn/lumen-generators` Then add the service provider in the file `app/Providers/AppServiceProvider.php`like the following: ```php public function register() { if ($this->app->environment() == 'local') { $this->app->register('Wn\Generators\CommandsServiceProvider'); } } ``` **Don't forget to include the application service provider on your `bootstrap/app.php` and to enable Eloquent and Facades if you are using Lumen** If you run the command `php artisan list` you will see the list of added commands: ``` wn:controller Generates RESTful controller using the RESTActions trait wn:controller:rest-actions Generates REST actions trait to use into controllers wn:migration Generates a migration to create a table with schema wn:model Generates a model class for a RESTfull resource wn:pivot-table Generates creation migration for a pivot table wn:resource Generates a model, migration, controller and routes for RESTful resource wn:resources Generates multiple resources from a file wn:route Generates RESTful routes. ``` ## Quick Usage To generate a RESTful resource for your application (model, migration, controller and RESTful routes), you simply need to run one single command. For example: ``` php artisan wn:resource task "name;string;required;fillable project_id;integer:unsigned;numeric;fillable,key due;date;;date" --add=timestamps --belongs-to=project ``` will generate these files: **app/Task.php** ```php "required", "project_id" => "numeric", ]; public function project() { return $this->belongsTo("App\Project"); } } ``` **app/Http/Controllers/RESTActions.php** ```php 200, 'created' => 201, 'removed' => 204, 'not_valid' => 400, 'not_found' => 404, 'conflict' => 409, 'permissions' => 401 ]; public function all() { $m = self::MODEL; return $this->respond('done', $m::all()); } public function get($id) { $m = self::MODEL; $model = $m::find($id); if(is_null($model)){ return $this->respond('not_found'); } return $this->respond('done', $model); } public function add(Request $request) { $m = self::MODEL; $this->validate($request, $m::$rules); return $this->respond('created', $m::create($request->all())); } public function put(Request $request, $id) { $m = self::MODEL; $this->validate($request, $m::$rules); $model = $m::find($id); if(is_null($model)){ return $this->respond('not_found'); } $model->update($request->all()); return $this->respond('done', $model); } public function remove($id) { $m = self::MODEL; if(is_null($m::find($id))){ return $this->respond('not_found'); } $m::destroy($id); return $this->respond('removed'); } protected function respond($status, $data = []) { return response()->json($data, $this->statusCodes[$status]); } } ``` **app/Http/Controllers/TasksController.php** ```php get('task', 'TasksController@all'); $app->get('task/{id}', 'TasksController@get'); $app->post('task', 'TasksController@add'); $app->put('task/{id}', 'TasksController@put'); $app->delete('task/{id}', 'TasksController@remove'); ``` **database/migrations/date_time_create_tasks.php** ```php increments('id'); $table->string('name'); $table->integer('project_id')->unsigned(); $table->date('due'); $table->foreign('project_id') ->references('id') ->on('projects'); $table->timestamps(); }); } public function down() { Schema::drop('tasks'); } } ``` Now simply run the migration and you are ready to go. More then that, you can generate multiple resources with only one command ! [Click here to see an example](#multiple-resources-from-file) ## Detailed Usage ### Model Generator The `wn:model` command is used to generate a model class based on Eloquent. It has the following syntax: ``` wn:model name [--fillable=...] [--dates=...] [--has-many=...] [--has-one=...] [--belongs-to=...] [--belongs-to-many=...] [--rules=...] [--timestamps=false] [--path=...] [--soft-deletes=true] [--force=true] ``` - **name**: the name of the model. `php artisan wn:model Task` generates the following: ```php hasMany("Tests\Tmp\Account"); } public function owner() { return $this->belongsTo("App\User"); } public function number() { return $this->hasOne("Tests\Tmp\Phone"); } public function tags() { return $this->belongsToMany("Tests\Tmp\Tag")->withTimestamps(); } ``` - **--rules**: specifies the validation rules of the model's fields. The syntax is `field1=rules1 field2=rules2 ...`. ``` php artisan wn:model TestingModel --rules="name=required age=integer|min:13 email=email|unique:users,email_address"` ``` gives: ```php // ... public static $rules = [ "name" => "required", "age" => "integer|min:13", "email" => "email|unique:users,email_address", ]; ``` - **--timestamps**: Enables timestamps on the model. Giving `--timestamps=false` will add `public $timestamps = false;` to the generated model. The default value is `true`. - **--soft-deletes**: Adds `Illuminate\Database\Eloquent\SoftDeletes` trait to the model. This is disabled by default. - **--force**: tells the generator to override the existing file. By default, if the model file already exists, it will not be overriden and the output will be something like: ``` TestingModel model already exists; use --force option to override it ! ``` ### Migration Generator The `wn:migration` command is used to generate a migration to create a table with schema. It has the following syntax: ``` wn:migration table [--schema=...] [--add=...] [--keys=...] [--force=true] [--file=...] ``` - **table**: the name of the table to create. - **--file**: The migration file name (to speicify only for testing purpose). By default the name follows the patern `date_time_create_tableName_table.php`. - **--schema**: the schema of the table using the syntax `field1:type.arg1,ag2:modifier1:modifier2.. field2:...`. The `type` could be `text`, `string.50`, `decimal.5,2` for example. Modifiers can be `unique` or `nullable` for example. [See documentation](http://laravel.com/docs/5.1/migrations#creating-columns) for the list of available types and modifiers. ``` php artisan wn:migration tasks --schema="amount:decimal.5,2:after.'size':default.8 title:string:nullable" ``` gives: ```php increments('id'); $table->decimal('amount', 5, 2)->after('size')->default(8); $table->string('title')->nullable(); // Constraints declaration }); } public function down() { Schema::drop('tasks'); } } ``` - **--add**: Specifies additional columns like `timestamps`, `softDeletes`, `rememberToken` and `nullableTimestamps`. - **--keys**: the foreign keys of the table following the syntax `field:column:table:on_delete:on_update ...`. The `column` is optional ("id" by default). The `table` is optional if the field follows the naming convention `singular_table_name_id`. `on_delete` and `on_update` are optional too. ``` php artisan wn:migration tasks --keys="category_type_id user_id:identifier:members:cascade" ``` gives: ```php //... $table->foreign('category_type_id') ->references('id') ->on('category_types'); $table->foreign('user_id') ->references('identifier') ->on('members') ->onDelete('cascade'); ``` ### Pivot Table Generator The `wn:pivot-table` command is used to generate a migration to create a pivot table between two models. It has the following syntax: ``` wn:pivot-table model1 model2 [--add=...] [--force=true] [--file=...] ``` - **model1** and **model2**: names of the two models (or the two tables if the models don't follow the naming conventions) - **--add**: Specifies additional columns like `timestamps`, `softDeletes`, `rememberToken` and `nullableTimestamps`. - **--file**: The migration file name. By default the name follows the patern `date_time_create_table_name.php`. ``` php artisan wn:pivot-table Tag Project --add=timestamps ``` gives: ```php increments('id'); $table->integer('project_id')->unsigned()->index(); $table->integer('tag_id')->unsigned()->index(); $table->foreign('project_id') ->references('id') ->on('projects'); $table->foreign('tag_id') ->references('id') ->on('tags'); $table->timestamps(); }); } public function down() { Schema::drop('project_tag'); } } ``` ### Controller Generator There are two commands for controllers. The first one is `wn:controller:rest-actions` which generates a trait used by all generated controllers. This trait includes the following methods: - `all()` : returns all the model entries as JSON. - `get($id)` : returns a specific model by id as JSON. - `add(Request $request)` : adds a new model or returns validation errors as JSON. - `put(Request $request, $id)` : updates a model or returns validation errors as JSON. - `remove($id)` : removes an entry by id. Note that the trait doesn't use the common used methods on Laravel (like index, store, ...) to avoid conflicts. Which enables you to use this trait with controllers you already have in your application. The second command is `wn:controller` which actually generates the controller. The syntax of this command is `wn:controller model [--no-routes] [--force=true]`. - **model**: Name of the model (with namespace if not `App`). - **--no-routes**: Since routes are generated by default for the controller, this option is used to tell the generator "do not generate routes !". - **--force**: tells the generator to override the existing file. - **--laravel**: create Laravel style routes `php artisan wn:controller Task --no-routes` gives: ```php get('project-type', 'ProjectTypesController@all'); $app->get('project-type/{id}', 'ProjectTypesController@get'); $app->post('project-type', 'ProjectTypesController@add'); $app->put('project-type/{id}', 'ProjectTypesController@put'); $app->delete('project-type/{id}', 'ProjectTypesController@remove'); ``` `php artisan wn:route project-type --laravel` adds the following routes: ```php Route::get('project-type', 'ProjectTypesController@all'); Route::get('project-type/{id}', 'ProjectTypesController@get'); Route::post('project-type', 'ProjectTypesController@add'); Route::put('project-type/{id}', 'ProjectTypesController@put'); Route::delete('project-type/{id}', 'ProjectTypesController@remove'); ``` ### Resource Generator The `wn:resource` command makes it very easy to generate a RESTful resource. It generates a model, migration, controller and routes. The syntax is : `wn:resource name fields [--add=...] [--has-many=...] [--has-one=...] [--belongs-to=...] [--migration-file=...] [--path=...] [--force=true]` - **name**: the name of the resource used in the URLs and to determine the model, table and controller names. - **fields**: specifies the fields of the resource along with schema and validation rules. It follows the syntax `name;schema;rules;tags ...` - name: the name of the field - schema: the schema following the syntax in the model generator. (note that the name is not part of the schema like on the model generator) - rules: the validation rules - tags: additional tags separated by commas. The possible tags are: - `fillable`: add this field to the fillable array of the model. - `date`: add this field to the dates array of the model. - `key`: this field is a foreign key. - **--add**: Specifies additional columns like `timestamps`, `softDeletes`, `rememberToken` and `nullableTimestamps` of the migration and if the list contains no timestamps, the model with contain `public $timestamps = false;`. - **--has-one**, **--has-many** and **--belongs-to** are the same as for the `wn:model` command. - **--migration-file**: passed to the `wn:migration` as the `--file` option. - **--path**: Defines where to store the model file as well as its namespace. - **--force**: tells the generator to override the existing file. - **--laravel**: create Laravel style routes ### Multiple Resources From File The `wn:resources` (note the "s" in "resources") command takes the generation process to an other level by parsing a file and generating multiple resources based on it. The syntax is ``` wn:resources filename [--path=...] [--force=true] ``` This generator is smart enough to add foreign keys automatically when finding a belongsTo relation. It also generates pivot tables for belongsToMany relations automatically. The file given to the command should be a valid YAML file ( for the moment, support of other types like XML or JSON could be added in the future). An example is the following: - **--path**: Defines where to store the model files as well as their namespace. - **--laravel**: create Laravel style routes ```yaml --- Store: hasMany: products fields: name: schema: string:50 unique rules: required|min:3 tags: fillable Product: belongsTo: store fields: name: schema: string rules: required tags: fillable store_id: schema: integer unsigned rules: required numeric tags: fillable key desc: schema: text nullable tags: fillable published_at: schema: date rules: date tags: date fillable price: schema: 'decimal:5,2' # need quotes when using ',' rules: numeric tags: fillable add: timestamps softDeletes ``` ## Testing To test the generators, I included a fresh lumen installation under the folder `lumen-test` to which I added this package and have written some acceptance tests using [Codeception](http://codeception.com/). To run tests you just have to execute the `install.sh` to install dependencies then execute `test.sh`. ## Development Notes - **Comming versions** - **Seeder and Test generators** - Requested Feature: [Custom Templates](https://github.com/webNeat/lumen-generators/issues/13) - Requested Feature: [Fractal integration](https://github.com/webNeat/lumen-generators/issues/24) - Requested Feature: [Add possibility to not run migrations when using `wn:resources`](https://github.com/webNeat/lumen-generators/issues/23) - Documentation: [Adding examples](https://github.com/webNeat/lumen-generators/issues/20) - **Version 1.3.3** - Bug Fixed: [Rules issue when creating resources from YAML file](https://github.com/webNeat/lumen-generators/issues/30) - **Version 1.3.2** - Bug Fixed: [softDeletes not added to model](https://github.com/webNeat/lumen-generators/issues/25) - **Version 1.3.1** - Bug Fixed: [duplicate column for the foriegn key when using `wn:resources`](https://github.com/webNeat/lumen-generators/issues/22) - **Version 1.3.0** - Requested Feature: [Disabling timestamps](https://github.com/webNeat/lumen-generators/issues/15) - Requested Feature: [Lumen 5.3 routes support](https://github.com/webNeat/lumen-generators/issues/21) - **Version 1.2.0** - Tests fixed. - Bug fixed: [Undefined index: factory](https://github.com/webNeat/lumen-generators/issues/14) - Feature added: [Check if file already exists before generating it](https://github.com/webNeat/lumen-generators/issues/11) - Feature added: [Support for additional columns like nullableTimestamps() and softDeletes() in migrations](https://github.com/webNeat/lumen-generators/issues/12) - Feature added: [Specifying namespace for `wn:resource` and `wn:resources`](https://github.com/webNeat/lumen-generators/issues/18) - **Version 1.1.1** - Pivot table generation from the `wn:resources` command bug fixed. - **Version 1.1.0** - Pivot table generator added. - belongsToMany relationship added to model generator. - Multiple resources generator adds foreign keys for belongsTo relationships automatically. - Multiple resources generator adds pivot tables for belongsToMany relationships automatically. - Generated migrations file names changed to be supported by `migrate` command. - **Version 1.0.0** - Model Generator - Migration Generator - Controller Generator - Routes Generator - Resource Generator - Multiple Resources From File ## Contributing Pull requests are welcome :D