From 6e5841f76e62e7333b1d8196991c8ac3d8ee1214 Mon Sep 17 00:00:00 2001 From: Awais Date: Wed, 28 Feb 2024 17:57:34 +0500 Subject: [PATCH] v1.5 - Support all DBs that Laravel support (MySQL,PgSQL, MSSQL) - Added more validation rules - Default Model name updated to `App\Models` - Bug fixes --- src/Commands/GeneratorCommand.php | 67 ++++++----- src/ModelGenerator.php | 188 ++++++++++++++---------------- 2 files changed, 126 insertions(+), 129 deletions(-) diff --git a/src/Commands/GeneratorCommand.php b/src/Commands/GeneratorCommand.php index a3a422a..a7bb768 100644 --- a/src/Commands/GeneratorCommand.php +++ b/src/Commands/GeneratorCommand.php @@ -6,7 +6,6 @@ use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Arr; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Str; use Symfony\Component\Console\Input\InputArgument; @@ -64,7 +63,7 @@ abstract class GeneratorCommand extends Command * * @var string */ - protected $modelNamespace = 'App'; + protected $modelNamespace = 'App\Models'; /** * Controller Namespace. @@ -90,7 +89,7 @@ abstract class GeneratorCommand extends Command /** * Create a new controller creator command instance. * - * @param \Illuminate\Filesystem\Filesystem $files + * @param \Illuminate\Filesystem\Filesystem $files * * @return void */ @@ -129,13 +128,13 @@ abstract protected function buildViews(); /** * Build the directory if necessary. * - * @param string $path + * @param string $path * * @return string */ protected function makeDirectory($path) { - if (!$this->files->isDirectory(dirname($path))) { + if (! $this->files->isDirectory(dirname($path))) { $this->files->makeDirectory(dirname($path), 0777, true, true); } @@ -156,8 +155,8 @@ protected function write($path, $content) /** * Get the stub file. * - * @param string $type - * @param boolean $content + * @param string $type + * @param boolean $content * * @return string * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException @@ -167,12 +166,12 @@ protected function getStub($type, $content = true) { $stub_path = config('crud.stub_path', 'default'); if ($stub_path == 'default') { - $stub_path = __DIR__ . '/../stubs/'; + $stub_path = __DIR__.'/../stubs/'; } - $path = Str::finish($stub_path, '/') . "{$type}.stub"; + $path = Str::finish($stub_path, '/')."{$type}.stub"; - if (!$content) { + if (! $content) { return $path; } @@ -201,7 +200,7 @@ private function _getSpace($no = 1) */ protected function _getControllerPath($name) { - return app_path($this->_getNamespacePath($this->controllerNamespace) . "{$name}Controller.php"); + return app_path($this->_getNamespacePath($this->controllerNamespace)."{$name}Controller.php"); } /** @@ -211,7 +210,7 @@ protected function _getControllerPath($name) */ protected function _getModelPath($name) { - return $this->makeDirectory(app_path($this->_getNamespacePath($this->modelNamespace) . "{$name}.php")); + return $this->makeDirectory(app_path($this->_getNamespacePath($this->modelNamespace)."{$name}.php")); } /** @@ -276,7 +275,7 @@ protected function buildReplacements() * * @param $title * @param $column - * @param string $type + * @param string $type * * @return mixed * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException @@ -308,7 +307,7 @@ protected function getHead($title) return str_replace( array_keys($replace), array_values($replace), - $this->_getSpace(10) . '{{title}}' . "\n" + $this->_getSpace(10).'{{title}}'."\n" ); } @@ -326,7 +325,7 @@ protected function getBody($column) return str_replace( array_keys($replace), array_values($replace), - $this->_getSpace(11) . '{{ ${{modelNameLowerCase}}->{{column}} }}' . "\n" + $this->_getSpace(11).'{{ ${{modelNameLowerCase}}->{{column}} }}'."\n" ); } @@ -337,7 +336,7 @@ protected function getBody($column) */ protected function buildLayout(): void { - if (!(view()->exists($this->layout))) { + if (! (view()->exists($this->layout))) { $this->info('Creating Layout ...'); @@ -357,7 +356,7 @@ protected function buildLayout(): void protected function getColumns() { if (empty($this->tableColumns)) { - $this->tableColumns = DB::select('SHOW COLUMNS FROM ' . $this->table); + $this->tableColumns = Schema::getColumns($this->table); } return $this->tableColumns; @@ -372,11 +371,11 @@ protected function getFilteredColumns() $columns = []; foreach ($this->getColumns() as $column) { - $columns[] = $column->Field; + $columns[] = $column['name']; } return array_filter($columns, function ($value) use ($unwanted) { - return !in_array($value, $unwanted); + return ! in_array($value, $unwanted); }); } @@ -391,14 +390,26 @@ protected function modelReplacements() $rulesArray = []; $softDeletesNamespace = $softDeletes = ''; - foreach ($this->getColumns() as $value) { - $properties .= "\n * @property $$value->Field"; + foreach ($this->getColumns() as $column) { + $properties .= "\n * @property \${$column['name']}"; + + if (! $column['nullable']) { + $rulesArray[$column['name']] = ['required']; + } + + if ($column['type_name'] == 'bool') { + $rulesArray[$column['name']][] = 'boolean'; + } + + if ($column['type_name'] == 'uuid') { + $rulesArray[$column['name']][] = 'uuid'; + } - if ($value->Null == 'NO') { - $rulesArray[$value->Field] = 'required'; + if ($column['type_name'] == 'text' || $column['type_name'] == 'varchar') { + $rulesArray[$column['name']][] = 'string'; } - if ($value->Field == 'deleted_at') { + if ($column['name'] == 'deleted_at') { $softDeletesNamespace = "use Illuminate\Database\Eloquent\SoftDeletes;\n"; $softDeletes = "use SoftDeletes;\n"; } @@ -410,7 +421,7 @@ protected function modelReplacements() $rulesArray = Arr::except($rulesArray, $this->unwantedColumns); // Make rulesArray foreach ($rulesArray as $col => $rule) { - $rules .= "\n\t\t'{$col}' => '{$rule}',"; + $rules .= "\n\t\t'{$col}' => '".implode('|', $rule)."',"; } return $rules; @@ -423,7 +434,7 @@ protected function modelReplacements() // Add quotes to the unwanted columns for fillable array_walk($filterColumns, function (&$value) { - $value = "'" . $value . "'"; + $value = "'".$value."'"; }); // CSV format @@ -432,7 +443,7 @@ protected function modelReplacements() $properties .= "\n *"; - list($relations, $properties) = (new ModelGenerator($this->table, $properties, $this->modelNamespace))->getEloquentRelations(); + [$relations, $properties] = (new ModelGenerator($this->table, $properties, $this->modelNamespace))->getEloquentRelations(); return [ '{{fillable}}' => $fillable(), @@ -463,7 +474,7 @@ protected function buildOptions() { $route = $this->option('route'); - if (!empty($route)) { + if (! empty($route)) { $this->options['route'] = $route; } diff --git a/src/ModelGenerator.php b/src/ModelGenerator.php index b9ecc87..7ab39ca 100644 --- a/src/ModelGenerator.php +++ b/src/ModelGenerator.php @@ -2,7 +2,7 @@ namespace Ibex\CrudGenerator; -use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; use Illuminate\Support\Str; /** @@ -12,16 +12,16 @@ class ModelGenerator { private $functions = null; - private $table = null; - private $properties = null; - private $modelNamespace = 'App'; + private $table; + private $properties; + private $modelNamespace; /** * ModelGenerator constructor. * - * @param string $table - * @param string $properties - * @param string $modelNamespace + * @param string $table + * @param string $properties + * @param string $modelNamespace */ public function __construct(string $table, string $properties, string $modelNamespace) { @@ -44,131 +44,117 @@ public function getEloquentRelations() private function _init() { foreach ($this->_getTableRelations() as $relation) { - if ($relation->ref) { - $tableKeys = $this->_getTableKeys($relation->ref_table); - $eloquent = $this->_getEloquent($relation, $tableKeys); - } else { - $eloquent = 'hasOne'; - } - - $this->functions .= $this->_getFunction($eloquent, $relation->ref_table, $relation->foreign_key, $relation->local_key); + $this->functions .= $this->_getFunction($relation); } } - /** - * @param $relation - * @param $tableKeys - * - * @return string - */ - private function _getEloquent($relation, $tableKeys) + private function _getFunction(array $relation) { - $eloquent = ''; - foreach ($tableKeys as $tableKey) { - if ($relation->foreign_key == $tableKey->Column_name) { - $eloquent = 'hasMany'; - - if ($tableKey->Key_name == 'PRIMARY') { - $eloquent = 'hasOne'; - } elseif ($tableKey->Non_unique == 0 && $tableKey->Seq_in_index == 1) { - $eloquent = 'hasOne'; - } - } - } - - return $eloquent; - } - - /** - * @param string $relation - * @param string $table - * @param string $foreign_key - * @param string $local_key - * - * @return string - */ - private function _getFunction(string $relation, string $table, string $foreign_key, string $local_key) - { - list($model, $relationName) = $this->_getModelName($table, $relation); - $relClass = ucfirst($relation); - - switch ($relation) { + switch ($relation['name']) { case 'hasOne': - $this->properties .= "\n * @property $model $$relationName"; + case 'belongsTo': + $this->properties .= "\n * @property {$relation['class']} \${$relation['relation_name']}"; break; case 'hasMany': - $this->properties .= "\n * @property ".$model."[] $$relationName"; + $this->properties .= "\n * @property ".$relation['class']."[] \${$relation['relation_name']}"; break; } return ' /** - * @return \Illuminate\Database\Eloquent\Relations\\'.$relClass.' + * @return \Illuminate\Database\Eloquent\Relations\\'.ucfirst($relation['name']).' */ - public function '.$relationName.'() + public function '.$relation['relation_name'].'() { - return $this->'.$relation.'(\''.$this->modelNamespace.'\\'.$model.'\', \''.$foreign_key.'\', \''.$local_key.'\'); + return $this->'.$relation['name'].'(\\'.$this->modelNamespace.'\\'.$relation['class'].'::class, \''.$relation['foreign_key'].'\', \''.$relation['owner_key'].'\'); } '; } /** - * Get the name relation and model. - * - * @param $name - * @param $relation + * Get all relations from Table. * * @return array */ - private function _getModelName($name, $relation) + private function _getTableRelations() { - $class = Str::studly(Str::singular($name)); - $relationName = ''; + return [ + ...$this->getBelongsTo(), + ...$this->getOtherRelations(), + ]; + } - switch ($relation) { - case 'hasOne': - $relationName = Str::camel(Str::singular($name)); - break; - case 'hasMany': - $relationName = Str::camel(Str::plural($name)); - break; + protected function getBelongsTo() + { + $relations = Schema::getForeignKeys($this->table); + + $eloquent = []; + + foreach ($relations as $relation) { + if (count($relation['foreign_columns']) != 1 || count($relation['columns']) != 1) { + continue; + } + + $eloquent[] = [ + 'name' => 'belongsTo', + 'relation_name' => Str::camel(Str::singular($relation['foreign_table'])), + 'class' => Str::studly(Str::singular($relation['foreign_table'])), + 'foreign_key' => $relation['columns'][0], + 'owner_key' => $relation['foreign_columns'][0], + ]; } - return [$class, $relationName]; + return $eloquent; } - /** - * Get all relations from Table. - * - * @return array - */ - private function _getTableRelations() + protected function getOtherRelations() { - $db = DB::getDatabaseName(); - $sql = <<table) { + continue; + } + + if (count($relation['foreign_columns']) != 1 || count($relation['columns']) != 1) { + continue; + } + + $isUniqueColumn = $this->getUniqueIndex($indexes, $relation['columns'][0]); + + $eloquent[] = [ + 'name' => $isUniqueColumn ? 'hasOne' : 'hasMany', + 'relation_name' => Str::camel($isUniqueColumn ? Str::singular($table) : Str::plural($table)), + 'class' => Str::studly(Str::singular($table)), + 'foreign_key' => $relation['foreign_columns'][0], + 'owner_key' => $relation['columns'][0], + ]; + } + } + + return $eloquent; } - /** - * Get all Keys from table. - * - * @param $table - * - * @return array - */ - private function _getTableKeys($table) + private function getUniqueIndex($indexes, $column) { - return DB::select("SHOW KEYS FROM {$table}"); + $isUnique = false; + + foreach ($indexes as $index) { + if ( + (count($index['columns']) == 1) + && ($index['columns'][0] == $column) + && $index['unique'] + ) { + $isUnique = true; + break; + } + } + + return $isUnique; } }