Skip to content

Instantly share code, notes, and snippets.

@jeff-silva
Last active October 31, 2021 05:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeff-silva/f8eeb7f7dab044fe842a2c3402dbd486 to your computer and use it in GitHub Desktop.
Save jeff-silva/f8eeb7f7dab044fe842a2c3402dbd486 to your computer and use it in GitHub Desktop.
LaravelCommands
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppBase extends Command
{
protected $signature = 'app:base';
protected $description = 'Classe base';
public function handle()
{
//
}
public function getFieldSchema($field) {
$field = (array) $field;
$schema = [ $field['Type'] ];
$schema[] = (($field['Null']=='NO' || $field['Key']=='PRI')? 'NOT NULL': 'NULL');
if ($field['Extra']=='auto_increment') $schema[] = 'AUTO_INCREMENT';
if ($field['Key'] != 'PRI' AND !str_contains($field['Type'], 'varchar') AND !str_contains($field['Type'], 'int') AND $field['Type']!='longtext' AND $field['Type']!='timestamp') {
$schema[] = ($field['Default']===NULL? 'DEFAULT NULL': "DEFAULT '{$field['Default']}'");
}
return implode(' ', $schema);
}
public function varExport($data) {
$dump = var_export($data, true);
$dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
$dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
$dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
if (gettype($data) == 'object') { // Deal with object states
$dump = str_replace('__set_state(array(', '__set_state([', $dump);
$dump = preg_replace('#\)\)$#', "])", $dump);
}
else { $dump = preg_replace('#\)$#', "]", $dump); }
return $dump;
}
public function classSource($class) {
if (is_string($class)) {
$class = app($this->Model->Namespace);
}
$class = new \ReflectionClass($class);
$fileName = $class->getFileName();
$startLine = $class->getStartLine()-1;
$endLine = $class->getEndLine();
$numLines = $endLine - $startLine;
$fileContents = null;
if(!empty($fileName)) {
$fileContents = file_get_contents($fileName);
$classSource = trim(implode('', array_slice(file($fileName), $startLine, $numLines))); // not perfect; if the class starts or ends on the same line as something else, this will be incorrect
// $hash = crc32($classSource);
}
return $fileContents;
}
public function classWriteMethod($class, $method_name, $method_content) {
$file = (new \ReflectionClass($class))->getFileName();
if (is_string($class)) {
$class = app($class);
}
$source = $this->classSource($class);
if (method_exists($class, $method_name)) {
$source = preg_replace("/\t+public function {$method_name}(.+?)\}/s", $method_content, $source);
}
else {
$source = rtrim(rtrim($source), '}') ."\n{$method_content}\n}";
}
file_put_contents($file, $source);
}
public function classWriteMethodOld($class, $method_name, $method_content) {
$class = "{$table['ModelNamespace']}\\{$table['Model']}";
if (is_string($class)) {
$class = app($class);
}
$source = $this->classSource($class);
dd($source);
if (method_exists($class, $method_name)) {
// $source = preg_replace("/\t+public function {$method_name}(.+?)\}/s", $method_content, $source);
}
else {
$source = rtrim(rtrim($source), '}') ."\n{$method_content}\n}";
}
file_put_contents(base_path($table['ModelFile']), $source);
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppBuild extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:build';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Build de aplicação';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// $this->comment('⚙️ Criando/alterando models');
// if (app()->environment('production')) {
// // Sincronizar tabelas
// return;
// }
$commands = [];
$commands[] = [
'title' => 'Migrate',
'command' => 'migrate',
];
$commands[] = [
'title' => 'Seed',
'command' => 'db:seed',
];
$commands[] = [
'title' => 'Limpar caches',
'command' => 'app:clear',
];
$commands[] = [
'title' => 'Cria configurações e schemas',
'command' => 'app:schema',
];
$commands[] = [
'title' => 'Gera/altera arquivos de model',
'command' => 'app:make-models',
];
$commands[] = [
'title' => 'Gera/altera arquivos de controllers',
'command' => 'app:make-controllers',
];
$commands[] = [
'title' => 'Gera/altera arquivo de rotas',
'command' => 'app:make-routes',
];
$commands[] = [
'title' => 'Gera/altera arquivos de UI',
'command' => 'app:make-ui',
];
foreach($commands as $com) {
$this->comment("⚙️ {$com['title']}");
try {
\Artisan::call($com['command']);
}
catch(\Exception $e) {
$this->comment('Error: '. $e->getMessage());
}
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppClear extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:clear';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Limpar caches';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$commands[] = [
'title' => 'Limpando cache de configurações',
'command' => 'config:clear',
];
$commands[] = [
'title' => 'Limpando cache de rotas',
'command' => 'route:clear',
];
$commands[] = [
'title' => 'Limpando cache de views',
'command' => 'view:clear',
];
$commands[] = [
'title' => 'Optimize clear',
'command' => 'optimize:clear',
];
$commands[] = [
'title' => 'Criando link de storage',
'command' => 'storage:link',
];
foreach($commands as $com) {
$this->comment($com['title']);
\Artisan::call($com['command']);
}
$this->comment('Concluído');
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppCommandsUpdate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:commands-update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Atualiza comandos';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$files = [
'AppBuild.php',
'AppClear.php',
'AppCommandsUpdate.php',
'AppDbExport.php',
'AppDbImport.php',
'AppDeploy.php',
'AppMakeControllers.php',
'AppMakeModels.php',
'AppMakeRoutes.php',
'AppMakeUi.php',
'AppMigrate.php',
'AppSchema.php',
];
foreach($files as $file) {
$filepath = implode(DIRECTORY_SEPARATOR, [__DIR__, $file]);
$content = "https://gist.githubusercontent.com/jeff-silva/f8eeb7f7dab044fe842a2c3402dbd486/raw/{$file}";
$content = \Illuminate\Support\Facades\Http::get($content)->body();
file_put_contents($filepath, $content);
$this->comment("Atualizando {$file} - {$filepath}");
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppDbExport extends AppBase
{
protected $signature = 'app:db-export';
protected $description = 'Exporta banco de dados para schema.sql';
public function handle()
{
$this->comment('⚙️ Gerando config/database-schema.php');
$database_schema = $this->getSchema();
file_put_contents(config_path('database-schema.php'), implode("\n\n", [
'<?php',
"/* Para gerar este arquivo, execute 'php artisan app:db-export'\nPara criar tabelas e colunas, execute 'php artisan app:db-import' */",
('return '. $this->varExport($database_schema) .';'),
]));
}
public function getSchema() {
$database_schema = [
'tables' => [],
'fks' => [],
];
foreach(\DB::select('SHOW TABLE STATUS') as $table) {
$deletes = [
'Version', 'Row_format', 'Rows', 'Avg_row_length', 'Data_length', 'Max_data_length', 'Index_length',
'Data_free', 'Create_time', 'Update_time', 'Check_time', 'Checksum', 'Create_options',
];
foreach($deletes as $delete) {
unset($table->$delete);
}
$table->Model = ((string) \Str::of($table->Name)->slug()->studly());
$table->ModelNamespace = '\App\Models';
$table->ModelFile = '\app\Models\\'. ((string) \Str::of($table->Name)->slug()->studly()) .'.php';
$table->Controller = ((string) \Str::of($table->Name)->slug()->studly()) .'Controller';
$table->ControllerNamespace = '\App\Http\Controllers';
$table->ControllerFile = '\app\Http\Controllers\\'. ((string) \Str::of($table->Name)->slug()->studly()) .'Controller.php';
$statement = collect(\DB::select("SHOW CREATE TABLE `{$table->Name}`;"))->pluck('Create Table')->first();
$statement = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $statement);
$table->Sql = str_replace(["\n", "\t"], '', $statement);
$table->Fields = [];
foreach(\DB::select("SHOW COLUMNS FROM {$table->Name}") as $col) {
$col->Sql = $this->getFieldSchema($col);
$table->Fields[ $col->Field ] = $col;
}
$database_schema['tables'][ $table->Name ] = $table;
}
$database = env('DB_DATABASE');
foreach(\DB::select("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA='{$database}' AND CONSTRAINT_NAME != 'PRIMARY' ") as $fk) {
$database_schema['fks'][ $fk->CONSTRAINT_NAME ] = $fk;
}
return json_decode(json_encode($database_schema), true);
}
}
<?php
namespace App\Console\Commands;
class AppDbImport extends AppBase
{
protected $signature = 'app:db-import';
protected $description = 'Importa schema.sql';
public function handle()
{
$schema = config('database-schema', []);
foreach($schema['tables'] as $table_name => $table) {
if (\Schema::hasTable($table_name)) {
foreach($table['Fields'] as $field_name => $field) {
if (\Schema::hasColumn($table_name, $field_name)) {
// \DB::statement("ALTER TABLE `{$table_name}` MODIFY COLUMN `{$field_name}` {$field['Sql']};");
}
else {
$this->comment("criando coluna {$table_name}.{$field_name}");
\DB::statement("ALTER TABLE `{$table_name}` ADD COLUMN `{$field_name}` {$field['Sql']};");
}
}
}
else {
$this->comment("criando tabela {$table_name}");
\DB::statement($table['Sql']);
}
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppDeploy extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:deploy';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Deploy de aplicação';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->comment('Iniciando deploy');
$commands[] = [
'title' => 'Migrate',
'command' => 'migrate',
];
$commands[] = [
'title' => 'Seed',
'command' => 'db:seed',
];
$commands[] = [
'title' => 'Limpando cache de configurações:',
'command' => 'config:clear',
];
$commands[] = [
'title' => 'Migrando banco de dados:',
'command' => 'app:migrate',
];
foreach($commands as $com) {
$this->comment($com['title']);
$this->call($com['command']);
}
}
}
<?php
namespace App\Console\Commands;
class AppMakeControllers extends AppBase
{
protected $signature = 'app:make-controllers';
protected $description = 'Criar/alterar controllers de acordo com modelo do banco';
public function handle()
{
// $this->comment('⚙️ Criando/alterando models');
$tables = config('database-schema.tables', []);
foreach($tables as $table_name=>$table) {
if (! file_exists(base_path($table['ControllerFile']))) {
file_put_contents(base_path($table['ControllerFile']), implode("\n", [
'<?php',
'',
"namespace App\Http\Controllers;",
'',
"class {$table['Controller']} extends Controller",
'{',
'}',
]));
}
$methods = [];
$methods['search'] = implode("\n", [
"\tpublic function search() {",
"\t\treturn {$table['ModelNamespace']}::querySearch();",
"\t}",
]);
$methods['find'] = implode("\n", [
"\tpublic function find(\$id) {",
"\t\treturn {$table['ModelNamespace']}::find(\$id);",
"\t}",
]);
$methods['save'] = implode("\n", [
"\tpublic function save() {",
"\t\treturn {$table['ModelNamespace']}::fill(request()->all())->save();",
"\t}",
]);
$methods['delete'] = implode("\n", [
"\tpublic function delete(\$id) {",
"\t\treturn {$table['ModelNamespace']}::find(\$id)->remove();",
"\t}",
]);
$methods['clone'] = implode("\n", [
"\tpublic function clone(\$id) {",
"\t\treturn {$table['ModelNamespace']}::find(\$id)->clone();",
"\t}",
]);
$methods['export'] = implode("\n", [
"\tpublic function export(\$id) {",
"\t\treturn {$table['ModelNamespace']}::find(\$id)->export();",
"\t}",
]);
foreach($methods as $method_name=>$method_content) {
$this->classWriteMethod("{$table['ControllerNamespace']}\\{$table['Controller']}", $method_name, $method_content);
}
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppMakeModels extends AppBase
{
protected $signature = 'app:make-models';
protected $description = 'Criar/alterar models de acordo com modelo do banco';
public function handle()
{
// $this->comment('⚙️ Criando/alterando models');
$schema = config('database-schema', []);
foreach($schema['tables'] as $table_name=>$table) {
if ($table_name=='users') continue;
if (! file_exists(base_path($table['ModelFile']))) {
file_put_contents(base_path($table['ModelFile']), implode("\n", [
'<?php',
'',
"namespace App\Models;",
'',
"class {$table['Model']} extends \Illuminate\Database\Eloquent\Model",
'{',
"\tuse \App\Traits\Model;",
'',
"\tprotected \$fillable = [\n\t\t'". implode("',\n\t\t'", array_keys($table['Fields'])) ."',\n\t];",
'',
"\tpublic function validate(\$data=[]) {",
"\t\treturn \Validator::make(\$data, [",
"\t\t\t'name' => ['required'],",
"\t\t]);",
"\t}",
'}',
]));
}
$content = file_get_contents(base_path($table['ModelFile']));
$me = $this;
// Criando protected $fillable
$content = preg_replace_callback('/protected \$fillable(.+?);/s', function($finds) use($me, $table) {
$fillable = "'". implode("',\n\t\t'", array_keys($table['Fields'])) ."'";
return "protected \$fillable = [\n\t\t{$fillable}\n\t];";
}, $content);
file_put_contents(base_path($table['ModelFile']), $content);
// Criando métodos belongsTo e hasMany
$methods = [];
$fks = config('database-schema.fks', []);
foreach($fks as $fk_table=>$fk) {
if (! $fk['REFERENCED_TABLE_NAME']) continue;
// hasMany
if ($fk['REFERENCED_TABLE_NAME']==$table_name) {
$methodName = (string) \Str::of($fk['TABLE_NAME'])->camel()->plural();
$modelName = "{$table['ModelNamespace']}\\{$table['Model']}";
$methods[ $methodName ] = "\tpublic function {$methodName}() {\n\t\treturn \$this->hasMany({$modelName}::class, '{$fk['COLUMN_NAME']}', '{$fk['REFERENCED_COLUMN_NAME']}');\n\t}";
}
// belongsTo
if ($fk['TABLE_NAME']==$table_name) {
$methodName = (string) \Str::of($fk['REFERENCED_TABLE_NAME'])->camel()->singular();
$modelName = "{$table['ModelNamespace']}\\{$table['Model']}";
$methods[ $methodName ] = "\tpublic function {$methodName}() {\n\t\treturn \$this->belongsTo({$modelName}::class, '{$fk['COLUMN_NAME']}', '{$fk['REFERENCED_COLUMN_NAME']}');\n\t}";
}
}
foreach($methods as $method_name=>$method_content) {
$this->classWriteMethod("{$table['ModelNamespace']}\\{$table['Model']}", $method_name, $method_content);
}
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppMakeRoutes extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:make-routes';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Criar/alterar rotas de acordo com métodos de controllers';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// $this->comment('⚙️ Criando/alterando models');
$content = ['<?php', '', '// File generated automatically', '// Do not edit or your changes will be lost', ''];
$paths = [app_path(implode(DIRECTORY_SEPARATOR, ['Http', 'Controllers']))];
foreach((new \Symfony\Component\Finder\Finder)->in($paths)->files() as $file) {
$filename = str_replace('.php', '', $file->getFilename());
$namespace = "\App\Http\Controllers\\{$filename}";
$prefix = (string) \Str::of(str_replace('Controller', '', $filename))->kebab();
foreach ((new \ReflectionClass($namespace))->getMethods() as $rmethod) {
$method_name = $rmethod->getName();
$ignore = [
'getValidationFactory',
'getMiddleware',
];
if (in_array($method_name, $ignore)) continue;
$route = [$prefix];
foreach(['any', 'get', 'post', 'put'] as $method) {
if (! \Str::startsWith($method_name, $method)) continue;
$route[] = (string) \Str::of(str_replace($method, '', $method_name))->studly()->kebab();
foreach($rmethod->getParameters() as $param) {
if (in_array($param->name, ['request'])) continue;
$route[] = '{'. $param->name .'}';
}
$route = implode('/', $route);
$content[] = "Route::{$method}('{$route}', '{$namespace}@{$method_name}');";
}
}
$content[] = '';
}
$content = implode("\n", $content);
$file = base_path(implode(DIRECTORY_SEPARATOR, ['routes', 'api-generated.php']));
file_put_contents($file, $content);
}
}
// Route::get('email-sent/search', '\App\Http\Controllers\EmailSentController@getSearch');
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppMakeUi extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:make-ui';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Gerar interfaces';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$tables = config('database-schema.tables', []);
foreach($tables as $table_name=>$table) {
if (config("database-settings.models.{$table_name}")) {
$model = new \stdClass;
$model->name = (string) \Str::of($table_name)->studly()->kebab()->singular();
$model->file = base_path(implode(DIRECTORY_SEPARATOR, ['resources', 'nuxt', 'components', 'app', "ui-{$model->name}.vue"]));
$model->route = (string) \Str::of($table_name)->studly()->kebab()->singular();
$content = implode("\n", [
'<template><div>',
"\t<el-select v-model=\"props.value\" :multiple=\"props.multiple\"",
"\t\t@change=\"emitValue()\" class=\"form-control p-0\"",
"\t\tfilterable remote :placeholder=\"props.placeholder\"",
"\t\treserve-keyword :remote-method=\"remoteSearch\"",
"\t>",
"\t\t<el-option :value=\"i.id\" :label=\"i.name||i.id\" v-for=\"i in items\" :key=\"i.id\">{{ i.name||i.id }}</el-option>",
"\t</el-select>",
'</div></template>',
'',
'<script>',
'export default {',
"\tname: \"ui-{$model->name}\",",
"\t",
"\tprops: {",
"\t\tvalue: {default:\"\", type:[Number, String, Array]},",
"\t\tplaceholder: {default:'Selecionar'},",
"\t\tmultiple: {default:false},",
"\t},",
"\t",
"\twatch: {",
"\t\t\$props: {deep:true, handler(value) {",
"\t\t\tthis.props = JSON.parse(JSON.stringify(value));",
"\t\t\tthis.remoteSearch('', this.props.value);",
"\t\t}},",
"\t},",
"\t",
"\tmethods: {",
"\t\temitValue() {",
"\t\t\tthis.\$emit('input', this.props.value);",
"\t\t\tthis.\$emit('change', this.props.value);",
"\t\t},",
"\t\t",
"\t\tremoteSearch(q='', id=null) {",
"\t\t\tthis.\$axios.get('/api/{$model->route}/search', {params:{q, id}}).then(resp => {",
"\t\t\t\tthis.items = resp.data.data;",
"\t\t\t});",
"\t\t},",
"\t},",
"\t",
"\tdata() {",
"\t\treturn {",
"\t\t\tprops: JSON.parse(JSON.stringify(this.\$props)),",
"\t\t\titems: [],",
"\t\t};",
"\t},",
'}',
'</script>',
]);
file_put_contents($model->file, $content);
}
}
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppMigrate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:migrate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Sincronização de schema';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->comment('🗂️ Iniciando migração');
$database = env('DB_DATABASE');
$schema = $this->getSchema();
$schema_cfg = config('database-schema');
$sqls = [];
// Criar tabelas que não existem
foreach($schema_cfg['tables'] as $table_cfg_name => $table_cfg) {
if (isset($schema['tables'][ $table_cfg_name ])) continue;
$sql_create = [];
foreach($table_cfg['Fields'] as $field_cfg_name => $field_cfg) {
$field_cfg_type = $this->getFieldSchema($field_cfg);
$sql_create[] = "\t{$field_cfg_name} {$field_cfg_type}";
}
foreach($table_cfg['Fields'] as $field_cfg_name => $field_cfg) {
if ($field_cfg['Key']=='PRI') {
$sql_create[] = "\tPRIMARY KEY (`{$field_cfg_name}`) USING BTREE";
break;
}
}
$sql_create = implode(",\n", $sql_create);
$sql_create = "CREATE TABLE `{$table_cfg_name}` (\n{$sql_create}\n) COLLATE='{$table_cfg['Collation']}' ENGINE={$table_cfg['Engine']};";
$sqls[] = $sql_create;
}
// Alterar tabelas existentes
foreach($schema_cfg['tables'] as $table_cfg_name => $table_cfg) {
if (! isset($schema['tables'][ $table_cfg_name ])) continue;
$table = $schema['tables'][ $table_cfg_name ];
// Verificando colunas
foreach($table_cfg['Fields'] as $field_cfg_name => $field_cfg) {
$field_cfg_type = $this->getFieldSchema($field_cfg);
// Alterando colunas que existem
if (isset($table['Fields'][ $field_cfg_name ])) {
$sqls[] = "ALTER TABLE `{$table_cfg_name}` CHANGE COLUMN `{$field_cfg_name}` `{$field_cfg_name}` {$field_cfg_type};";
}
// Criando colunas que não existem
else {
$sqls[] = "ALTER TABLE `{$table_cfg_name}` ADD COLUMN `{$field_cfg_name}` {$field_cfg_type};";
}
}
}
// Criar chaves estrangeiras
foreach($schema_cfg['fks'] as $fk_cfg_name => $fk_cfg) {
if (isset($schema['fks'][ $fk_cfg_name ])) continue;
// Criando chave estrangeira
$sqls[] = "ALTER TABLE `{$fk_cfg['TABLE_NAME']}` ADD CONSTRAINT `{$fk_cfg['CONSTRAINT_NAME']}` FOREIGN KEY (`{$fk_cfg['COLUMN_NAME']}`) REFERENCES `{$fk_cfg['REFERENCED_TABLE_NAME']}` (`{$fk_cfg['REFERENCED_COLUMN_NAME']}`);";
}
$this->comment("\nAlterando tabela:");
foreach($sqls as $sql) {
$this->comment($sql);
\DB::select(\DB::raw($sql));
}
}
public function getFieldSchema($field) {
$schema = [ $field['Type'] ];
$schema[] = (($field['Null']=='NO' || $field['Key']=='PRI')? 'NOT NULL': 'NULL');
if ($field['Extra']=='auto_increment') $schema[] = 'AUTO_INCREMENT';
if ($field['Key'] != 'PRI' AND !\Str::contains($field['Type'], 'varchar') AND !\Str::contains($field['Type'], 'int') AND $field['Type']!='longtext' AND $field['Type']!='timestamp') {
$schema[] = ($field['Default']===NULL? 'DEFAULT NULL': "DEFAULT '{$field['Default']}'");
}
return implode(' ', $schema);
}
public function getSchema() {
$database_schema = [
'tables' => [],
'fks' => [],
];
foreach(\DB::select('SHOW TABLE STATUS') as $table) {
$table->Fields = [];
foreach(\DB::select("SHOW COLUMNS FROM {$table->Name}") as $col) {
$table->Fields[ $col->Field ] = $col;
}
$database_schema['tables'][ $table->Name ] = $table;
}
$database = env('DB_DATABASE');
foreach(\DB::select("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA='{$database}' AND CONSTRAINT_NAME != 'PRIMARY' ") as $fk) {
$database_schema['fks'][ $fk->CONSTRAINT_NAME ] = $fk;
}
return json_decode(json_encode($database_schema), true);
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AppSchema extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:schema';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Cria schema do banco de dados';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->comment('⚙️ Gerando config/database-schema.php');
$database_schema = $this->getSchema();
$_procedure = function($query) {
$procedureName = '_temporary';
return implode("\n", [
"DROP PROCEDURE IF EXISTS `{$procedureName}`; DELIMITER //",
"CREATE PROCEDURE `{$procedureName}`() BEGIN",
"\tDECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;",
"\t{$query};",
"END // DELIMITER ; CALL {$procedureName}();",
"DROP PROCEDURE IF EXISTS `{$procedureName}`;",
]);
};
$sqls = ['SET FOREIGN_KEY_CHECKS = 0;', ''];
foreach($database_schema['tables'] as $table_name=>$table) {
$sqls[] = "-- create table {$table_name} ";
$sql = collect(\DB::select("SHOW CREATE TABLE `{$table_name}`;"))->pluck('Create Table')->first();
$sql = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $sql) .';';
$sql = preg_replace('/AUTO_INCREMENT=\d+\s/', '', $sql);
$sqls[] = $sql;
$sqls[] = '';
}
foreach($database_schema['tables'] as $table_name=>$table) {
foreach($table['Fields'] as $col_field=>$col) {
$fieldSchema = $this->getFieldSchema((array) $col);
$sqls[] = "-- create field '{$col_field}' if not exists";
$sqls[] = $_procedure("ALTER TABLE `{$table_name}` ADD COLUMN `{$col_field}` {$fieldSchema};");
$sqls[] = '';
$sqls[] = "-- modify field {$col_field} ";
$sqls[] = "ALTER TABLE `{$table_name}` MODIFY COLUMN `{$col_field}` {$fieldSchema};";
$sqls[] = '';
}
}
foreach($database_schema['fks'] as $fk_name=>$fk) {
$sqls[] = "-- creating fk if not exists";
$sqls[] = $_procedure("ALTER TABLE {$fk['TABLE_NAME']} ADD CONSTRAINT {$fk_name} FOREIGN KEY ({$fk['COLUMN_NAME']}) REFERENCES {$fk['REFERENCED_TABLE_NAME']}({$fk['REFERENCED_COLUMN_NAME']});");
$sqls[] = '';
}
$sqls[] = 'SET FOREIGN_KEY_CHECKS = 1;';
file_put_contents(database_path('schema.sql'), implode("\n", $sqls));
$content = $this->varExport($database_schema);
$generated = "/*\n * Gerado em ". date('d/m/Y à\s H:i:s') ."\n * Por favor, não altere manualmente.\n */";
file_put_contents(config_path('database-schema.php'), "<?php \n\n{$generated}\n\nreturn {$content};");
$this->comment('⚙️ Gerando config/database-settings.php');
$this->comment('Não se esqueça de alterar as configurações "model" para definir quais tabelas gerarão arquivos.');
$database_settings_default = [
'models' => [],
'controllers' => [],
];
$database_settings = $database_settings_default;
foreach($database_schema['tables'] as $table_name=>$table) {
$database_settings['models'][ $table_name ] = false;
$database_settings['controllers'][ $table_name ] = false;
}
$database_settings2 = config('database-settings', $database_settings_default);
foreach($database_settings as $name=>$value) {
$database_settings2[$name] = isset($database_settings2[$name])? $database_settings2[$name]: [];
$database_settings2[$name] = array_merge($database_settings[$name], $database_settings2[$name]);
}
file_put_contents(config_path('database-settings.php'), '<?php return '. $this->varExport($database_settings2) .';');
}
public function varExport($data) {
$dump = var_export($data, true);
$dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
$dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
$dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
if (gettype($data) == 'object') { // Deal with object states
$dump = str_replace('__set_state(array(', '__set_state([', $dump);
$dump = preg_replace('#\)\)$#', "])", $dump);
}
else { $dump = preg_replace('#\)$#', "]", $dump); }
return $dump;
}
public function getSchema() {
$database_schema = [
'tables' => [],
'fks' => [],
];
foreach(\DB::select('SHOW TABLE STATUS') as $table) {
$table->Fields = [];
foreach(\DB::select("SHOW COLUMNS FROM {$table->Name}") as $col) {
$table->Fields[ $col->Field ] = $col;
}
$database_schema['tables'][ $table->Name ] = $table;
}
$database = env('DB_DATABASE');
foreach(\DB::select("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE CONSTRAINT_SCHEMA='{$database}' AND CONSTRAINT_NAME != 'PRIMARY' ") as $fk) {
$database_schema['fks'][ $fk->CONSTRAINT_NAME ] = $fk;
}
return json_decode(json_encode($database_schema), true);
}
public function getFieldSchema($field) {
$schema = [ $field['Type'] ];
$schema[] = (($field['Null']=='NO' || $field['Key']=='PRI')? 'NOT NULL': 'NULL');
if ($field['Extra']=='auto_increment') $schema[] = 'AUTO_INCREMENT';
if ($field['Key'] != 'PRI' AND !\Str::contains($field['Type'], 'varchar') AND !\Str::contains($field['Type'], 'int') AND $field['Type']!='longtext' AND $field['Type']!='timestamp') {
$schema[] = ($field['Default']===NULL? 'DEFAULT NULL': "DEFAULT '{$field['Default']}'");
}
return implode(' ', $schema);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment