├── .gitignore ├── .travis.yml ├── LICENSE ├── composer.json ├── phpunit.xml ├── readme.md ├── src ├── Commands │ └── ScaffoldMakeCommand.php ├── GeneratorException.php ├── GeneratorsServiceProvider.php ├── Localizations │ ├── SchemaParser.php │ └── SyntaxBuilder.php ├── Makes │ ├── MakeController.php │ ├── MakeLayout.php │ ├── MakeLocalization.php │ ├── MakeMigration.php │ ├── MakeModel.php │ ├── MakeRoute.php │ ├── MakeSeed.php │ ├── MakeView.php │ └── MakerTrait.php ├── Migrations │ ├── NameParser.php │ ├── SchemaParser.php │ └── SyntaxBuilder.php ├── Stubs │ ├── controller.stub │ ├── localization.stub │ ├── migration.stub │ ├── model.stub │ ├── pivot.stub │ ├── route.stub │ ├── schema-change.stub │ ├── schema-create.stub │ ├── seed.stub │ └── views │ │ └── bs3 │ │ ├── error.blade.php.stub │ │ ├── fields │ │ ├── content │ │ │ └── default │ │ ├── empty │ │ │ ├── default │ │ │ ├── string │ │ │ └── text │ │ ├── fillable │ │ │ ├── default │ │ │ ├── string │ │ │ └── text │ │ ├── header │ │ │ └── default │ │ └── show │ │ │ └── default │ │ ├── layout.blade.php.stub │ │ └── pages │ │ ├── create.blade.php.stub │ │ ├── edit.blade.php.stub │ │ ├── index.blade.php.stub │ │ └── show.blade.php.stub └── Validators │ ├── SchemaParser.php │ └── SyntaxBuilder.php └── tests ├── CommandTest.php └── StartTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea 3 | .DS_Store 4 | composer.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | 6 | before_script: 7 | - composer self-update 8 | - composer install --no-interaction 9 | 10 | script: 11 | - vendor/bin/phpunit -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Fernando 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laralib/l5scaffold", 3 | "description": "Extend Laravel 5's generators scaffold.", 4 | "keywords": ["laravel", "generators", "scaffold" , "laravel5"], 5 | "license": "MIT", 6 | "minimum-stability": "dev", 7 | "authors": [ 8 | { 9 | "name": "Fernando Brito", 10 | "email": "fernandobritofl@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.4.0" 15 | }, 16 | "require-dev": { 17 | "laravel/laravel": "dev-master", 18 | "phpunit/phpunit": "^5.4" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "Laralib\\L5scaffold\\": "src/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | ./tests 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | ./app/Http/routes.php 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel 5.x Scaffold Generator 2 | [![Travis](https://img.shields.io/travis/laralib/l5scaffold.svg?style=flat-square)](https://github.com/laralib/l5scaffold) 3 | [![Packagist](https://img.shields.io/packagist/dt/laralib/l5scaffold.svg?style=flat-square)](https://packagist.org/packages/laralib/l5scaffold) 4 | [![Tag](https://img.shields.io/github/tag/laralib/l5scaffold.svg)](https://github.com/laralib/l5scaffold/tags) 5 | ## Usage 6 | 7 | ### Step 1: Install Through Composer 8 | 9 | ``` 10 | composer require 'laralib/l5scaffold' --dev 11 | ``` 12 | 13 | ### Step 2: Add the Service Provider 14 | 15 | Open `config/app.php` and, to your **providers** array at the bottom, add: 16 | 17 | ``` 18 | Laralib\L5scaffold\GeneratorsServiceProvider::class 19 | ``` 20 | 21 | ### Step 3: Run Artisan! 22 | 23 | You're all set. Run `php artisan` from the console, and you'll see the new commands `make:scaffold`. 24 | 25 | ## Examples 26 | 27 | Use this command to generator scaffolding of **Tweet** in your project: 28 | ``` 29 | php artisan make:scaffold Tweet \ 30 | --schema="title:string:default('Tweet #1'), body:text" 31 | ``` 32 | or with more options 33 | ``` 34 | php artisan make:scaffold Tweet \ 35 | --schema="title:string:default('Tweet #1'), body:text" \ 36 | --ui="bs3" \ 37 | --prefix="admin" 38 | ``` 39 | 40 | This command will generate: 41 | 42 | ``` 43 | app/Tweet.php 44 | app/Http/Controllers/TweetController.php 45 | 46 | database/migrations/201x_xx_xx_xxxxxx_create_tweets_table.php 47 | database/seeds/TweetTableSeeder.php 48 | 49 | resources/views/layout.blade.php 50 | resources/views/tweets/index.blade.php 51 | resources/views/tweets/show.blade.php 52 | resources/views/tweets/edit.blade.php 53 | resources/views/tweets/create.blade.php 54 | ``` 55 | 56 | After don't forget to run: 57 | 58 | 59 | ``` 60 | php artisan migrate 61 | ``` 62 | ## Custom stub 63 | Create a new folder inside **Stubs > views** with your UI name custom 64 | ![image](http://i66.tinypic.com/10ndpgw.png) 65 | 66 | Custom fields in `Stubs > views > **ui-name** > fields` 67 | 68 | Custom pages in `Stubs > views > **ui-name** > pages` 69 | 70 |
71 | 72 | :thought_balloon: **Send us your ideas.** (creating issues) 73 | 74 | 75 | ##Collaborators 76 | [Fernando Brito](https://github.com/fernandobritofl "fernandobritofl") 77 |
[Sylvio Tavares](https://github.com/sylviot "Sylviot") 78 |
[Raphael Heitor](https://github.com/raphaelheitor "raphaelheitor") 79 |
[Alfred Nutile](https://github.com/alnutile "alnutile") 80 |
[Sazzad Hossain Khan](https://github.com/itsazzad "itsazzad") 81 |
[Alexander Makhaev](https://github.com/mankms "mankms") 82 |
[Adam Brown](https://github.com/DeftNerd "DeftNerd") 83 |
[TJ Webb](https://github.com/webbtj "webbtj") 84 |
[Tsaganos Tolis](https://github.com/Dev-Force "Dev-Force") 85 |
[Ryan Gurnick](https://github.com/ryangurn "ryangurn") 86 | -------------------------------------------------------------------------------- /src/Commands/ScaffoldMakeCommand.php: -------------------------------------------------------------------------------- 1 | files = $files; 71 | $this->composer = app()['composer']; 72 | } 73 | 74 | /** 75 | * Execute the console command. 76 | * 77 | * @return void 78 | */ 79 | public function fire() 80 | { 81 | $header = "scaffolding: {$this->getObjName("Name")}"; 82 | $footer = str_pad('', strlen($header), '-'); 83 | $dump = str_pad('>DUMP AUTOLOAD<', strlen($header), ' ', STR_PAD_BOTH); 84 | 85 | $this->line("\n----------- $header -----------\n"); 86 | 87 | $this->makeMeta(); 88 | $this->makeMigration(); 89 | $this->makeSeed(); 90 | $this->makeModel(); 91 | $this->makeController(); 92 | // $this->makeLocalization(); //ToDo - implement in future version 93 | $this->makeViews(); 94 | $this->makeViewLayout(); 95 | 96 | $this->line("\n----------- $footer -----------"); 97 | $this->comment("----------- $dump -----------"); 98 | 99 | $this->composer->dumpAutoloads(); 100 | $this->error("Don't forget to adjust: 'migrate' and 'routes'"); 101 | } 102 | 103 | /** 104 | * Generate the desired migration. 105 | * 106 | * @return void 107 | */ 108 | protected function makeMeta() 109 | { 110 | // ToDo - Verificar utilidade... 111 | $this->meta['action'] = 'create'; 112 | $this->meta['var_name'] = $this->getObjName("name"); 113 | $this->meta['table'] = $this->getObjName("names");//obsoleto 114 | 115 | $this->meta['ui'] = $this->option('ui'); 116 | 117 | $this->meta['namespace'] = $this->getAppNamespace(); 118 | 119 | $this->meta['Model'] = $this->getObjName('Name'); 120 | $this->meta['Models'] = $this->getObjName('Names'); 121 | $this->meta['model'] = $this->getObjName('name'); 122 | $this->meta['models'] = $this->getObjName('names'); 123 | $this->meta['ModelMigration'] = "Create{$this->meta['Models']}Table"; 124 | 125 | $this->meta['schema'] = $this->option('schema'); 126 | $this->meta['prefix'] = ($prefix = $this->option('prefix')) ? "$prefix." : ""; 127 | } 128 | 129 | /** 130 | * Generate the desired migration. 131 | * 132 | * @return void 133 | */ 134 | protected function makeMigration() 135 | { 136 | new MakeMigration($this, $this->files); 137 | } 138 | 139 | /** 140 | * Make a Controller with default actions 141 | * 142 | * @return void 143 | */ 144 | private function makeController() 145 | { 146 | new MakeController($this, $this->files); 147 | } 148 | 149 | /** 150 | * Make a layout.blade.php with bootstrap 151 | * 152 | * @return void 153 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 154 | */ 155 | private function makeViewLayout() 156 | { 157 | new MakeLayout($this, $this->files); 158 | } 159 | 160 | /** 161 | * Generate an Eloquent model, if the user wishes. 162 | * 163 | * @return void 164 | */ 165 | protected function makeModel() 166 | { 167 | new MakeModel($this, $this->files); 168 | } 169 | 170 | /** 171 | * Generate a Seed 172 | * 173 | * @return void 174 | */ 175 | private function makeSeed() 176 | { 177 | new MakeSeed($this, $this->files); 178 | } 179 | 180 | /** 181 | * Setup views and assets 182 | * 183 | * @return void 184 | */ 185 | private function makeViews() 186 | { 187 | new MakeView($this, $this->files); 188 | } 189 | 190 | /** 191 | * Setup the localizations 192 | */ 193 | private function makeLocalization() 194 | { 195 | new MakeLocalization($this, $this->files); 196 | } 197 | 198 | /** 199 | * Get the console command arguments. 200 | * 201 | * @return array 202 | */ 203 | protected function getArguments() 204 | { 205 | return 206 | [ 207 | ['name', InputArgument::REQUIRED, 'The name of the model. (Ex: Post)'], 208 | ]; 209 | } 210 | 211 | /** 212 | * Get the console command options. 213 | * 214 | * @return array 215 | */ 216 | protected function getOptions() 217 | { 218 | return 219 | [ 220 | [ 221 | 'schema', 222 | 's', 223 | InputOption::VALUE_REQUIRED, 224 | 'Schema to generate scaffold files. (Ex: --schema="title:string")', 225 | null 226 | ], 227 | [ 228 | 'ui', 229 | 'ui', 230 | InputOption::VALUE_OPTIONAL, 231 | 'UI Framework to generate scaffold. (Default bs3 - bootstrap 3)', 232 | 'bs3' 233 | ], 234 | [ 235 | 'validator', 236 | 'a', 237 | InputOption::VALUE_OPTIONAL, 238 | 'Validators to generate scaffold files. (Ex: --validator="title:required")', 239 | null 240 | ], 241 | [ 242 | 'localization', 243 | 'l', 244 | InputOption::VALUE_OPTIONAL, 245 | 'Localizations to generate scaffold files. (Ex. --localization="key:value")', 246 | null 247 | ], 248 | [ 249 | 'lang', 250 | 'b', 251 | InputOption::VALUE_OPTIONAL, 252 | 'Language for Localization (Ex. --lang="en")', 253 | null, 254 | ], 255 | [ 256 | 'form', 257 | 'f', 258 | InputOption::VALUE_OPTIONAL, 259 | 'Use Illumintate/Html Form facade to generate input fields', 260 | false 261 | ], 262 | [ 263 | 'prefix', 264 | 'p', 265 | InputOption::VALUE_OPTIONAL, 266 | 'Generate schema with prefix', 267 | false 268 | ] 269 | ]; 270 | } 271 | 272 | /** 273 | * Get access to $meta array 274 | * 275 | * @return array 276 | */ 277 | public function getMeta() 278 | { 279 | return $this->meta; 280 | } 281 | 282 | /** 283 | * Generate names 284 | * 285 | * @param string $config 286 | * @return mixed 287 | * @throws \Exception 288 | */ 289 | public function getObjName($config = 'Name') 290 | { 291 | $names = []; 292 | $args_name = $this->argument('name'); 293 | 294 | // Name[0] = Tweet 295 | $names['Name'] = str_singular(ucfirst($args_name)); 296 | // Name[1] = Tweets 297 | $names['Names'] = str_plural(ucfirst($args_name)); 298 | // Name[2] = tweets 299 | $names['names'] = str_plural(strtolower(preg_replace('/(?registerScaffoldGenerator(); 28 | } 29 | 30 | /** 31 | * Register the make:scaffold generator. 32 | * 33 | * @return void 34 | */ 35 | private function registerScaffoldGenerator() 36 | { 37 | $this->app->singleton('command.larascaf.scaffold', function ($app) { 38 | return $app['Laralib\L5scaffold\Commands\ScaffoldMakeCommand']; 39 | }); 40 | 41 | $this->commands('command.larascaf.scaffold'); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Localizations/SchemaParser.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class SchemaParser 11 | { 12 | 13 | /** 14 | * The parsed schema. 15 | * 16 | * @var array 17 | */ 18 | private $schema = []; 19 | 20 | /** 21 | * Parse the command line migration schema. 22 | * Ex: name:string, age:integer:nullable 23 | * 24 | * @param string $schema 25 | * @return array 26 | */ 27 | public function parse($schema) 28 | { 29 | $fields = $this->splitIntoFields($schema); 30 | 31 | foreach ($fields as $field) { 32 | $segments = $this->parseSegments($field); 33 | 34 | $this->addField($segments); 35 | } 36 | 37 | return $this->schema; 38 | } 39 | 40 | /** 41 | * Add a field to the schema array. 42 | * 43 | * @param array $field 44 | * @return $this 45 | */ 46 | private function addField($field) 47 | { 48 | $this->schema[] = $field; 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * Get an array of fields from the given schema. 55 | * 56 | * @param string $schema 57 | * @return array 58 | */ 59 | private function splitIntoFields($schema) 60 | { 61 | return preg_split('/,\s?(?![^()]*\))/', $schema); 62 | } 63 | 64 | /** 65 | * Get the segments of the schema field. 66 | * 67 | * @param string $field 68 | * @return array 69 | */ 70 | private function parseSegments($field) 71 | { 72 | $segments = explode(':', $field); 73 | 74 | $name = array_shift($segments); 75 | $argument = $segments[0]; 76 | 77 | return compact('name', 'argument'); 78 | 79 | } 80 | 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/Localizations/SyntaxBuilder.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class SyntaxBuilder 11 | { 12 | 13 | /** 14 | * Create the PHP syntax for the given schema. 15 | * 16 | * @param array $schema 17 | * @param array $meta 18 | * @param string $type 19 | * @param bool $illuminate 20 | * @return string 21 | * @throws GeneratorException 22 | * @throws \Exception 23 | */ 24 | public function create($schema) 25 | { 26 | $fieldsc = $this->createSchemaForLocalization($schema); 27 | return $fieldsc; 28 | } 29 | 30 | private function createSchemaForLocalization($schema) 31 | { 32 | $localization = ''; 33 | if(is_array($schema)) { 34 | foreach ($schema as $k => $v) { 35 | $localization .= "'" . $v['name'] . "' => '" . $v['argument'] . "',\n\t"; 36 | } 37 | } 38 | return $localization; 39 | } 40 | } -------------------------------------------------------------------------------- /src/Makes/MakeController.php: -------------------------------------------------------------------------------- 1 | files = $files; 32 | $this->scaffoldCommandObj = $scaffoldCommand; 33 | 34 | $this->start(); 35 | } 36 | 37 | /** 38 | * Start make controller. 39 | * 40 | * @return void 41 | */ 42 | private function start() 43 | { 44 | $name = $this->scaffoldCommandObj->getObjName('Name') . 'Controller'; 45 | $path = $this->getPath($name, 'controller'); 46 | 47 | if ($this->files->exists($path)) 48 | { 49 | return $this->scaffoldCommandObj->comment("x $name"); 50 | } 51 | 52 | $this->makeDirectory($path); 53 | 54 | $this->files->put($path, $this->compileControllerStub()); 55 | 56 | $this->scaffoldCommandObj->info('+ Controller'); 57 | } 58 | 59 | /** 60 | * Compile the controller stub. 61 | * 62 | * @return string 63 | */ 64 | protected function compileControllerStub() 65 | { 66 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/controller.stub'); 67 | 68 | $this->buildStub($this->scaffoldCommandObj->getMeta(), $stub); 69 | // $this->replaceValidator($stub); 70 | 71 | return $stub; 72 | } 73 | 74 | 75 | // /** 76 | // * Replace validator in the controller stub. 77 | // * 78 | // * @return $this 79 | // */ 80 | // private function replaceValidator(&$stub) 81 | // { 82 | // if($schema = $this->scaffoldCommandObj->option('validator')){ 83 | // $schema = (new ValidatorParser)->parse($schema); 84 | // } 85 | 86 | // $schema = (new ValidatorSyntax)->create($schema, $this->scaffoldCommandObj->getMeta(), 'validation'); 87 | // $stub = str_replace('{{validation_fields}}', $schema, $stub); 88 | 89 | // return $this; 90 | // } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/Makes/MakeLayout.php: -------------------------------------------------------------------------------- 1 | files = $files; 28 | $this->scaffoldCommandObj = $scaffoldCommand; 29 | 30 | $this->start(); 31 | } 32 | 33 | /** 34 | * Start make layout(view). 35 | * 36 | * @return void 37 | */ 38 | protected function start() 39 | { 40 | $ui = $this->scaffoldCommandObj->getMeta()['ui']; 41 | $this->putViewLayout('Layout', "Stubs/views/$ui/layout.blade.php.stub", 'layout.blade.php'); 42 | $this->putViewLayout('Error', "Stubs/views/$ui/error.blade.php.stub", 'error.blade.php'); 43 | } 44 | 45 | 46 | /** 47 | * Write layout in path 48 | * 49 | * @param $path_resource 50 | * @return void 51 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 52 | */ 53 | protected function putViewLayout($name, $stub, $file) 54 | { 55 | $path_file = $this->getPathResource().$file; 56 | $path_stub = substr(__DIR__,0, -5) .$stub; 57 | 58 | if ($this->files->exists($path_file)) 59 | { 60 | return $this->scaffoldCommandObj->comment("x $name (Skip)"); 61 | } 62 | 63 | $html = $this->files->get($path_stub); 64 | $html = $this->buildStub($this->scaffoldCommandObj->getMeta(), $html); 65 | $this->files->put($path_file, $html); 66 | $this->scaffoldCommandObj->info("+ $name"); 67 | } 68 | 69 | /** 70 | * Get the path to where we should store the view. 71 | * 72 | * @return string 73 | */ 74 | protected function getPathResource() 75 | { 76 | return './resources/views/'; 77 | } 78 | } -------------------------------------------------------------------------------- /src/Makes/MakeLocalization.php: -------------------------------------------------------------------------------- 1 | files = $files; 32 | $this->scaffoldCommandObj = $scaffoldCommand; 33 | $this->language_code = $this->scaffoldCommandObj->option('lang'); 34 | 35 | $this->start(); 36 | } 37 | 38 | /** 39 | * Start make seed. 40 | * 41 | * @return void 42 | */ 43 | protected function start() 44 | { 45 | $path = $this->getPath($this->language_code . '/'.$this->scaffoldCommandObj->getObjName('Name'), 'localization'); 46 | 47 | $this->makeDirectory($path); 48 | 49 | if ($this->files->exists($path)) 50 | { 51 | return $this->scaffoldCommandObj->comment('x Localization'); 52 | } 53 | 54 | $this->files->put($path, $this->compileLocalizationStub()); 55 | $this->scaffoldCommandObj->info('+ Localization'); 56 | } 57 | 58 | /** 59 | * Compile the migration stub. 60 | * 61 | * @return string 62 | */ 63 | protected function compileLocalizationStub() 64 | { 65 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/localization.stub'); 66 | 67 | $this->build($stub); 68 | 69 | return $stub; 70 | } 71 | 72 | private function build(&$stub){ 73 | $this->replaceLocalization($stub); 74 | } 75 | 76 | private function replaceLocalization(&$stub){ 77 | if($schema = $this->scaffoldCommandObj->option('localization')){ 78 | $schema = (new LocalizationsParser())->parse($schema); 79 | } 80 | 81 | $schema = (new LocalizationsBuilder())->create($schema, $this->scaffoldCommandObj->getMeta(), 'validation'); 82 | $stub = str_replace('{{localization}}', $schema, $stub); 83 | 84 | return $this; 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /src/Makes/MakeMigration.php: -------------------------------------------------------------------------------- 1 | files = $files; 37 | $this->scaffoldCommandObj = $scaffoldCommand; 38 | 39 | $this->start(); 40 | } 41 | 42 | /** 43 | * Start make migration. 44 | * 45 | * @return void 46 | */ 47 | protected function start(){ 48 | $name = 'create_'.str_plural(strtolower( $this->scaffoldCommandObj->argument('name') )).'_table'; 49 | 50 | if ($this->files->exists($path = $this->getPath($name))) 51 | { 52 | return $this->scaffoldCommandObj->error($this->type.' already exists!'); 53 | } 54 | 55 | $this->makeDirectory($path); 56 | $this->files->put($path, $this->compileMigrationStub()); 57 | $this->scaffoldCommandObj->info('+ Migration'); 58 | } 59 | 60 | /** 61 | * Get the path to where we should store the migration. 62 | * 63 | * @param string $name 64 | * @return string 65 | */ 66 | protected function getPath($name) 67 | { 68 | return './database/migrations/'.date('Y_m_d_His').'_'.$name.'.php'; 69 | } 70 | 71 | /** 72 | * Compile the migration stub. 73 | * 74 | * @return string 75 | */ 76 | protected function compileMigrationStub() 77 | { 78 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/migration.stub'); 79 | 80 | $this->replaceSchema($stub); 81 | $this->buildStub($this->scaffoldCommandObj->getMeta(), $stub); 82 | 83 | return $stub; 84 | } 85 | 86 | /** 87 | * Replace the schema for the stub. 88 | * 89 | * @param string $stub 90 | * @param string $type 91 | * @return $this 92 | */ 93 | protected function replaceSchema(&$stub) 94 | { 95 | if ($schema = $this->scaffoldCommandObj->getMeta()['schema']) 96 | { 97 | $schema = (new SchemaParser)->parse($schema); 98 | } 99 | 100 | $schema = (new SyntaxBuilder)->create($schema, $this->scaffoldCommandObj->getMeta()); 101 | $stub = str_replace(['{{schema_up}}', '{{schema_down}}'], $schema, $stub); 102 | 103 | return $this; 104 | } 105 | } -------------------------------------------------------------------------------- /src/Makes/MakeModel.php: -------------------------------------------------------------------------------- 1 | files = $files; 30 | $this->scaffoldCommandObj = $scaffoldCommand; 31 | 32 | $this->start(); 33 | } 34 | 35 | /** 36 | * Start make controller. 37 | * 38 | * @return void 39 | */ 40 | private function start() 41 | { 42 | $name = $this->scaffoldCommandObj->getObjName('Name'); 43 | $path = $this->getPath($name, 'model'); 44 | 45 | if ($this->files->exists($path)) 46 | { 47 | return $this->scaffoldCommandObj->comment("x $name"); 48 | } 49 | 50 | $this->files->put($path, $this->compileModelStub()); 51 | 52 | $this->scaffoldCommandObj->info('+ Model'); 53 | } 54 | 55 | /** 56 | * Compile the migration stub. 57 | * 58 | * @return string 59 | */ 60 | protected function compileModelStub() 61 | { 62 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/model.stub'); 63 | 64 | $this->buildStub($this->scaffoldCommandObj->getMeta(), $stub); 65 | $this->buildFillable($stub); 66 | 67 | return $stub; 68 | } 69 | 70 | /** 71 | * Build stub replacing the variable template. 72 | * 73 | * @return string 74 | */ 75 | protected function buildFillable(&$stub) 76 | { 77 | $schemaArray = []; 78 | 79 | $schema = $this->scaffoldCommandObj->getMeta()['schema']; 80 | 81 | if ($schema) 82 | { 83 | $items = (new SchemaParser)->parse($schema); 84 | foreach($items as $item) 85 | { 86 | $schemaArray[] = "'{$item['name']}'"; 87 | } 88 | 89 | $schemaArray = join(", ", $schemaArray); 90 | } 91 | 92 | $stub = str_replace('{{fillable}}', $schemaArray, $stub); 93 | 94 | return $this; 95 | } 96 | } -------------------------------------------------------------------------------- /src/Makes/MakeRoute.php: -------------------------------------------------------------------------------- 1 | files = $files; 31 | $this->scaffoldCommandObj = $scaffoldCommand; 32 | 33 | $this->start(); 34 | } 35 | 36 | /** 37 | * Start make controller. 38 | * 39 | * @return void 40 | */ 41 | private function start() 42 | { 43 | $name = $this->scaffoldCommandObj->getObjName('Name'); 44 | $path = $this->getPath($name, 'route'); 45 | 46 | $this->files->append($path, $this->compileRouteStub()); 47 | 48 | $this->scaffoldCommandObj->info('Routes Updated successfully.'); 49 | } 50 | 51 | /** 52 | * Compile the migration stub. 53 | * 54 | * @return string 55 | */ 56 | protected function compileRouteStub() 57 | { 58 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/route.stub'); 59 | 60 | $this->buildStub($this->scaffoldCommandObj->getMeta(), $stub); 61 | 62 | return $stub; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Makes/MakeSeed.php: -------------------------------------------------------------------------------- 1 | files = $files; 28 | $this->scaffoldCommandObj = $scaffoldCommand; 29 | 30 | $this->start(); 31 | } 32 | 33 | /** 34 | * Start make seed. 35 | * 36 | * @return void 37 | */ 38 | protected function start() 39 | { 40 | $path = $this->getPath($this->scaffoldCommandObj->getObjName('Name') . 'TableSeeder', 'seed'); 41 | 42 | 43 | if ($this->files->exists($path)) 44 | { 45 | return $this->scaffoldCommandObj->comment('x Seed'); 46 | } 47 | 48 | $this->makeDirectory($path); 49 | $this->files->put($path, $this->compileSeedStub()); 50 | $this->scaffoldCommandObj->info('+ Seed'); 51 | } 52 | 53 | /** 54 | * Compile the seed stub. 55 | * 56 | * @return string 57 | */ 58 | protected function compileSeedStub() 59 | { 60 | $stub = $this->files->get(substr(__DIR__,0, -5) . 'Stubs/seed.stub'); 61 | 62 | $this->buildStub($this->scaffoldCommandObj->getMeta(), $stub); 63 | 64 | return $stub; 65 | } 66 | } -------------------------------------------------------------------------------- /src/Makes/MakeView.php: -------------------------------------------------------------------------------- 1 | files = $files; 45 | $this->scaffoldCommandObj = $scaffoldCommand; 46 | 47 | $this->start(); 48 | } 49 | 50 | /** 51 | * Get all property of model 52 | * 53 | * @return void 54 | */ 55 | protected function getSchemaArray() 56 | { 57 | // ToDo - schema is required? 58 | if($this->scaffoldCommandObj->option('schema') != null) 59 | { 60 | if ($schema = $this->scaffoldCommandObj->option('schema')) 61 | { 62 | return (new SchemaParser)->parse($schema); 63 | } 64 | } 65 | 66 | return []; 67 | } 68 | 69 | /** 70 | * Start make view. 71 | * 72 | * @return void 73 | */ 74 | private function start() 75 | { 76 | $this->scaffoldCommandObj->line("\n--- Views ---"); 77 | 78 | $viewsFiles = $this->getStubViews($this->scaffoldCommandObj->getMeta()['ui']); 79 | $destination = $this->getDestinationViews($this->scaffoldCommandObj->getMeta()['models']); 80 | $metas = $this->scaffoldCommandObj->getMeta(); 81 | 82 | $metas = array_merge_recursive 83 | ( 84 | $metas, 85 | [ 86 | 'form_fields_fillable' => $this->getFields($metas['ui'], 'fillable'), 87 | 'form_fields_empty' => $this->getFields($metas['ui'], 'empty'), 88 | 'form_fields_show' => $this->getFields($metas['ui'], 'show'), 89 | 'table_fields_header' => $this->getFields($metas['ui'], 'header'), 90 | 'table_fields_content' => $this->getFields($metas['ui'], 'content'), 91 | ] 92 | ); 93 | 94 | foreach ($viewsFiles as $viewFileBaseName => $viewFile) 95 | { 96 | $viewFileName = str_replace('.stub', '', $viewFileBaseName); 97 | $viewDestination = $destination . $viewFileName; 98 | 99 | if ($this->files->exists($viewDestination)) 100 | { 101 | $this->scaffoldCommandObj->comment(" x $viewFileName"); 102 | continue; 103 | } 104 | 105 | $stub = $this->files->get($viewFile); 106 | $stub = $this->buildStub($metas, $stub); 107 | 108 | $this->makeDirectory($viewDestination); 109 | $this->files->put($viewDestination, $stub); 110 | $this->scaffoldCommandObj->info(" + $viewFileName"); 111 | } 112 | } 113 | 114 | protected function getFields($ui, $type) 115 | { 116 | $stubsFields = $this->getStubFields($ui, $type); 117 | $stubsFieldsAllow = array_keys($stubsFields); 118 | $schemas = $this->getSchemaArray(); 119 | $metas = $this->scaffoldCommandObj->getMeta(); 120 | 121 | $stubs = []; 122 | 123 | foreach ($schemas as $schema) 124 | { 125 | $variablesFromField = $this->getVariablesFromField($schema); 126 | $fieldType = $variablesFromField['field.type']; 127 | 128 | if(!in_array($fieldType, $stubsFieldsAllow)) 129 | { 130 | $fieldType = 'default'; 131 | } 132 | 133 | $stub = $stubsFields[$fieldType]; 134 | $stub = $this->buildStub($variablesFromField, $stub); 135 | $stub = $this->buildStub($metas, $stub); 136 | 137 | $stubs[] = $stub; 138 | } 139 | 140 | return join(' ', $stubs); 141 | } 142 | 143 | private function getVariablesFromField($options) 144 | { 145 | $data = []; 146 | 147 | $data['field.name'] = $options['name']; 148 | $data['field.Name'] = ucwords($options['name']); 149 | $data['field.type'] = @$options['type']; 150 | $data['field.value.default'] = @$options['options']['default']; 151 | 152 | return $data; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/Makes/MakerTrait.php: -------------------------------------------------------------------------------- 1 | files = $files; 32 | $this->scaffoldCommandM = $scaffoldCommand; 33 | 34 | $this->generateNames($this->scaffoldCommandM); 35 | } 36 | 37 | protected function getArrayRecursive(array $array, $parent = '') 38 | { 39 | $data = []; 40 | 41 | foreach ($array as $key => $value) 42 | { 43 | if(gettype($value) == 'array') 44 | { 45 | array_merge( 46 | $data, 47 | $this->getArrayRecursive($value, "$parent") 48 | ); 49 | continue; 50 | } 51 | 52 | $data["$parent.$key"] = $value; 53 | } 54 | 55 | return $data; 56 | } 57 | 58 | 59 | protected function getFilesRecursive($path) 60 | { 61 | $files = []; 62 | $scan = array_diff(scandir($path), ['.', '..']); 63 | 64 | foreach ($scan as $file) 65 | { 66 | $file = realpath("$path$file"); 67 | 68 | if(is_dir($file)) 69 | { 70 | $files = array_merge 71 | ( 72 | $files, 73 | $this->getFilesRecursive($file.DIRECTORY_SEPARATOR) 74 | ); 75 | continue; 76 | } 77 | 78 | $files[] = $file; 79 | } 80 | 81 | return $files; 82 | } 83 | 84 | /** 85 | * Get stub path. 86 | * 87 | * @param $file_name 88 | * @param string $path 89 | * @return string 90 | */ 91 | protected function getStubPath() 92 | { 93 | return substr(__DIR__,0, -5) . 'Stubs/'; 94 | } 95 | 96 | /** 97 | * Get fields stubs. 98 | * 99 | * @return array fields 100 | */ 101 | protected function getStubFields($ui, $type) 102 | { 103 | $stubsFieldsPath= $this->getStubPath()."views/$ui/fields/$type/"; 104 | 105 | if($this->existsDirectory($stubsFieldsPath)) 106 | { 107 | $this->scaffoldCommandM->error('Stub not found'); 108 | return; 109 | } 110 | 111 | $stubsFieldsFiles = $this->getFilesRecursive($stubsFieldsPath); 112 | 113 | $stubs = []; 114 | 115 | foreach ($stubsFieldsFiles as $file) 116 | { 117 | $stubs[str_replace($stubsFieldsPath, '', $file)] = $this->getFile($file); 118 | } 119 | 120 | return $stubs; 121 | } 122 | 123 | /** 124 | * Get views stubs. 125 | * 126 | * @return array views 127 | */ 128 | protected function getStubViews($ui) 129 | { 130 | $viewsPath = $this->getStubPath()."views/$ui/pages/"; 131 | $files = $this->getFilesRecursive($viewsPath); 132 | $viewFiles = []; 133 | 134 | foreach ($files as $file) 135 | { 136 | $viewFiles[str_replace($viewsPath, '', $file)] = $file; 137 | } 138 | 139 | return $viewFiles; 140 | } 141 | 142 | 143 | protected function getDestinationViews($model) 144 | { 145 | return "./resources/views/$model/"; 146 | } 147 | 148 | /** 149 | * Build file replacing metas in template. 150 | * 151 | * @param array $metas 152 | * @param string &$template 153 | * @return void 154 | */ 155 | protected function buildStub(array $metas, &$template) 156 | { 157 | foreach($metas as $k => $v) 158 | { 159 | $template = str_replace("{{". $k ."}}", $v, $template); 160 | } 161 | 162 | return $template; 163 | } 164 | 165 | /** 166 | * Get the path to where we should store the controller. 167 | * 168 | * @param $file_name 169 | * @param string $path 170 | * @return string 171 | */ 172 | protected function getPath($file_name, $path='controller') 173 | { 174 | if($path == "controller") 175 | { 176 | return './app/Http/Controllers/' . $file_name . '.php'; 177 | } 178 | elseif($path == "model") 179 | { 180 | return './app/'.$file_name.'.php'; 181 | } 182 | elseif($path == "seed") 183 | { 184 | return './database/seeds/'.$file_name.'.php'; 185 | } 186 | elseif($path == "view-index") 187 | { 188 | return './resources/views/'.$file_name.'/index.blade.php'; 189 | } 190 | elseif($path == "view-edit") 191 | { 192 | return './resources/views/'.$file_name.'/edit.blade.php'; 193 | } 194 | elseif($path == "view-show") 195 | { 196 | return './resources/views/'.$file_name.'/show.blade.php'; 197 | } 198 | elseif($path == "view-create") 199 | { 200 | return './resources/views/'.$file_name.'/create.blade.php'; 201 | } 202 | elseif($path == "localization"){ 203 | return './resources/lang/'.$file_name.'.php'; 204 | } 205 | elseif($path == "route"){ 206 | return './app/Http/routes.php'; 207 | } 208 | } 209 | 210 | protected function getFile($file) 211 | { 212 | return $this->files->get($file); 213 | } 214 | 215 | protected function existsDirectory($path) 216 | { 217 | return !$this->files->isDirectory($path); 218 | } 219 | 220 | /** 221 | * Build the directory for the class if necessary. 222 | * 223 | * @param string $path 224 | * @return string 225 | */ 226 | protected function makeDirectory($path) 227 | { 228 | if ( ! $this->files->isDirectory(dirname($path))) 229 | { 230 | $this->files->makeDirectory(dirname($path), 0777, true, true); 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/Migrations/NameParser.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class NameParser 11 | { 12 | 13 | /** 14 | * Parse the migration name into something we can use. 15 | * 16 | * @param string $name 17 | * @return array 18 | */ 19 | public function parse($name) 20 | { 21 | $segments = array_reverse(explode('_', $name)); 22 | 23 | if ($segments[0] == 'table') { 24 | array_shift($segments); 25 | } 26 | 27 | return [ 28 | 'action' => $this->getAction($segments), 29 | 'table' => $this->getTableName($segments) 30 | ]; 31 | } 32 | 33 | /** 34 | * Calculate the table name. 35 | * 36 | * @param array $segments 37 | * @return array 38 | */ 39 | private function getTableName($segments) 40 | { 41 | $tableName = []; 42 | 43 | foreach ($segments as $segment) { 44 | if ($this->isConnectingWord($segment)) { 45 | break; 46 | } 47 | 48 | $tableName[] = $segment; 49 | } 50 | 51 | return implode('_', array_reverse($tableName)); 52 | } 53 | 54 | /** 55 | * Determine the user's desired action for the migration. 56 | * 57 | * @param array $segments 58 | * @return mixed 59 | */ 60 | private function getAction(&$segments) 61 | { 62 | return $this->normalizeActionName(array_pop($segments)); 63 | } 64 | 65 | /** 66 | * Normalize the user's chosen action to name to 67 | * something that we recognize. 68 | * 69 | * @param string $action 70 | * @return string 71 | */ 72 | private function normalizeActionName($action) 73 | { 74 | switch ($action) { 75 | case 'create': 76 | case 'make': 77 | return 'create'; 78 | case 'delete': 79 | case 'destroy': 80 | case 'drop': 81 | return 'remove'; 82 | case 'add': 83 | case 'append': 84 | case 'update': 85 | case 'insert': 86 | return 'add'; 87 | default: 88 | return $action; 89 | } 90 | } 91 | 92 | /** 93 | * Determine if the current segment is a connecting word. 94 | * 95 | * @param string $segment 96 | * @return bool 97 | */ 98 | private function isConnectingWord($segment) 99 | { 100 | $connectors = ['to', 'from', 'and', 'with', 'for', 'in', 'of', 'on']; 101 | 102 | return in_array($segment, $connectors); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/Migrations/SchemaParser.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class SchemaParser 11 | { 12 | 13 | /** 14 | * The parsed schema. 15 | * 16 | * @var array 17 | */ 18 | private $schema = []; 19 | 20 | /** 21 | * Parse the command line migration schema. 22 | * Ex: name:string, age:integer:nullable 23 | * 24 | * @param string $schema 25 | * @return array 26 | */ 27 | public function parse($schema) 28 | { 29 | $fields = $this->splitIntoFields($schema); 30 | 31 | foreach ($fields as $field) { 32 | $segments = $this->parseSegments($field); 33 | 34 | if ($this->fieldNeedsForeignConstraint($segments)) { 35 | unset($segments['options']['foreign']); 36 | 37 | // If the user wants a foreign constraint, then 38 | // we'll first add the regular field. 39 | $this->addField($segments); 40 | 41 | // And then add another field for the constraint. 42 | $this->addForeignConstraint($segments); 43 | 44 | continue; 45 | } 46 | 47 | $this->addField($segments); 48 | } 49 | 50 | return $this->schema; 51 | } 52 | 53 | /** 54 | * Add a field to the schema array. 55 | * 56 | * @param array $field 57 | * @return $this 58 | */ 59 | private function addField($field) 60 | { 61 | $this->schema[] = $field; 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * Get an array of fields from the given schema. 68 | * 69 | * @param string $schema 70 | * @return array 71 | */ 72 | private function splitIntoFields($schema) 73 | { 74 | return preg_split('/,\s?(?![^()]*\))/', $schema); 75 | } 76 | 77 | /** 78 | * Get the segments of the schema field. 79 | * 80 | * @param string $field 81 | * @return array 82 | */ 83 | private function parseSegments($field) 84 | { 85 | $segments = explode(':', $field); 86 | 87 | $name = array_shift($segments); 88 | $type = array_shift($segments); 89 | $arguments = []; 90 | $options = $this->parseOptions($segments); 91 | 92 | // Do we have arguments being used here? 93 | // Like: string(100) 94 | if (preg_match('/(.+?)\(([^)]+)\)/', $type, $matches)) { 95 | $type = $matches[1]; 96 | $arguments = explode(',', $matches[2]); 97 | } 98 | 99 | return compact('name', 'type', 'arguments', 'options'); 100 | } 101 | 102 | /** 103 | * Parse any given options into something usable. 104 | * 105 | * @param array $options 106 | * @return array 107 | */ 108 | private function parseOptions($options) 109 | { 110 | if (empty($options)) return []; 111 | 112 | foreach ($options as $option) { 113 | if (str_contains($option, '(')) { 114 | preg_match('/([a-z]+)\(([^\)]+)\)/i', $option, $matches); 115 | 116 | $results[$matches[1]] = $matches[2]; 117 | } else { 118 | $results[$option] = true; 119 | } 120 | } 121 | 122 | return $results; 123 | } 124 | 125 | /** 126 | * Add a foreign constraint field to the schema. 127 | * 128 | * @param array $segments 129 | */ 130 | private function addForeignConstraint($segments) 131 | { 132 | $string = sprintf( 133 | "%s:foreign:references('id'):on('%s')", 134 | $segments['name'], 135 | $this->getTableNameFromForeignKey($segments['name']) 136 | ); 137 | 138 | $this->addField($this->parseSegments($string)); 139 | } 140 | 141 | /** 142 | * Try to figure out the name of a table from a foreign key. 143 | * Ex: user_id => users 144 | * 145 | * @param string $key 146 | * @return string 147 | */ 148 | private function getTableNameFromForeignKey($key) 149 | { 150 | return str_plural(str_replace('_id', '', $key)); 151 | } 152 | 153 | /** 154 | * Determine if the user wants a foreign constraint for the field. 155 | * 156 | * @param array $segments 157 | * @return bool 158 | */ 159 | private function fieldNeedsForeignConstraint($segments) 160 | { 161 | return array_key_exists('foreign', $segments['options']); 162 | } 163 | 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/Migrations/SyntaxBuilder.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class SyntaxBuilder 14 | { 15 | 16 | /** 17 | * A template to be inserted. 18 | * 19 | * @var string 20 | */ 21 | private $template; 22 | 23 | /** 24 | * @var bool 25 | */ 26 | protected $illuminate = false; 27 | 28 | /** 29 | * Enable/Disable use of Illuminate/Html form facades 30 | * 31 | * @param $value 32 | */ 33 | public function setIllumination($value) { 34 | $this->illuminate = $value; 35 | } 36 | 37 | /** 38 | * Create the PHP syntax for the given schema. 39 | * 40 | * @param array $schema 41 | * @param array $meta 42 | * @param string $type 43 | * @param bool $illuminate 44 | * @return string 45 | * @throws GeneratorException 46 | * @throws \Exception 47 | */ 48 | public function create($schema, $meta, $type = "migration", $illuminate = false) 49 | { 50 | $this->setIllumination($illuminate); 51 | 52 | if ($type == "migration") { 53 | 54 | $up = $this->createSchemaForUpMethod($schema, $meta); 55 | $down = $this->createSchemaForDownMethod($schema, $meta); 56 | return compact('up', 'down'); 57 | 58 | 59 | } else if ($type == "controller") { 60 | 61 | $fieldsc = $this->createSchemaForControllerMethod($schema, $meta); 62 | return $fieldsc; 63 | 64 | 65 | } else if ($type == "view-index-header") { 66 | 67 | $fieldsc = $this->createSchemaForViewMethod($schema, $meta, 'index-header'); 68 | return $fieldsc; 69 | 70 | } else if ($type == "view-index-content") { 71 | 72 | $fieldsc = $this->createSchemaForViewMethod($schema, $meta, 'index-content'); 73 | return $fieldsc; 74 | 75 | } else if ($type == "view-show-content") { 76 | 77 | $fieldsc = $this->createSchemaForViewMethod($schema, $meta, 'show-content'); 78 | return $fieldsc; 79 | 80 | } else if ($type == "view-edit-content") { 81 | 82 | $fieldsc = $this->createSchemaForViewMethod($schema, $meta, 'edit-content'); 83 | return $fieldsc; 84 | 85 | } else if ($type == "view-create-content") { 86 | 87 | $fieldsc = $this->createSchemaForViewMethod($schema, $meta, 'create-content'); 88 | return $fieldsc; 89 | 90 | } else { 91 | throw new \Exception("Type not found in syntaxBuilder"); 92 | } 93 | } 94 | 95 | /** 96 | * Create the schema for the "up" method. 97 | * 98 | * @param string $schema 99 | * @param array $meta 100 | * @return string 101 | * @throws GeneratorException 102 | */ 103 | private function createSchemaForUpMethod($schema, $meta) 104 | { 105 | //dd($schema); 106 | $fields = $this->constructSchema($schema); 107 | 108 | 109 | if ($meta['action'] == 'create') { 110 | return $this->insert($fields)->into($this->getCreateSchemaWrapper()); 111 | } 112 | 113 | if ($meta['action'] == 'add') { 114 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 115 | } 116 | 117 | if ($meta['action'] == 'remove') { 118 | $fields = $this->constructSchema($schema, 'Drop'); 119 | 120 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 121 | } 122 | 123 | // Otherwise, we have no idea how to proceed. 124 | throw new GeneratorException; 125 | } 126 | 127 | 128 | /** 129 | * Construct the syntax for a down field. 130 | * 131 | * @param array $schema 132 | * @param array $meta 133 | * @return string 134 | * @throws GeneratorException 135 | */ 136 | private function createSchemaForDownMethod($schema, $meta) 137 | { 138 | // If the user created a table, then for the down 139 | // method, we should drop it. 140 | if ($meta['action'] == 'create') { 141 | return sprintf("Schema::drop('%s');", $meta['table']); 142 | } 143 | 144 | // If the user added columns to a table, then for 145 | // the down method, we should remove them. 146 | if ($meta['action'] == 'add') { 147 | $fields = $this->constructSchema($schema, 'Drop'); 148 | 149 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 150 | } 151 | 152 | // If the user removed columns from a table, then for 153 | // the down method, we should add them back on. 154 | if ($meta['action'] == 'remove') { 155 | $fields = $this->constructSchema($schema); 156 | 157 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 158 | } 159 | 160 | // Otherwise, we have no idea how to proceed. 161 | throw new GeneratorException; 162 | } 163 | 164 | /** 165 | * Store the given template, to be inserted somewhere. 166 | * 167 | * @param string $template 168 | * @return $this 169 | */ 170 | private function insert($template) 171 | { 172 | $this->template = $template; 173 | 174 | return $this; 175 | } 176 | 177 | /** 178 | * Get the stored template, and insert into the given wrapper. 179 | * 180 | * @param string $wrapper 181 | * @param string $placeholder 182 | * @return mixed 183 | */ 184 | private function into($wrapper, $placeholder = 'schema_up') 185 | { 186 | return str_replace('{{' . $placeholder . '}}', $this->template, $wrapper); 187 | } 188 | 189 | /** 190 | * Get the wrapper template for a "create" action. 191 | * 192 | * @return string 193 | */ 194 | private function getCreateSchemaWrapper() 195 | { 196 | return file_get_contents(__DIR__ . '/../Stubs/schema-create.stub'); 197 | } 198 | 199 | /** 200 | * Get the wrapper template for an "add" action. 201 | * 202 | * @return string 203 | */ 204 | private function getChangeSchemaWrapper() 205 | { 206 | return file_get_contents(__DIR__ . '/../Stubs/schema-change.stub'); 207 | } 208 | 209 | /** 210 | * Construct the schema fields. 211 | * 212 | * @param array $schema 213 | * @param string $direction 214 | * @return array 215 | */ 216 | private function constructSchema($schema, $direction = 'Add') 217 | { 218 | if (!$schema) return ''; 219 | 220 | $fields = array_map(function ($field) use ($direction) { 221 | $method = "{$direction}Column"; 222 | return $this->$method($field); 223 | }, $schema); 224 | 225 | 226 | return implode("\n" . str_repeat(' ', 12), $fields); 227 | } 228 | 229 | 230 | /** 231 | * Construct the syntax to add a column. 232 | * 233 | * @param string $field 234 | * @param string $type 235 | * @param $meta 236 | * @return string 237 | */ 238 | private function addColumn($field, $type = "migration", $meta = "") 239 | { 240 | 241 | 242 | if ($type == 'migration') { 243 | 244 | $syntax = sprintf("\$table->%s('%s')", $field['type'], $field['name']); 245 | 246 | // If there are arguments for the schema type, like decimal('amount', 5, 2) 247 | // then we have to remember to work those in. 248 | if ($field['arguments']) { 249 | $syntax = substr($syntax, 0, -1) . ', '; 250 | 251 | $syntax .= implode(', ', $field['arguments']) . ')'; 252 | } 253 | 254 | foreach ($field['options'] as $method => $value) { 255 | $syntax .= sprintf("->%s(%s)", $method, $value === true ? '' : $value); 256 | } 257 | 258 | $syntax .= ';'; 259 | 260 | 261 | } elseif ($type == 'view-index-header') { 262 | 263 | // Fields to index view 264 | $syntax = sprintf("%s", strtoupper($field['name'])); 265 | $syntax .= ''; 266 | 267 | } elseif ($type == 'view-index-content') { 268 | 269 | // Fields to index view 270 | $syntax = sprintf("{{\$%s->%s", $meta['var_name'], strtolower($field['name'])); 271 | $syntax .= '}}'; 272 | 273 | } elseif ($type == 'view-show-content') { 274 | 275 | // Fields to show view 276 | $syntax = sprintf("
\n" . 277 | str_repeat(' ', 21) . "\n" . 278 | str_repeat(' ', 21) . "

{{\$%s->%s}}

\n" . 279 | str_repeat(' ', 16) . "
", strtolower($field['name']), strtoupper($field['name']), $meta['var_name'], strtolower($field['name'])); 280 | 281 | 282 | } elseif ($type == 'view-edit-content') { 283 | $syntax = $this->buildField($field, $type, $meta['var_name']); 284 | } elseif ($type == 'view-create-content') { 285 | $syntax = $this->buildField($field, $type, $meta['var_name'], false); 286 | } else { 287 | // Fields to controller 288 | $syntax = sprintf("\$%s->%s = \$request->input(\"%s", $meta['var_name'], $field['name'], $field['name']); 289 | $syntax .= '");'; 290 | } 291 | 292 | 293 | return $syntax; 294 | } 295 | 296 | /** 297 | * Build form field with validation using Illuminate/Html Form facade or pure HTML 298 | * 299 | * @param $field 300 | * @param $variable 301 | * @param bool $value 302 | * @return string 303 | */ 304 | private function buildField($field, $type, $variable, $value = true) 305 | { 306 | $column = strtolower($field['name']); 307 | $title = ucfirst($field['name']); 308 | 309 | if ($value === true) { 310 | $value = '$' . $variable . '->' . $column; 311 | } else { 312 | $value = 'old("'.$column.'")'; 313 | } 314 | 315 | $syntax = []; 316 | 317 | switch($type) { 318 | case 'string': 319 | default: 320 | $input = 'text'; 321 | break; 322 | case 'text': 323 | $input = 'textarea'; 324 | break; 325 | } 326 | 327 | $syntax[] = '
'; 328 | $syntax[] = ' '; 329 | 330 | if($this->illuminate) { 331 | $syntax[] = ' {!! Form::' . $input . '("' . $column . '", ' . $value . ', array("class" => "form-control", "id" => "' . $column . '-field")) !!}'; 332 | } else { 333 | $syntax[] = $this->htmlField($column, $variable, $field, $type); 334 | } 335 | 336 | $syntax[] = ' @if($errors->has("' . $column . '"))'; 337 | $syntax[] = ' {{ $errors->first("' . $column . '") }}'; 338 | $syntax[] = ' @endif'; 339 | $syntax[] = '
'; 340 | 341 | return join("\n".str_repeat(' ', 20), $syntax); 342 | } 343 | 344 | 345 | /** 346 | * Construct the syntax to drop a column. 347 | * 348 | * @param string $field 349 | * @return string 350 | */ 351 | private function dropColumn($field) 352 | { 353 | return sprintf("\$table->dropColumn('%s');", $field['name']); 354 | } 355 | 356 | 357 | /** 358 | * Construct the controller fields 359 | * 360 | * @param $schema 361 | * @param $meta 362 | * @return string 363 | */ 364 | private function createSchemaForControllerMethod($schema, $meta) 365 | { 366 | 367 | 368 | if (!$schema) return ''; 369 | 370 | $fields = array_map(function ($field) use ($meta) { 371 | return $this->AddColumn($field, 'controller', $meta); 372 | }, $schema); 373 | 374 | 375 | return implode("\n" . str_repeat(' ', 8), $fields); 376 | } 377 | 378 | 379 | /** 380 | * Construct the view fields 381 | * 382 | * @param $schema 383 | * @param $meta 384 | * @param string $type Params 'header' or 'content' 385 | * @return string 386 | */ 387 | private function createSchemaForViewMethod($schema, $meta, $type = 'index-header') 388 | { 389 | 390 | 391 | if (!$schema) return ''; 392 | 393 | $fields = array_map(function ($field) use ($meta, $type) { 394 | return $this->AddColumn($field, 'view-' . $type, $meta); 395 | }, $schema); 396 | 397 | 398 | // Format code 399 | if ($type == 'index-header') { 400 | return implode("\n" . str_repeat(' ', 24), $fields); 401 | } else { 402 | // index-content 403 | return implode("\n" . str_repeat(' ', 20), $fields); 404 | } 405 | 406 | } 407 | 408 | private function htmlField($column, $variable, $field, $type) 409 | { 410 | 411 | $value = '{{ old("'.$column.'") }}'; 412 | 413 | if($type == 'view-edit-content') 414 | { 415 | $value = '{{ is_null(old("'.$column.'")) ? $'.$variable.'->'.$column.' : old("'.$column.'") }}'; 416 | } 417 | 418 | switch ($field['type']) { 419 | case 'date': 420 | $layout = ""; 421 | break; 422 | case 'boolean': 423 | $layout = "
"; 424 | break; 425 | case 'text': 426 | $layout = ""; 427 | break; 428 | case 'string': 429 | default: 430 | $layout = ""; 431 | } 432 | 433 | return $layout; 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/Stubs/controller.stub: -------------------------------------------------------------------------------- 1 | model = $model; 26 | } 27 | 28 | /** 29 | * Display a listing of the resource. 30 | * 31 | * @return Response 32 | */ 33 | public function index() 34 | { 35 | ${{models}} = $this->model->paginate(); 36 | 37 | return view('{{models}}.index', compact('{{models}}')); 38 | } 39 | 40 | /** 41 | * Show the form for creating a new resource. 42 | * 43 | * @return Response 44 | */ 45 | public function create() 46 | { 47 | return view('{{models}}.create'); 48 | } 49 | 50 | /** 51 | * Store a newly created resource in storage. 52 | * 53 | * @param Request $request 54 | * @return Response 55 | */ 56 | public function store(Request $request) 57 | { 58 | $inputs = $request->all(); 59 | $this->model->create($inputs); 60 | 61 | return redirect()->route('{{prefix}}{{models}}.index')->with('message', 'Item created successfully.'); 62 | } 63 | 64 | /** 65 | * Display the specified resource. 66 | * 67 | * @param int $id 68 | * @return Response 69 | */ 70 | public function show($id) 71 | { 72 | ${{model}} = $this->model->findOrFail($id); 73 | 74 | return view('{{models}}.show', compact('{{model}}')); 75 | } 76 | 77 | /** 78 | * Show the form for editing the specified resource. 79 | * 80 | * @param int $id 81 | * @return Response 82 | */ 83 | public function edit($id) 84 | { 85 | ${{model}} = $this->model->findOrFail($id); 86 | 87 | return view('{{models}}.edit', compact('{{model}}')); 88 | } 89 | 90 | /** 91 | * Update the specified resource in storage. 92 | * 93 | * @param int $id 94 | * @param Request $request 95 | * @return Response 96 | */ 97 | public function update(Request $request, $id) 98 | { 99 | $inputs = $request->all(); 100 | 101 | ${{model}} = $this->model->findOrFail($id); 102 | ${{model}}->update($inputs); 103 | 104 | return redirect()->route('{{prefix}}{{models}}.index')->with('message', 'Item updated successfully.'); 105 | } 106 | 107 | /** 108 | * Remove the specified resource from storage. 109 | * 110 | * @param int $id 111 | * @return Response 112 | */ 113 | public function destroy($id) 114 | { 115 | $this->model->destroy($id); 116 | 117 | return redirect()->route('{{prefix}}{{models}}.index')->with('message', 'Item deleted successfully.'); 118 | } 119 | } -------------------------------------------------------------------------------- /src/Stubs/localization.stub: -------------------------------------------------------------------------------- 1 | integer('{{columnOne}}_id')->unsigned()->index(); 18 | $table->foreign('{{columnOne}}_id')->references('id')->on('{{tableOne}}')->onDelete('cascade'); 19 | $table->integer('{{columnTwo}}_id')->unsigned()->index(); 20 | $table->foreign('{{columnTwo}}_id')->references('id')->on('{{tableTwo}}')->onDelete('cascade'); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::drop('{{pivotTableName}}'); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/Stubs/route.stub: -------------------------------------------------------------------------------- 1 | Route::resource('{{models}}', '{{Model}}Controller'); -------------------------------------------------------------------------------- /src/Stubs/schema-change.stub: -------------------------------------------------------------------------------- 1 | Schema::table('{{models}}', function(Blueprint $table) { 2 | {{schema_up}} 3 | }); -------------------------------------------------------------------------------- /src/Stubs/schema-create.stub: -------------------------------------------------------------------------------- 1 | Schema::create('{{models}}', function(Blueprint $table) { 2 | $table->increments('id'); 3 | {{schema_up}} 4 | $table->timestamps(); 5 | }); -------------------------------------------------------------------------------- /src/Stubs/seed.stub: -------------------------------------------------------------------------------- 1 | create('App\{{Model}}'); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /src/Stubs/views/bs3/error.blade.php.stub: -------------------------------------------------------------------------------- 1 | @if (count($errors) > 0) 2 |
3 |

There were some problems with your input.

4 | 9 |
10 | @endif -------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/content/default: -------------------------------------------------------------------------------- 1 | {{${{model}}->{{field.name}}}} -------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/empty/default: -------------------------------------------------------------------------------- 1 |
2 | 3 | --{{field.name}}-- 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/empty/string: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/empty/text: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/fillable/default: -------------------------------------------------------------------------------- 1 |
2 | 3 | --{{field.name}}-- 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/fillable/string: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/fillable/text: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
-------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/header/default: -------------------------------------------------------------------------------- 1 | {{field.Name}} -------------------------------------------------------------------------------- /src/Stubs/views/bs3/fields/show/default: -------------------------------------------------------------------------------- 1 | 2 |

3 | {{ ${{model}}->{{field.name}} }} 4 |

-------------------------------------------------------------------------------- /src/Stubs/views/bs3/layout.blade.php.stub: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Starter Template 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | @yield('css') 49 | 50 | 51 | 52 | 53 | 71 | 72 |
73 | @if(session('message')) 74 | 80 | @endif 81 | 82 | @yield('header') 83 | @yield('content') 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | @yield('scripts') 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/Stubs/views/bs3/pages/create.blade.php.stub: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('header') 4 | 7 | @endsection 8 | 9 | @section('content') 10 | @include('error') 11 | 12 |
13 |
14 | 15 |
16 | 17 | 18 | {{form_fields_empty}} 19 | 20 |
21 | 22 | Back 23 |
24 |
25 | 26 |
27 |
28 | @endsection -------------------------------------------------------------------------------- /src/Stubs/views/bs3/pages/edit.blade.php.stub: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('header') 4 | 7 | @endsection 8 | 9 | @section('content') 10 | @include('error') 11 | 12 |
13 |
14 | 15 |
16 | 17 | 18 | 19 | {{form_fields_fillable}} 20 | 21 |
22 | 23 | Back 24 |
25 |
26 | 27 |
28 |
29 | @endsection -------------------------------------------------------------------------------- /src/Stubs/views/bs3/pages/index.blade.php.stub: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | 3 | @section('header') 4 | 10 | @endsection 11 | 12 | @section('content') 13 |
14 |
15 | @if(${{models}}->count()) 16 | 17 | 18 | 19 | 20 | {{table_fields_header}} 21 | 22 | 23 | 24 | 25 | 26 | @foreach(${{models}} as ${{model}}) 27 | 28 | 29 | 30 | {{table_fields_content}} 31 | 32 | 48 | 49 | @endforeach 50 | 51 |
#OPTIONS
{{${{model}}->id}} 33 | 34 | View 35 | 36 | 37 | 38 | Edit 39 | 40 | 41 |
42 | {{csrf_field()}} 43 | 44 | 45 | 46 |
47 |
52 | {!! ${{models}}->render() !!} 53 | @else 54 |

Empty!

55 | @endif 56 | 57 |
58 |
59 | 60 | @endsection -------------------------------------------------------------------------------- /src/Stubs/views/bs3/pages/show.blade.php.stub: -------------------------------------------------------------------------------- 1 | @extends('layout') 2 | @section('header') 3 | 6 | @endsection 7 | 8 | @section('content') 9 |
10 |
11 |
12 | Back 13 |
14 | 19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | {{form_fields_show}} 27 | 28 |
29 | 30 |
31 | @endsection 32 | -------------------------------------------------------------------------------- /src/Validators/SchemaParser.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class SchemaParser 11 | { 12 | 13 | /** 14 | * The parsed schema. 15 | * 16 | * @var array 17 | */ 18 | private $schema = []; 19 | 20 | /** 21 | * Parse the command line migration schema. 22 | * Ex: name:string, age:integer:nullable 23 | * 24 | * @param string $schema 25 | * @return array 26 | */ 27 | public function parse($schema) 28 | { 29 | $fields = $this->splitIntoFields($schema); 30 | 31 | foreach ($fields as $field) { 32 | $segments = $this->parseSegments($field); 33 | 34 | $this->addField($segments); 35 | } 36 | 37 | return $this->schema; 38 | } 39 | 40 | /** 41 | * Add a field to the schema array. 42 | * 43 | * @param array $field 44 | * @return $this 45 | */ 46 | private function addField($field) 47 | { 48 | $this->schema[] = $field; 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * Get an array of fields from the given schema. 55 | * 56 | * @param string $schema 57 | * @return array 58 | */ 59 | private function splitIntoFields($schema) 60 | { 61 | return preg_split('/,\s?(?![^()]*\))/', $schema); 62 | } 63 | 64 | /** 65 | * Get the segments of the schema field. 66 | * 67 | * @param string $field 68 | * @return array 69 | */ 70 | private function parseSegments($field) 71 | { 72 | $segments = explode(':', $field); 73 | 74 | $name = array_shift($segments); 75 | $arguments = $segments; 76 | // Do we have arguments being used here? 77 | // Like: string(100) 78 | return compact('name', 'arguments'); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/Validators/SyntaxBuilder.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class SyntaxBuilder 11 | { 12 | 13 | /** 14 | * Create the PHP syntax for the given schema. 15 | * 16 | * @param array $schema 17 | * @param array $meta 18 | * @param string $type 19 | * @param bool $illuminate 20 | * @return string 21 | * @throws GeneratorException 22 | * @throws \Exception 23 | */ 24 | public function create($schema) 25 | { 26 | $fieldsc = $this->createSchemaForValidation($schema); 27 | return $fieldsc; 28 | } 29 | 30 | private function createSchemaForValidation($schema) 31 | { 32 | $validator = ''; 33 | if(is_array($schema)) { 34 | foreach ($schema as $s) { 35 | $validator .= "'" . $s['name'] . "' => '"; 36 | 37 | #deal with the different format of the console 38 | if(isset($s['arguments'][0]) && $s['arguments'][0] != null ) { 39 | $validator .= str_replace(")", "", str_replace("(", ":", $s['arguments'][0])); 40 | $validator .= "',\n\t\t\t"; 41 | } 42 | } 43 | return $validator; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/CommandTest.php: -------------------------------------------------------------------------------- 1 | prepareFolderStructure(); 24 | 25 | $this->createApplication(); 26 | 27 | $this->mountFolderStructure(); 28 | } 29 | 30 | public function tearDown() 31 | { 32 | $this->unmontFolderStructure(); 33 | } 34 | 35 | public function createApplication() 36 | { 37 | $this->app = require __DIR__.'/../vendor/laravel/laravel/bootstrap/app.php'; 38 | 39 | $this->app->register('Laralib\L5scaffold\GeneratorsServiceProvider'); 40 | 41 | $this->app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); 42 | } 43 | 44 | public function prepareFolderStructure() 45 | { 46 | $this->filesystem = new Filesystem(); 47 | 48 | $this->folders = 49 | [ 50 | 'app/Http/Controllers', 51 | 'database/seeds', 52 | 'database/migrations', 53 | 'resources/views' 54 | ]; 55 | } 56 | 57 | public function mountFolderStructure() 58 | { 59 | foreach($this->folders as $folder) 60 | { 61 | $this->filesystem->makeDirectory($folder, 0777, true, true); 62 | } 63 | } 64 | 65 | public function unmontFolderStructure() 66 | { 67 | foreach ($this->folders as $folder) 68 | { 69 | $this->filesystem->deleteDirectory(explode("/", $folder)[0]); 70 | } 71 | } 72 | 73 | public function testExecuteCommand() 74 | { 75 | Artisan::call('make:scaffold', 76 | [ 77 | 'name' => 'Tweet', 78 | '--schema' => 'title:string', 79 | '--validator' => 'title:required|unique:tweets,id', 80 | '--no-interaction' 81 | ]); 82 | 83 | Artisan::call('make:scaffold', 84 | [ 85 | 'name' => 'Tweet2', 86 | '--schema' => 'title:string', 87 | '--localization' => 'title:required', 88 | '--lang' => 'fr', 89 | '--no-interaction' 90 | ]); 91 | } 92 | } -------------------------------------------------------------------------------- /tests/StartTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); // Yeah \o/ Tests 12 | } 13 | } --------------------------------------------------------------------------------