wn:pivot-table command added

This commit is contained in:
Amine Ben hammou 2015-10-06 22:41:40 +01:00
parent 383cf6fd06
commit 4b66c5af88
28 changed files with 675 additions and 15 deletions

View File

@ -1,12 +1,13 @@
# Lumen generators
[![Build Status](https://travis-ci.org/webNeat/lumen-generators.svg?branch=master)](https://travis-ci.org/webNeat/lumen-generators)
[![License](https://poser.pugx.org/laravel/framework/license.svg)](http://opensource.org/licenses/MIT)
A collection of generators for [Lumen](http://lumen.laravel.com) and [Laravel 5](http://laravel.com/).
## Contents
- [Why](#why)
- [Why ?](#why)
- [Installation](#installation)
@ -18,6 +19,8 @@ A collection of generators for [Lumen](http://lumen.laravel.com) and [Laravel 5]
- [Migration Generator](#migration-generator)
- [Pivot Table Generator](#pivot-table-generator)(New on version 1.1.0)
- [Controller Generator](#controller-generator)
- [Routes Generator](#routes-generator)
@ -30,7 +33,6 @@ A collection of generators for [Lumen](http://lumen.laravel.com) and [Laravel 5]
- [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.
@ -64,6 +66,7 @@ wn:controller Generates RESTful controller using the RESTActions t
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.
@ -252,7 +255,7 @@ More then that, you can generate multiple resources with only one command ! [Cli
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=...] [--rules=...] [--path=...]
wn:model name [--fillable=...] [--dates=...] [--has-many=...] [--has-one=...] [--belongs-to=...] [--belongs-to-many=...] [--rules=...] [--path=...]
```
- **name**: the name of the model.
@ -306,10 +309,10 @@ class Task extends Model {
//...
```
- **--has-one**, **--has-many** and **--belongs-to**: the relationships of the model following the syntax `relation1:model1,relation2:model2,...`. If the `model` is missing, it will be deducted from the relation's name. If the `model` is given without a namespace, it will be considered having the same namespace as the model being generated.
- **--has-one**, **--has-many**, **--belongs-to** and **--belongs-to-many**: the relationships of the model following the syntax `relation1:model1,relation2:model2,...`. If the `model` is missing, it will be deducted from the relation's name. If the `model` is given without a namespace, it will be considered having the same namespace as the model being generated.
```
php artisan wn:model Task --has-many=accounts --belongs-to="owner:App\User" --has-one=number:Phone --path=tests/tmp
php artisan wn:model Task --has-many=accounts --belongs-to="owner:App\User" --has-one=number:Phone belongs-to-many=tags --path=tests/tmp
```
gives:
@ -317,17 +320,22 @@ gives:
//...
public function accounts()
{
return $this->hasMany("Tests\\Tmp\\Account");
return $this->hasMany("Tests\Tmp\Account");
}
public function owner()
{
return $this->belongsTo("App\\User");
return $this->belongsTo("App\User");
}
public function number()
{
return $this->hasOne("Tests\\Tmp\\Phone");
return $this->hasOne("Tests\Tmp\Phone");
}
public function tags()
{
return $this->belongsToMany("Tests\Tmp\Tag")->withTimestamps();
}
```
@ -412,6 +420,55 @@ $table->foreign('user_id')
->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 [--file=...]
```
- **model1** and **model2**: names of the two models (or the two tables if the models don't follow the naming conventions)
- **--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
```
gives:
```php
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectTagMigration extends Migration
{
public function up()
{
Schema::create('project_tag', function(Blueprint $table) {
$table->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:
@ -498,7 +555,13 @@ The `wn:resource` command makes it very easy to generate a RESTful resource. It
### 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`
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
```
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:
@ -542,3 +605,4 @@ To test the generators, I included a fresh lumen installation under the folder `
## Contributing
Pull requests are welcome :D

View File

@ -0,0 +1,10 @@
<?php namespace App\Http\Controllers;
class ProjectsController extends Controller {
const MODEL = "App\Project";
use RESTActions;
}

View File

@ -0,0 +1,10 @@
<?php namespace App\Http\Controllers;
class TagsController extends Controller {
const MODEL = "App\Tag";
use RESTActions;
}

View File

@ -0,0 +1,21 @@
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Project extends Model {
protected $fillable = ["name", "descr"];
protected $dates = [];
public static $rules = [
"name" => "required",
];
public function tags()
{
return $this->belongsToMany("App\Tag")->withTimestamps();
}
}

21
lumen-test/app/Tag.php Normal file
View File

@ -0,0 +1,21 @@
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model {
protected $fillable = ["name"];
protected $dates = [];
public static $rules = [
"name" => "required|unique",
];
public function projects()
{
return $this->belongsToMany("App\Project")->withTimestamps();
}
}

21
lumen-test/app/Tags.php Normal file
View File

@ -0,0 +1,21 @@
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Tags extends Model {
protected $fillable = ["name"];
protected $dates = [];
public static $rules = [
"name" => "required|unique",
];
public function projects()
{
return $this->belongsToMany("App\Project")->withTimestamps();
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectTagMigration extends Migration
{
public function up()
{
Schema::create('project_tag', function(Blueprint $table) {
$table->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');
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectTagMigration extends Migration
{
public function up()
{
Schema::create('project_tag', function(Blueprint $table) {
$table->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');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectTagMigration extends Migration
{
public function up()
{
Schema::create('project_tag', function(Blueprint $table) {
$table->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');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectsMigration extends Migration
{
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('descr')->nullable();
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('projects');
}
}

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTagsMigration extends Migration
{
public function up()
{
Schema::create('tags', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
// Constraints declaration
$table->timestamps();
});
}
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,39 @@
<?php
$I = new AcceptanceTester($scenario);
$I->wantTo('generate a pivot table');
$I->runShellCommand('php artisan wn:pivot-table Tag Project --file=pivot_table');
$I->seeInShellOutput('project_tag migration generated');
$I->seeFileFound('./database/migrations/pivot_table.php');
$I->openFile('./database/migrations/pivot_table.php');
$I->seeFileContentsEqual('<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProjectTagMigration extends Migration
{
public function up()
{
Schema::create(\'project_tag\', function(Blueprint $table) {
$table->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\');
}
}
');
$I->deleteFile('./database/migrations/pivot_table.php');

View File

@ -10,6 +10,7 @@ class ModelCommand extends BaseCommand {
{--has-many= : hasMany relationships.}
{--has-one= : hasOne relationships.}
{--belongs-to= : belongsTo relationships.}
{--belongs-to-many= : belongsToMany relationships.}
{--rules= : fields validation rules.}
{--path=app : where to store the model php file.}
{--parsed : tells the command that arguments have been already parsed. To use when calling the command from an other command and passing the parsed arguments and options}';
@ -60,7 +61,8 @@ class ModelCommand extends BaseCommand {
$relations = array_merge([],
$this->getRelationsByType('hasOne', 'has-one'),
$this->getRelationsByType('hasMany', 'has-many'),
$this->getRelationsByType('belongsTo', 'belongs-to')
$this->getRelationsByType('belongsTo', 'belongs-to'),
$this->getRelationsByType('belongsToMany', 'belongs-to-many', true)
);
if(empty($relations)){
@ -70,15 +72,16 @@ class ModelCommand extends BaseCommand {
return implode(PHP_EOL, $relations);
}
protected function getRelationsByType($type, $option)
protected function getRelationsByType($type, $option, $withTimestamps = false)
{
$relations = [];
$option = $this->option($option);
if($option){
$items = $this->getArgumentParser('relations')->parse($option);
$template = $this->getTemplate('model/relation');
$template = ($withTimestamps) ? 'model/relation-with-timestamps' : 'model/relation';
$template = $this->getTemplate($template);
foreach ($items as $item) {
$item['type'] = $type;
if(! $item['model']){

View File

@ -0,0 +1,52 @@
<?php namespace Wn\Generators\Commands;
class PivotTableCommand extends BaseCommand {
protected $signature = 'wn:pivot-table
{model1 : Name of the first model or table}
{model2 : Name of the second model or table}
{--file= : name of the migration file.}
';
protected $description = 'Generates creation migration for a pivot table';
protected $tables;
public function handle()
{
$this->parseTables();
$this->call('wn:migration', [
'table' => implode('_', $this->tables),
'--schema' => $this->schema(),
'--keys' => $this->keys(),
'--file' => $this->option('file'),
'--parsed' => false
]);
}
protected function parseTables()
{
$this->tables = array_map(function($arg) {
return snake_case(str_singular($this->argument($arg)));
}, ['model1', 'model2']);
sort($this->tables);
}
protected function schema()
{
return implode(' ', array_map(function($table){
return $table . '_id:integer:unsigned:index';
}, $this->tables));
}
protected function keys()
{
return implode(' ', array_map(function($table){
return $table . '_id';
}, $this->tables));
}
}

View File

@ -9,6 +9,7 @@ class ResourceCommand extends BaseCommand {
{--has-many= : hasMany relationships.}
{--has-one= : hasOne relationships.}
{--belongs-to= : belongsTo relationships.}
{--belongs-to-many= : belongsToMany relationships.}
{--migration-file= : the migration file name.}
{--parsed : tells the command that arguments have been already parsed. To use when calling the command from an other command and passing the parsed arguments and options}
';
@ -33,6 +34,7 @@ class ResourceCommand extends BaseCommand {
'--has-many' => $this->option('has-many'),
'--has-one' => $this->option('has-one'),
'--belongs-to' => $this->option('belongs-to'),
'--belongs-to-many' => $this->option('belongs-to-many'),
'--rules' => $this->rules(),
'--path' => 'app',
'--parsed' => true

View File

@ -10,6 +10,8 @@ class ResourcesCommand extends BaseCommand {
protected $description = 'Generates multiple resources from a file';
protected $pivotTables = [];
public function handle()
{
$content = $this->fs->get($this->argument('file'));
@ -23,7 +25,22 @@ class ResourcesCommand extends BaseCommand {
'fields' => $i['fields'],
'--has-many' => $i['hasMany'],
'--has-one' => $i['hasOne'],
'--belongs-to' => $i['belongsTo']
'--belongs-to' => $i['belongsTo'],
'--belongs-to-many' => $i['belongsToMany']
]);
}
$this->pivotTables = array_map(
'unserialize',
array_unique(array_map('serialize', $this->pivotTables))
);
dd($this->pivotTables);
foreach ($this->pivotTables as $tables) {
$this->call('wn:pivot-table', [
'model1' => $tables[0],
'model2' => $tables[1]
]);
}
}
@ -32,7 +49,7 @@ class ResourcesCommand extends BaseCommand {
{
$i['name'] = snake_case($modelName);
foreach(['hasMany', 'hasOne', 'belongsTo'] as $relation){
foreach(['hasMany', 'hasOne', 'belongsTo', 'belongsToMany'] as $relation){
if(isset($i[$relation])){
$i[$relation] = $this->convertArray($i[$relation], ' ', ',');
} else {
@ -59,6 +76,24 @@ class ResourcesCommand extends BaseCommand {
}
}
if($i['belongsToMany']){
$relations = $this->getArgumentParser('relations')->parse($i['belongsToMany']);
foreach ($relations as $relation){
$table = '';
if(! $relation['model']){
$table = snake_case($relation['name']);
} else {
$names = array_reverse(explode("\\", $relation['model']));
$table = snake_case($names[0]);
}
$tables = [ str_singular($table), $i['name'] ];
sort($tables);
$this->pivotTables[] = $tables;
}
}
$fields = [];
foreach($i['fields'] as $name => $value) {
$value['name'] = $name;

View File

@ -14,6 +14,7 @@ class CommandsServiceProvider extends ServiceProvider
$this->registerMigrationCommand();
$this->registerResourceCommand();
$this->registerResourcesCommand();
$this->registerPivotTableCommand();
// $this->registerSeedCommand();
// $this->registerTestCommand();
}
@ -90,4 +91,12 @@ class CommandsServiceProvider extends ServiceProvider
}
protected function registerPivotTableCommand(){
$this->app->singleton('command.wn.pivot-table', function($app){
return $app['Wn\Generators\Commands\PivotTableCommand'];
});
$this->commands('command.wn.pivot-table');
}
}

View File

@ -0,0 +1,4 @@
public function {{name}}()
{
return $this->{{type}}("{{model}}")->withTimestamps();
}