From 06b024ce9f8e3ee904364d5a2bff9dbc3fe6d1f5 Mon Sep 17 00:00:00 2001 From: omair saleh Date: Mon, 14 Sep 2020 16:36:40 +0800 Subject: [PATCH] added code generator back to repository --- .gitignore | 1 - .../CodeGenerator/Commands/BaseCommand.php | 277 +++++++++ .../Commands/RollbackGeneratorCommand.php | 187 ++++++ .../Scaffold/MicroGeneratorCommand.php | 91 +++ .../Scaffold/ScaffoldGeneratorCommand.php | 96 ++++ .../CodeGenerator/Common/CommandData.php | 294 ++++++++++ .../CodeGenerator/Common/GenerateGetters.php | 26 + .../CodeGenerator/Common/GeneratorConfig.php | 413 +++++++++++++ .../CodeGenerator/Common/GeneratorField.php | 173 ++++++ .../Common/GeneratorFieldRelation.php | 103 ++++ .../CodeGenerator/Common/GeneratorHelpers.php | 78 +++ .../CodeGenerator/Common/TemplatesManager.php | 24 + .../Generators/BaseGenerator.php | 31 + .../Generators/FactoryGenerator.php | 119 ++++ .../Micros/DataTransferObjectGenerator.php | 140 +++++ .../Generators/Micros/ResourceGenerator.php | 75 +++ .../Generators/Micros/RulesGenerator.php | 68 +++ .../Generators/Micros/ServicesGenerator.php | 96 ++++ .../Generators/Micros/ValidatorsGenerator.php | 112 ++++ .../Generators/MigrationGenerator.php | 92 +++ .../Generators/ModelGenerator.php | 351 ++++++++++++ .../Scaffold/ControllerLogicGenerator.php | 83 +++ .../Scaffold/ControllersGenerator.php | 64 +++ .../Generators/Scaffold/RoutesGenerator.php | 55 ++ .../Generators/Scaffold/ViewsGenerator.php | 53 ++ .../Generators/Scaffold/VueGenerator.php | 196 +++++++ .../Generators/Scaffold/WebRouteGenerator.php | 55 ++ .../Generators/SeederGenerator.php | 86 +++ .../CodeGenerator/Schemas/addresses.json | 102 ++++ .../CodeGenerator/Schemas/companies.json | 35 ++ .../CodeGenerator/Schemas/contacts.json | 70 +++ .../CodeGenerator/Stubs/Docs/model.stub | 6 + .../Stubs/Factories/model_factory.stub | 12 + .../CodeGenerator/Stubs/Fields/date.stub | 1 + .../CodeGenerator/Stubs/Fields/email.stub | 1 + .../CodeGenerator/Stubs/Fields/field.stub | 8 + .../Stubs/Fields/filter_field.stub | 8 + .../CodeGenerator/Stubs/Fields/password.stub | 1 + .../CodeGenerator/Stubs/Fields/select.stub | 1 + .../Stubs/Fields/selectable.stub | 1 + .../CodeGenerator/Stubs/Fields/text.stub | 1 + .../CodeGenerator/Stubs/Fields/textarea.stub | 1 + .../Stubs/Micros/data_transfer_object.stub | 24 + .../Stubs/Micros/getter_function.stub | 7 + .../Stubs/Migration/migration.stub | 31 + .../CodeGenerator/Stubs/Models/model.stub | 44 ++ .../Stubs/Models/relationship.stub | 7 + .../Stubs/Resource/model_resource.stub | 22 + .../CodeGenerator/Stubs/Routes/route.stub | 15 + .../CodeGenerator/Stubs/Routes/web.stub | 5 + .../CodeGenerator/Stubs/Rules/can_create.stub | 57 ++ .../CodeGenerator/Stubs/Rules/can_delete.stub | 43 ++ .../CodeGenerator/Stubs/Rules/can_fetch.stub | 43 ++ .../CodeGenerator/Stubs/Rules/can_list.stub | 43 ++ .../CodeGenerator/Stubs/Rules/can_update.stub | 57 ++ .../Controllers/create_controller.stub | 20 + .../Controllers/delete_controller.stub | 20 + .../Controllers/fetch_controller.stub | 20 + .../Scaffold/Controllers/list_controller.stub | 20 + .../Controllers/update_controller.stub | 20 + .../create_controller_logic.stub | 69 +++ .../delete_controller_logic.stub | 73 +++ .../fetch_controller_logic.stub | 67 +++ .../list_controller_logic.stub | 66 +++ .../update_controller_logic.stub | 78 +++ .../Stubs/Seeds/model_seeder.stub | 16 + .../Stubs/Services/create_service.stub | 19 + .../Stubs/Services/delete_service.stub | 15 + .../Stubs/Services/fetch_service.stub | 33 ++ .../Stubs/Services/list_service.stub | 33 ++ .../Stubs/Services/update_service.stub | 19 + .../Stubs/Validator/request_validation.stub | 39 ++ .../CodeGenerator/Stubs/Views/column.stub | 16 + .../CodeGenerator/Stubs/Views/view.stub | 31 + .../Stubs/VueJs/element_component.stub | 41 ++ .../Stubs/VueJs/filter_component.stub | 49 ++ .../Stubs/VueJs/form_component.stub | 63 ++ .../CodeGenerator/Stubs/base_repository.stub | 193 +++++++ app/Classes/CodeGenerator/Utils/FileUtil.php | 37 ++ .../Utils/GeneratorFieldsInputUtil.php | 105 ++++ .../Utils/HTMLFieldGenerator.php | 85 +++ .../CodeGenerator/Utils/ResponseUtil.php | 41 ++ .../CodeGenerator/Utils/SchemaUtil.php | 42 ++ .../Utils/TableFieldsGenerator.php | 541 ++++++++++++++++++ 84 files changed, 5955 insertions(+), 1 deletion(-) create mode 100644 app/Classes/CodeGenerator/Commands/BaseCommand.php create mode 100644 app/Classes/CodeGenerator/Commands/RollbackGeneratorCommand.php create mode 100644 app/Classes/CodeGenerator/Commands/Scaffold/MicroGeneratorCommand.php create mode 100644 app/Classes/CodeGenerator/Commands/Scaffold/ScaffoldGeneratorCommand.php create mode 100644 app/Classes/CodeGenerator/Common/CommandData.php create mode 100644 app/Classes/CodeGenerator/Common/GenerateGetters.php create mode 100644 app/Classes/CodeGenerator/Common/GeneratorConfig.php create mode 100644 app/Classes/CodeGenerator/Common/GeneratorField.php create mode 100644 app/Classes/CodeGenerator/Common/GeneratorFieldRelation.php create mode 100644 app/Classes/CodeGenerator/Common/GeneratorHelpers.php create mode 100644 app/Classes/CodeGenerator/Common/TemplatesManager.php create mode 100644 app/Classes/CodeGenerator/Generators/BaseGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/FactoryGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Micros/DataTransferObjectGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Micros/ResourceGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Micros/RulesGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Micros/ServicesGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Micros/ValidatorsGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/MigrationGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/ModelGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/ControllerLogicGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/ControllersGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/RoutesGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/ViewsGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/VueGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/Scaffold/WebRouteGenerator.php create mode 100644 app/Classes/CodeGenerator/Generators/SeederGenerator.php create mode 100644 app/Classes/CodeGenerator/Schemas/addresses.json create mode 100644 app/Classes/CodeGenerator/Schemas/companies.json create mode 100644 app/Classes/CodeGenerator/Schemas/contacts.json create mode 100644 app/Classes/CodeGenerator/Stubs/Docs/model.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Factories/model_factory.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/date.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/email.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/field.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/filter_field.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/password.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/select.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/selectable.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/text.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Fields/textarea.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Micros/data_transfer_object.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Micros/getter_function.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Migration/migration.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Models/model.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Models/relationship.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Resource/model_resource.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Routes/route.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Routes/web.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Rules/can_create.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Rules/can_delete.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Rules/can_fetch.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Rules/can_list.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Rules/can_update.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/create_controller.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/delete_controller.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/fetch_controller.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/list_controller.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/update_controller.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/create_controller_logic.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/delete_controller_logic.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/fetch_controller_logic.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/list_controller_logic.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/update_controller_logic.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Seeds/model_seeder.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Services/create_service.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Services/delete_service.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Services/fetch_service.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Services/list_service.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Services/update_service.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Validator/request_validation.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Views/column.stub create mode 100644 app/Classes/CodeGenerator/Stubs/Views/view.stub create mode 100644 app/Classes/CodeGenerator/Stubs/VueJs/element_component.stub create mode 100644 app/Classes/CodeGenerator/Stubs/VueJs/filter_component.stub create mode 100644 app/Classes/CodeGenerator/Stubs/VueJs/form_component.stub create mode 100644 app/Classes/CodeGenerator/Stubs/base_repository.stub create mode 100644 app/Classes/CodeGenerator/Utils/FileUtil.php create mode 100644 app/Classes/CodeGenerator/Utils/GeneratorFieldsInputUtil.php create mode 100644 app/Classes/CodeGenerator/Utils/HTMLFieldGenerator.php create mode 100644 app/Classes/CodeGenerator/Utils/ResponseUtil.php create mode 100644 app/Classes/CodeGenerator/Utils/SchemaUtil.php create mode 100644 app/Classes/CodeGenerator/Utils/TableFieldsGenerator.php diff --git a/.gitignore b/.gitignore index f0eb58a3..eec23d5b 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,3 @@ Homestead.json Homestead.yaml npm-debug.log yarn-error.log -/app/Classes/CodeGenerator \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Commands/BaseCommand.php b/app/Classes/CodeGenerator/Commands/BaseCommand.php new file mode 100644 index 00000000..e1f4c80c --- /dev/null +++ b/app/Classes/CodeGenerator/Commands/BaseCommand.php @@ -0,0 +1,277 @@ +composer = app()['composer']; + } + + public function handle() + { + $this->commandData->modelName = $this->argument('model'); + + $this->commandData->initCommandData(); + $this->commandData->getFields(); + } + + public function generateCommonItems() + { + if (!$this->commandData->getOption('fromTable')) { + $migrationGenerator = new MigrationGenerator($this->commandData); + $migrationGenerator->generate(); + } + + $modelGenerator = new ModelGenerator($this->commandData); + $modelGenerator->generate(); + + $factoryGenerator = new FactoryGenerator($this->commandData); + $factoryGenerator->generate(); + + $seederGenerator = new SeederGenerator($this->commandData); + $seederGenerator->generate(); + + if($this->confirm("\nDo you want to include this seeder to the main seeder? [y|N]", false)){ + $seederGenerator->updateMainSeeder(); + } + + } + + public function generateMicroItems() + { + $dataTransferObjectGenerator = new DataTransferObjectGenerator($this->commandData); + $dataTransferObjectGenerator->generate(); + + $serviceGenerator = new ServicesGenerator($this->commandData); + $serviceGenerator->generate(); + } + + public function generateScaffoldItems() + { + + $resourceGenerator = new ResourceGenerator($this->commandData); + $resourceGenerator->generate(); + + $validatorsGenerator = new ValidatorsGenerator($this->commandData); + $validatorsGenerator->generate(); + + $rulesGenerator = new RulesGenerator($this->commandData); + $rulesGenerator->generate(); + + if (!$this->isSkip('controllers') and !$this->isSkip('scaffold_controller')) { + $controllerLogicGenerator = new ControllerLogicGenerator($this->commandData); + $controllerLogicGenerator->generate(); + + $controllerGenerator = new ControllersGenerator($this->commandData); + $controllerGenerator->generate(); + + } + + $routesGenerator = new RoutesGenerator($this->commandData); + $routesGenerator->generate(); + +// $webRouteGenerator = new WebRouteGenerator($this->commandData); +// $webRouteGenerator->generate(); + } + + public function generateViews(){ + $viewGenerator = new ViewsGenerator($this->commandData); + $viewGenerator->generate(); + + $vueGenerator = new vueGenerator($this->commandData); + $vueGenerator->generate(); + + if($this->confirm("\nDo you want to compile your vue files? [y|N]", false)){ + shell_exec('yarn dev'); + } + } + + public function performPostActions($runMigration = false) + { + if ($this->commandData->getOption('save')) { + $this->saveSchemaFile(); + } + + if ($runMigration) { + if ($this->commandData->getOption('forceMigrate')) { + $this->runMigration(); + } elseif (!$this->commandData->getOption('fromTable') and !$this->isSkip('migration')) { + $requestFromConsole = (php_sapi_name() == 'cli') ? true : false; + if ($this->commandData->getOption('jsonFromGUI') && $requestFromConsole) { + $this->runMigration(); + } elseif ($requestFromConsole && $this->confirm("\nDo you want to migrate database? [y|N]", false)) { + $this->runMigration(); + } + } + } + + if (!$this->isSkip('dump-autoload')) { + $this->info('Generating autoload files'); + $this->composer->dumpOptimized(); + } + } + + public function runMigration() + { + $migrationPath = database_path('migrations/'); + $path = Str::after($migrationPath, base_path()); // get path after base_path + $this->call('migrate', ['--path' => $path, '--force' => true]); + + return true; + } + + public function isSkip($skip) + { + if ($this->commandData->getOption('skip')) { + return in_array($skip, (array) $this->commandData->getOption('skip')); + } + + return false; + } + + public function performPostActionsWithMigration() + { + $this->performPostActions(true); + } + + private function saveSchemaFile() + { + $fileFields = []; + + foreach ($this->commandData->fields as $field) { + $fileFields[] = [ + 'name' => $field->name, + 'dbType' => $field->dbInput, + 'htmlType' => $field->htmlInput, + 'validations' => $field->validations, + 'searchable' => $field->isSearchable, + 'fillable' => $field->isFillable, + 'primary' => $field->isPrimary, + 'inForm' => $field->inForm, + 'inIndex' => $field->inIndex, + 'inView' => $field->inView, + ]; + } + + foreach ($this->commandData->relations as $relation) { + $fileFields[] = [ + 'type' => 'relation', + 'relation' => $relation->type.','.implode(',', $relation->inputs), + ]; + } + + $path = app_path('Classes/CodeGenerator/Schemas/'); + + $fileName = $this->commandData->modelName.'.json'; + + if (file_exists($path.$fileName) && !$this->confirmOverwrite($fileName)) { + return; + } + FileUtil::createFile($path, $fileName, json_encode($fileFields, JSON_PRETTY_PRINT)); + $this->commandData->commandComment("\nSchema File saved: "); + $this->commandData->commandInfo($fileName); + } + + /** + * @param $fileName + * @param string $prompt + * + * @return bool + */ + protected function confirmOverwrite($fileName, $prompt = '') + { + $prompt = (empty($prompt)) + ? $fileName.' already exists. Do you want to overwrite it? [y|N]' + : $prompt; + + return $this->confirm($prompt, false); + } + + + /** + * Get the console command options. + * + * @return array + */ + public function getOptions() + { + return [ + ['fieldsFile', null, InputOption::VALUE_REQUIRED, 'Fields input as json file'], + ['jsonFromGUI', null, InputOption::VALUE_REQUIRED, 'Direct Json string while using GUI interface'], + ['plural', null, InputOption::VALUE_REQUIRED, 'Plural Model name'], + ['tableName', null, InputOption::VALUE_REQUIRED, 'Table Name'], + ['fromTable', null, InputOption::VALUE_NONE, 'Generate from existing table'], + ['ignoreFields', null, InputOption::VALUE_REQUIRED, 'Ignore fields while generating from table'], + ['save', null, InputOption::VALUE_NONE, 'Save model schema to file'], + ['primary', null, InputOption::VALUE_REQUIRED, 'Custom primary key'], + ['prefix', null, InputOption::VALUE_REQUIRED, 'Prefix for all files'], + ['paginate', null, InputOption::VALUE_REQUIRED, 'Pagination for index.blade.php'], + ['skip', null, InputOption::VALUE_REQUIRED, 'Skip Specific Items to Generate (migration,model,controllers,api_controller,scaffold_controller,repository,requests,api_requests,scaffold_requests,routes,api_routes,scaffold_routes,views,tests,menu,dump-autoload)'], + ['datatables', null, InputOption::VALUE_REQUIRED, 'Override datatables settings'], + ['views', null, InputOption::VALUE_REQUIRED, 'Specify only the views you want generated: index,create,edit,show'], + ['relations', null, InputOption::VALUE_NONE, 'Specify if you want to pass relationships for fields'], + ['softDelete', null, InputOption::VALUE_NONE, 'Soft Delete Option'], + ['forceMigrate', null, InputOption::VALUE_NONE, 'Specify if you want to run migration or not'], + ['factory', null, InputOption::VALUE_NONE, 'To generate factory'], + ['seeder', null, InputOption::VALUE_NONE, 'To generate seeder'], + ['localized', null, InputOption::VALUE_NONE, 'Localize files.'], + ['repositoryPattern', null, InputOption::VALUE_REQUIRED, 'Repository Pattern'], + ['connection', null, InputOption::VALUE_REQUIRED, 'Specify connection name'], + ]; + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['model', InputArgument::REQUIRED, 'Singular Model name'], + ]; + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Commands/RollbackGeneratorCommand.php b/app/Classes/CodeGenerator/Commands/RollbackGeneratorCommand.php new file mode 100644 index 00000000..dd7552d1 --- /dev/null +++ b/app/Classes/CodeGenerator/Commands/RollbackGeneratorCommand.php @@ -0,0 +1,187 @@ +composer = app()['composer']; + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + if (!in_array($this->argument('type'), [ + 'scaffold', 'micro' + ])) { + $this->error('invalid rollback type'); + } + + $this->commandData = new CommandData($this, $this->argument('type')); + $this->commandData->config->mName = $this->commandData->modelName = $this->argument('model'); + + $this->commandData->config->init($this->commandData, ['tableName', 'prefix', 'plural', 'views']); + + $this->rollbackCommon(); + $this->rollbackMicros(); + + if($this->commandData->commandType === 'scaffold'){ + + $this->rollbackScaffold(); + $this->rollbackViews(); + + } + + + $this->info('Generating autoload files'); + $this->composer->dumpOptimized(); + } + + private function rollbackCommon(){ + $migrationGenerator = new MigrationGenerator($this->commandData); + $migrationGenerator->rollback(); + + $modelGenerator = new ModelGenerator($this->commandData); + $modelGenerator->rollback(); + + $factoryGenerator = new FactoryGenerator($this->commandData); + $factoryGenerator->rollback(); + + $seederGenerator = new SeederGenerator($this->commandData); + $seederGenerator->rollback(); + } + + private function rollbackMicros(){ + + $dataTransferObjectGenerator = new DataTransferObjectGenerator($this->commandData); + $dataTransferObjectGenerator->rollback(); + + $serviceGenerator = new ServicesGenerator($this->commandData); + $serviceGenerator->rollback(); + + } + + private function rollbackScaffold(){ + $resourceGenerator = new ResourceGenerator($this->commandData); + $resourceGenerator->rollback(); + + $validatorsGenerator = new ValidatorsGenerator($this->commandData); + $validatorsGenerator->rollback(); + + $rulesGenerator = new RulesGenerator($this->commandData); + $rulesGenerator->rollback(); + + File::deleteDirectories(app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/Standards/')); + + $routesGenerator = new RoutesGenerator($this->commandData); + $routesGenerator->rollback(); + + $webRouteGenerator = new WebRouteGenerator($this->commandData); + $webRouteGenerator->rollback(); + + $controllerGenerator = new ControllersGenerator($this->commandData); + $controllerGenerator->rollback(); + + $controllerLogicGenerator = new ControllerLogicGenerator($this->commandData); + $controllerLogicGenerator->rollback(); + + File::deleteDirectories(app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/')); + + } + + private function rollbackViews(){ + $viewGenerator = new ViewsGenerator($this->commandData); + $viewGenerator->rollback(); + + $vueGenerator = new vueGenerator($this->commandData); + $vueGenerator->rollback(); + } + + + + /** + * Get the console command options. + * + * @return array + */ + public function getOptions() + { + return [ + ['tableName', null, InputOption::VALUE_REQUIRED, 'Table Name'], + ['prefix', null, InputOption::VALUE_REQUIRED, 'Prefix for all files'], + ['plural', null, InputOption::VALUE_REQUIRED, 'Plural Model name'], + ['views', null, InputOption::VALUE_REQUIRED, 'Views to rollback'], + ]; + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return [ + ['model', InputArgument::REQUIRED, 'Singular Model name'], + ['type', InputArgument::REQUIRED, 'Rollback type: (micro / scaffold )'], + ]; + } + +} diff --git a/app/Classes/CodeGenerator/Commands/Scaffold/MicroGeneratorCommand.php b/app/Classes/CodeGenerator/Commands/Scaffold/MicroGeneratorCommand.php new file mode 100644 index 00000000..2964a6b1 --- /dev/null +++ b/app/Classes/CodeGenerator/Commands/Scaffold/MicroGeneratorCommand.php @@ -0,0 +1,91 @@ +commandData = new CommandData($this, 'micro'); + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + parent::handle(); + + if ($this->checkIsThereAnyDataToGenerate()) { + + $this->generateCommonItems(); + + $this->generateMicroItems(); + + $this->performPostActionsWithMigration(); + + } else { + + $this->commandData->commandInfo('There are not enough input fields for scaffold generation.'); + + } + } + + + /** + * Get the console command options. + * + * @return array + */ + public function getOptions() + { + return array_merge(parent::getOptions(), []); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array_merge(parent::getArguments(), []); + } + + /** + * Check if there is anything to generate. + * + * @return bool + */ + protected function checkIsThereAnyDataToGenerate() + { + if (count($this->commandData->fields) > 1) { + return true; + } + } +} diff --git a/app/Classes/CodeGenerator/Commands/Scaffold/ScaffoldGeneratorCommand.php b/app/Classes/CodeGenerator/Commands/Scaffold/ScaffoldGeneratorCommand.php new file mode 100644 index 00000000..dc370e61 --- /dev/null +++ b/app/Classes/CodeGenerator/Commands/Scaffold/ScaffoldGeneratorCommand.php @@ -0,0 +1,96 @@ +commandData = new CommandData($this, 'scaffold'); + } + + /** + * Execute the command. + * + * @return void + */ + public function handle() + { + parent::handle(); + + if ($this->checkIsThereAnyDataToGenerate()) { + + + $this->generateCommonItems(); + + $this->generateMicroItems(); + + $this->generateScaffoldItems(); + +// $this->generateViews(); + + $this->performPostActionsWithMigration(); + + } else { + + $this->commandData->commandInfo('There are not enough input fields for scaffold generation.'); + + } + } + + + /** + * Get the console command options. + * + * @return array + */ + public function getOptions() + { + return array_merge(parent::getOptions(), []); + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array_merge(parent::getArguments(), []); + } + + /** + * Check if there is anything to generate. + * + * @return bool + */ + protected function checkIsThereAnyDataToGenerate() + { + if (count($this->commandData->fields) > 1) { + return true; + } + } +} diff --git a/app/Classes/CodeGenerator/Common/CommandData.php b/app/Classes/CodeGenerator/Common/CommandData.php new file mode 100644 index 00000000..a58cb978 --- /dev/null +++ b/app/Classes/CodeGenerator/Common/CommandData.php @@ -0,0 +1,294 @@ +templateManager; + } + + + /** + * @param Command $commandObj + * @param $commandType + * @param TemplatesManager $templatesManager + */ + public function __construct(Command $commandObj, $commandType, TemplatesManager $templatesManager = null) + { + $this->commandObj = $commandObj; + + if (is_null($templatesManager)) { + $this->templateManager = app(TemplatesManager::class); + } else { + $this->templateManager = $templatesManager; + } + + $this->commandType = $commandType; + + $this->fieldNamesMapping = [ + '$FIELD_NAME_TITLE$' => 'fieldTitle', + '$FIELD_NAME$' => 'name', + ]; + + $this->config = new GeneratorConfig(); + } + + public function commandError($error) + { + $this->commandObj->error($error); + } + + public function commandComment($message) + { + $this->commandObj->comment($message); + } + + public function commandWarn($warning) + { + $this->commandObj->warn($warning); + } + + public function commandInfo($message) + { + $this->commandObj->info($message); + } + + public function initCommandData() + { + $this->config->init($this); + } + + public function getOption($option) + { + return $this->config->getOption($option); + } + + public function getAddOn($option) + { + return $this->config->getAddOn($option); + } + + public function setOption($option, $value) + { + $this->config->setOption($option, $value); + } + + public function addDynamicVariable($name, $val) + { + $this->dynamicVars[$name] = $val; + } + + public function getFields() + { + $this->fields = []; + + if ($this->getOption('fieldsFile') or $this->getOption('jsonFromGUI')) { + $this->getInputFromFileOrJson(); + } elseif ($this->getOption('fromTable')) { + $this->getInputFromTable(); + } else { + $this->getInputFromConsole(); + } + } + + private function getInputFromConsole() + { + $this->commandInfo('Specify fields for the model (skip id & timestamp fields, we will add it automatically)'); + $this->commandInfo('Read docs carefully to specify field inputs)'); + $this->commandInfo('Enter "exit" to finish'); + + $this->addPrimaryKey(); + + while (true) { + $fieldInputStr = $this->commandObj->ask('Field: (name db_type html_type options)', ''); + + if (empty($fieldInputStr) || $fieldInputStr == false || $fieldInputStr == 'exit') { + break; + } + + if (!GeneratorFieldsInputUtil::validateFieldInput($fieldInputStr)) { + $this->commandError('Invalid Input. Try again'); + continue; + } + + $validations = $this->commandObj->ask('Enter validations: ', false); + $validations = ($validations == false) ? '' : $validations; + + if ($this->getOption('relations')) { + $relation = $this->commandObj->ask('Enter relationship (Leave Blank to skip):', false); + } else { + $relation = ''; + } + + $this->fields[] = GeneratorFieldsInputUtil::processFieldInput( + $fieldInputStr, + $validations + ); + + if (!empty($relation)) { + $this->relations[] = GeneratorFieldRelation::parseRelation($relation); + } + } + + $this->addTimestamps(); + } + + private function addPrimaryKey() + { + $primaryKey = new GeneratorField(); + if ($this->getOption('primary')) { + $primaryKey->name = $this->getOption('primary'); + } else { + $primaryKey->name = 'id'; + } + $primaryKey->parseDBType('increments'); + $primaryKey->parseOptions('s,f,p,if,ii'); + + $this->fields[] = $primaryKey; + } + + private function addTimestamps() + { + $createdAt = new GeneratorField(); + $createdAt->name = 'created_at'; + $createdAt->parseDBType('timestamp'); + $createdAt->parseOptions('s,f,if,ii'); + $this->fields[] = $createdAt; + + $updatedAt = new GeneratorField(); + $updatedAt->name = 'updated_at'; + $updatedAt->parseDBType('timestamp'); + $updatedAt->parseOptions('s,f,if,ii'); + $this->fields[] = $updatedAt; + } + + private function getInputFromFileOrJson() + { + // fieldsFile option will get high priority than json option if both options are passed + try { + if ($this->getOption('fieldsFile')) { + $fieldsFileValue = $this->getOption('fieldsFile'); + if (file_exists($fieldsFileValue)) { + $filePath = $fieldsFileValue; + } elseif (file_exists(base_path($fieldsFileValue))) { + $filePath = base_path($fieldsFileValue); + } else { + $schemaFileDirector = app_path('Classes/CodeGenerator/Schemas/'); + $filePath = $schemaFileDirector.$fieldsFileValue; + } + + if (!file_exists($filePath)) { + $this->commandError('Fields file not found'); + exit; + } + + $fileContents = file_get_contents($filePath); + $jsonData = json_decode($fileContents, true); + $this->fields = []; + foreach ($jsonData as $field) { + if (isset($field['type']) && $field['relation']) { + $this->relations[] = GeneratorFieldRelation::parseRelation($field['relation']); + } else { + $this->fields[] = GeneratorField::parseFieldFromFile($field); + if (isset($field['relation'])) { + $this->relations[] = GeneratorFieldRelation::parseRelation($field['relation']); + } + } + } + } else { + $fileContents = $this->getOption('jsonFromGUI'); + $jsonData = json_decode($fileContents, true); + + // override config options from jsonFromGUI + $this->config->overrideOptionsFromJsonFile($jsonData); + + // Manage custom table name option + if (isset($jsonData['tableName'])) { + $tableName = $jsonData['tableName']; + $this->config->tableName = $tableName; + $this->addDynamicVariable('$TABLE_NAME$', $tableName); + $this->addDynamicVariable('$TABLE_NAME_TITLE$', Str::studly($tableName)); + } + + // Manage migrate option + if (isset($jsonData['migrate']) && $jsonData['migrate'] == false) { + $this->config->options['skip'][] = 'migration'; + } + + foreach ($jsonData['fields'] as $field) { + if (isset($field['type']) && $field['relation']) { + $this->relations[] = GeneratorFieldRelation::parseRelation($field['relation']); + } else { + $this->fields[] = GeneratorField::parseFieldFromFile($field); + if (isset($field['relation'])) { + $this->relations[] = GeneratorFieldRelation::parseRelation($field['relation']); + } + } + } + } + } catch (Exception $e) { + $this->commandError($e->getMessage()); + exit; + } + } + + private function getInputFromTable() + { + $tableName = $this->dynamicVars['$TABLE_NAME$']; + + $ignoredFields = $this->getOption('ignoreFields'); + if (!empty($ignoredFields)) { + $ignoredFields = explode(',', trim($ignoredFields)); + } else { + $ignoredFields = []; + } + + $tableFieldsGenerator = new TableFieldsGenerator($tableName, $ignoredFields, $this->config->connection); + $tableFieldsGenerator->prepareFieldsFromTable(); + $tableFieldsGenerator->prepareRelations(); + + $this->fields = $tableFieldsGenerator->fields; + $this->relations = $tableFieldsGenerator->relations; + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Common/GenerateGetters.php b/app/Classes/CodeGenerator/Common/GenerateGetters.php new file mode 100644 index 00000000..fbf5be5a --- /dev/null +++ b/app/Classes/CodeGenerator/Common/GenerateGetters.php @@ -0,0 +1,26 @@ +generatorHelpers->get_template('Micros.getter_function'); + + $template = str_replace('$FIELD_NAME$', str::camel($name), $template); + $template = str_replace('$DATA_TYPE$', $type, $template); + $template = str_replace('$FUNCTION_NAME$', $functionPrefix.str::studly($name), $template); + + return $template; + } + + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Common/GeneratorConfig.php b/app/Classes/CodeGenerator/Common/GeneratorConfig.php new file mode 100644 index 00000000..6c96c118 --- /dev/null +++ b/app/Classes/CodeGenerator/Common/GeneratorConfig.php @@ -0,0 +1,413 @@ +mName = $commandData->modelName; + + $this->prepareAddOns(); + $this->prepareOptions($commandData); + $this->prepareModelNames(); + $this->preparePrefixes(); + $this->loadPaths(); + $this->prepareTableName(); + $this->preparePrimaryName(); + $this->loadNamespaces($commandData); + $commandData = $this->loadDynamicVariables($commandData); + $this->commandData = &$commandData; + } + + public function loadNamespaces(CommandData &$commandData) + { + $prefix = $this->prefixes['ns']; + + if (!empty($prefix)) { + $prefix = '\\'.$prefix; + } + + $this->nsApp = $commandData->commandObj->getLaravel()->getNamespace(); + $this->nsApp = substr($this->nsApp, 0, strlen($this->nsApp) - 1); + $this->nsModel = 'App\Models'; + $this->nsModelExtend = 'App\Models\AbstractModel'; + + $this->nsBaseController = 'App\Http\Controllers'; + $this->nsController = 'App\Http\Controllers'.$prefix; + + $this->nsApiTests = 'Tests\APIs'; + $this->nsTests = 'Tests'; + } + + public function loadPaths() + { + $prefix = $this->prefixes['path']; + + if (!empty($prefix)) { + $prefix .= '/'; + } + + $this->pathModel = app_path('Models/'); + + $this->pathApiRoutes = base_path('routes/api.php'); + + $this->pathApiTests = base_path('tests/APIs/'); + + $this->pathController = app_path('Http/Controllers/').$prefix; + + $this->pathRoutes = base_path('routes/web.php'); + $this->pathFactory = database_path('factories/'); + + + $this->pathSeeder = database_path('seeds/'); + $this->pathDatabaseSeeder = database_path('seeds/DatabaseSeeder.php'); + } + + public function loadDynamicVariables(CommandData &$commandData) + { + $commandData->addDynamicVariable('$NAMESPACE_APP$', $this->nsApp); + $commandData->addDynamicVariable('$NAMESPACE_MODEL$', $this->nsModel); + $commandData->addDynamicVariable('$NAMESPACE_MODEL_EXTEND$', $this->nsModelExtend); + + $commandData->addDynamicVariable('$NAMESPACE_BASE_CONTROLLER$', $this->nsBaseController); + $commandData->addDynamicVariable('$NAMESPACE_CONTROLLER$', $this->nsController); + + $commandData->addDynamicVariable('$NAMESPACE_API_TESTS$', $this->nsApiTests); + $commandData->addDynamicVariable('$NAMESPACE_TESTS$', $this->nsTests); + + $commandData->addDynamicVariable('$TABLE_NAME$', $this->tableName); + $commandData->addDynamicVariable('$TABLE_NAME_TITLE$', Str::studly($this->tableName)); + $commandData->addDynamicVariable('$PRIMARY_KEY_NAME$', $this->primaryName); + + $commandData->addDynamicVariable('$MODEL_NAME$', $this->mName); + $commandData->addDynamicVariable('$MODEL_NAME_CAMEL$', $this->mCamel); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL$', $this->mPlural); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL_CAMEL$', $this->mCamelPlural); + $commandData->addDynamicVariable('$MODEL_NAME_SNAKE$', $this->mSnake); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL_SNAKE$', $this->mSnakePlural); + $commandData->addDynamicVariable('$MODEL_NAME_DASHED$', $this->mDashed); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL_DASHED$', $this->mDashedPlural); + $commandData->addDynamicVariable('$MODEL_NAME_SLASH$', $this->mSlash); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL_SLASH$', $this->mSlashPlural); + $commandData->addDynamicVariable('$MODEL_NAME_HUMAN$', $this->mHuman); + $commandData->addDynamicVariable('$MODEL_NAME_PLURAL_HUMAN$', $this->mHumanPlural); + $commandData->addDynamicVariable('$FILES$', ''); + + if (!empty($this->prefixes['route'])) { + $commandData->addDynamicVariable('$ROUTE_NAMED_PREFIX$', $this->prefixes['route'].'.'); + $commandData->addDynamicVariable('$ROUTE_PREFIX$', str_replace('.', '/', $this->prefixes['route']).'/'); + $commandData->addDynamicVariable('$RAW_ROUTE_PREFIX$', $this->prefixes['route']); + } else { + $commandData->addDynamicVariable('$ROUTE_PREFIX$', ''); + $commandData->addDynamicVariable('$ROUTE_NAMED_PREFIX$', ''); + } + + if (!empty($this->prefixes['ns'])) { + $commandData->addDynamicVariable('$PATH_PREFIX$', $this->prefixes['ns'].'\\'); + } else { + $commandData->addDynamicVariable('$PATH_PREFIX$', ''); + } + + if (!empty($this->prefixes['view'])) { + $commandData->addDynamicVariable('$VIEW_PREFIX$', str_replace('/', '.', $this->prefixes['view']).'.'); + } else { + $commandData->addDynamicVariable('$VIEW_PREFIX$', ''); + } + + if (!empty($this->prefixes['public'])) { + $commandData->addDynamicVariable('$PUBLIC_PREFIX$', $this->prefixes['public']); + } else { + $commandData->addDynamicVariable('$PUBLIC_PREFIX$', ''); + } + + $commandData->addDynamicVariable( + '$API_PREFIX$', + 'api' + ); + + $commandData->addDynamicVariable( + '$API_VERSION$', + 'v1' + ); + + $commandData->addDynamicVariable('$SEARCHABLE$', ''); + + return $commandData; + } + + public function prepareTableName() + { + if ($this->getOption('tableName')) { + $this->tableName = $this->getOption('tableName'); + } else { + $this->tableName = $this->mSnakePlural; + } + } + + public function preparePrimaryName() + { + if ($this->getOption('primary')) { + $this->primaryName = $this->getOption('primary'); + } else { + $this->primaryName = 'id'; + } + } + + public function prepareModelNames() + { + if ($this->getOption('plural')) { + $this->mPlural = $this->getOption('plural'); + } else { + $this->mPlural = Str::plural($this->mName); + } + $this->mCamel = Str::camel($this->mName); + $this->mCamelPlural = Str::camel($this->mPlural); + $this->mSnake = Str::snake($this->mName); + $this->mSnakePlural = Str::snake($this->mPlural); + $this->mDashed = str_replace('_', '-', Str::snake($this->mSnake)); + $this->mDashedPlural = str_replace('_', '-', Str::snake($this->mSnakePlural)); + $this->mSlash = str_replace('_', '/', Str::snake($this->mSnake)); + $this->mSlashPlural = str_replace('_', '/', Str::snake($this->mSnakePlural)); + $this->mHuman = Str::title(str_replace('_', ' ', Str::snake($this->mSnake))); + $this->mHumanPlural = Str::title(str_replace('_', ' ', Str::snake($this->mSnakePlural))); + } + + public function prepareOptions(CommandData &$commandData) + { + foreach (self::$availableOptions as $option) { + $this->options[$option] = $commandData->commandObj->option($option); + } + + if (isset($options['fromTable']) and $this->options['fromTable']) { + if (!$this->options['tableName']) { + $commandData->commandError('tableName required with fromTable option.'); + exit; + } + } + + $this->options['softDelete'] = true; + if (!empty($this->options['skip'])) { + $this->options['skip'] = array_map('trim', explode(',', $this->options['skip'])); + } + } + + public function preparePrefixes() + { + $this->prefixes['route'] = explode('/', ''); + $this->prefixes['path'] = explode('/', ''); + $this->prefixes['view'] = explode('.', ''); + $this->prefixes['public'] = explode('/', ''); + + if ($this->getOption('prefix')) { + $multiplePrefixes = explode('/', $this->getOption('prefix')); + + $this->prefixes['route'] = array_merge($this->prefixes['route'], $multiplePrefixes); + $this->prefixes['path'] = array_merge($this->prefixes['path'], $multiplePrefixes); + $this->prefixes['view'] = array_merge($this->prefixes['view'], $multiplePrefixes); + $this->prefixes['public'] = array_merge($this->prefixes['public'], $multiplePrefixes); + } + + $this->prefixes['route'] = array_diff($this->prefixes['route'], ['']); + $this->prefixes['path'] = array_diff($this->prefixes['path'], ['']); + $this->prefixes['view'] = array_diff($this->prefixes['view'], ['']); + $this->prefixes['public'] = array_diff($this->prefixes['public'], ['']); + + $routePrefix = ''; + + foreach ($this->prefixes['route'] as $singlePrefix) { + $routePrefix .= Str::camel($singlePrefix).'.'; + } + + if (!empty($routePrefix)) { + $routePrefix = substr($routePrefix, 0, strlen($routePrefix) - 1); + } + + $this->prefixes['route'] = $routePrefix; + + $nsPrefix = ''; + + foreach ($this->prefixes['path'] as $singlePrefix) { + $nsPrefix .= Str::title($singlePrefix).'\\'; + } + + if (!empty($nsPrefix)) { + $nsPrefix = substr($nsPrefix, 0, strlen($nsPrefix) - 1); + } + + $this->prefixes['ns'] = $nsPrefix; + + $pathPrefix = ''; + + foreach ($this->prefixes['path'] as $singlePrefix) { + $pathPrefix .= Str::title($singlePrefix).'/'; + } + + if (!empty($pathPrefix)) { + $pathPrefix = substr($pathPrefix, 0, strlen($pathPrefix) - 1); + } + + $this->prefixes['path'] = $pathPrefix; + + $viewPrefix = ''; + + foreach ($this->prefixes['view'] as $singlePrefix) { + $viewPrefix .= Str::camel($singlePrefix).'/'; + } + + if (!empty($viewPrefix)) { + $viewPrefix = substr($viewPrefix, 0, strlen($viewPrefix) - 1); + } + + $this->prefixes['view'] = $viewPrefix; + + $publicPrefix = ''; + + foreach ($this->prefixes['public'] as $singlePrefix) { + $publicPrefix .= Str::camel($singlePrefix).'/'; + } + + if (!empty($publicPrefix)) { + $publicPrefix = substr($publicPrefix, 0, strlen($publicPrefix) - 1); + } + + $this->prefixes['public'] = $publicPrefix; + } + + public function overrideOptionsFromJsonFile($jsonData) + { + $options = self::$availableOptions; + + foreach ($options as $option) { + if (isset($jsonData['options'][$option])) { + $this->setOption($option, $jsonData['options'][$option]); + } + } + + // prepare prefixes than reload namespaces, paths and dynamic variables + if (!empty($this->getOption('prefix'))) { + $this->preparePrefixes(); + $this->loadPaths(); + $this->loadNamespaces($this->commandData); + $this->loadDynamicVariables($this->commandData); + } + } + + public function getOption($option) + { + if (isset($this->options[$option])) { + return $this->options[$option]; + } + + return false; + } + + public function getAddOn($addOn) + { + if (isset($this->addOns[$addOn])) { + return $this->addOns[$addOn]; + } + + return false; + } + + public function setOption($option, $value) + { + $this->options[$option] = $value; + } + + public function prepareAddOns() + { + $this->addOns['tests'] = false; + } + + public function excludeFields() + { + return self::$excludeFields; + } +} diff --git a/app/Classes/CodeGenerator/Common/GeneratorField.php b/app/Classes/CodeGenerator/Common/GeneratorField.php new file mode 100644 index 00000000..b3a7adff --- /dev/null +++ b/app/Classes/CodeGenerator/Common/GeneratorField.php @@ -0,0 +1,173 @@ +dbInput = $dbInput; + if (!is_null($column)) { + $this->dbInput = ($column->getLength() > 0) ? $this->dbInput.','.$column->getLength() : $this->dbInput; + $this->dbInput = (!$column->getNotnull()) ? $this->dbInput.':nullable' : $this->dbInput; + } + $this->prepareMigrationText(); + } + + public function parseHtmlInput($htmlInput) + { + $this->htmlInput = $htmlInput; + $this->htmlValues = []; + + if (empty($htmlInput)) { + $this->htmlType = 'text'; + + return; + } + + if (Str::contains($htmlInput, 'selectTable')) { + $inputsArr = explode(':', $htmlInput); + $this->htmlType = array_shift($inputsArr); + $this->htmlValues = $inputsArr; + + return; + } + + $inputsArr = explode(',', $htmlInput); + + $this->htmlType = array_shift($inputsArr); + + if (count($inputsArr) > 0) { + $this->htmlValues = $inputsArr; + } + } + + public function parseOptions($options) + { + $options = strtolower($options); + $optionsArr = explode(',', $options); + if (in_array('s', $optionsArr)) { + $this->isSearchable = false; + } + if (in_array('p', $optionsArr)) { + // if field is primary key, then its not searchable, fillable, not in index & form + $this->isPrimary = true; + $this->isSearchable = false; + $this->isFillable = false; + $this->inForm = false; + $this->inIndex = false; + $this->inView = false; + } + if (in_array('f', $optionsArr)) { + $this->isFillable = false; + } + if (in_array('if', $optionsArr)) { + $this->inForm = false; + } + if (in_array('ii', $optionsArr)) { + $this->inIndex = false; + } + if (in_array('iv', $optionsArr)) { + $this->inView = false; + } + } + + private function prepareMigrationText() + { + $inputsArr = explode(':', $this->dbInput); + $this->migrationText = '$table->'; + + $fieldTypeParams = explode(',', array_shift($inputsArr)); + $this->fieldType = array_shift($fieldTypeParams); + $this->migrationText .= $this->fieldType."('".$this->name."'"; + + if ($this->fieldType == 'enum') { + $this->migrationText .= ', ['; + foreach ($fieldTypeParams as $param) { + $this->migrationText .= "'".$param."',"; + } + $this->migrationText = substr($this->migrationText, 0, strlen($this->migrationText) - 1); + $this->migrationText .= ']'; + } else { + foreach ($fieldTypeParams as $param) { + $this->migrationText .= ', '.$param; + } + } + + $this->migrationText .= ')'; + + foreach ($inputsArr as $input) { + $inputParams = explode(',', $input); + $functionName = array_shift($inputParams); + if ($functionName == 'foreign') { + $foreignTable = array_shift($inputParams); + $foreignField = array_shift($inputParams); + $this->foreignKeyText .= "\$table->foreign('".$this->name."')->references('".$foreignField."')->on('".$foreignTable."');"; + } else { + $this->migrationText .= '->'.$functionName; + $this->migrationText .= '('; + $this->migrationText .= implode(', ', $inputParams); + $this->migrationText .= ')'; + } + } + + $this->migrationText .= ';'; + } + + public static function parseFieldFromFile($fieldInput) + { + $field = new self(); + $field->name = $fieldInput['name']; + $field->parseDBType($fieldInput['dbType']); + $field->parseHtmlInput(isset($fieldInput['htmlType']) ? $fieldInput['htmlType'] : ''); + $field->validations = isset($fieldInput['validations']) ? $fieldInput['validations'] : ''; + $field->isSearchable = isset($fieldInput['searchable']) ? $fieldInput['searchable'] : false; + $field->isFillable = isset($fieldInput['fillable']) ? $fieldInput['fillable'] : true; + $field->isPrimary = isset($fieldInput['primary']) ? $fieldInput['primary'] : false; + $field->inForm = isset($fieldInput['inForm']) ? $fieldInput['inForm'] : true; + $field->inIndex = isset($fieldInput['inIndex']) ? $fieldInput['inIndex'] : true; + $field->inView = isset($fieldInput['inView']) ? $fieldInput['inView'] : true; + + return $field; + } + + public function __get($key) + { + if ($key == 'fieldTitle') { + return Str::title(str_replace('_', ' ', $this->name)); + } + + return $this->$key; + } +} diff --git a/app/Classes/CodeGenerator/Common/GeneratorFieldRelation.php b/app/Classes/CodeGenerator/Common/GeneratorFieldRelation.php new file mode 100644 index 00000000..eb569c75 --- /dev/null +++ b/app/Classes/CodeGenerator/Common/GeneratorFieldRelation.php @@ -0,0 +1,103 @@ +type = array_shift($inputs); + $modelWithRelation = explode(':', array_shift($inputs)); //e.g ModelName:relationName + if (count($modelWithRelation) == 2) { + $relation->relationName = $modelWithRelation[1]; + unset($modelWithRelation[1]); + } + $relation->inputs = array_merge($modelWithRelation, $inputs); + + return $relation; + } + + public function getRelationFunctionText($relationText = null) + { + $singularRelation = (!empty($this->relationName)) ? $this->relationName : Str::camel($relationText); + $pluralRelation = (!empty($this->relationName)) ? $this->relationName : Str::camel(Str::plural($relationText)); + + switch ($this->type) { + case '1t1': + $functionName = $singularRelation; + $relation = 'hasOne'; + $relationClass = 'HasOne'; + break; + case '1tm': + $functionName = $pluralRelation; + $relation = 'hasMany'; + $relationClass = 'HasMany'; + break; + case 'mt1': + if (!empty($this->relationName)) { + $singularRelation = $this->relationName; + } elseif (isset($this->inputs[1])) { + $singularRelation = Str::camel(str_replace('_id', '', strtolower($this->inputs[1]))); + } + $functionName = $singularRelation; + $relation = 'belongsTo'; + $relationClass = 'BelongsTo'; + break; + case 'mtm': + $functionName = $pluralRelation; + $relation = 'belongsToMany'; + $relationClass = 'BelongsToMany'; + break; + case 'hmt': + $functionName = $pluralRelation; + $relation = 'hasManyThrough'; + $relationClass = 'HasManyThrough'; + break; + default: + $functionName = ''; + $relation = ''; + $relationClass = ''; + break; + } + + if (!empty($functionName) and !empty($relation)) { + return $this->generateRelation($functionName, $relation, $relationClass); + } + + return ''; + } + + private function generateRelation($functionName, $relation, $relationClass) + { + $inputs = $this->inputs; + $modelName = array_shift($inputs); + + $template = (new GeneratorHelpers())->get_template('Models.relationship'); + + $template = str_replace('$RELATIONSHIP_CLASS$', $relationClass, $template); + $template = str_replace('$FUNCTION_NAME$', $functionName, $template); + $template = str_replace('$RELATION$', $relation, $template); + $template = str_replace('$RELATION_MODEL_NAME$', $modelName, $template); + + if (count($inputs) > 0) { + $inputFields = implode("', '", $inputs); + $inputFields = ", '".$inputFields."'"; + } else { + $inputFields = ''; + } + + $template = str_replace('$INPUT_FIELDS$', $inputFields, $template); + + return $template; + } +} diff --git a/app/Classes/CodeGenerator/Common/GeneratorHelpers.php b/app/Classes/CodeGenerator/Common/GeneratorHelpers.php new file mode 100644 index 00000000..350faf57 --- /dev/null +++ b/app/Classes/CodeGenerator/Common/GeneratorHelpers.php @@ -0,0 +1,78 @@ +generator_tab($spaces), $tabs); + } + + public function generator_nl($count = 1) + { + return str_repeat(PHP_EOL, $count); + } + + public function generator_nls($count, $nls = 1) + { + return str_repeat($this->generator_nl($nls), $count); + } + + public function generator_nl_tab($lns = 1, $tabs = 1) + { + return $this->generator_nl($lns) . $this->generator_tabs($tabs); + } + + public function get_template_file_path($templateName) + { + $templateName = str_replace('.', '/', $templateName); + + return base_path('App/Classes/CodeGenerator/Stubs/'.$templateName.'.stub'); + } + + public function get_template($templateName) + { + $path = $this->get_template_file_path($templateName); + + return file_get_contents($path); + } + + public function fill_template($variables, $template) + { + foreach ($variables as $variable => $value) { + $template = str_replace($variable, $value, $template); + } + + return $template; + } + + public function fill_field_template($variables, $template, $field) + { + foreach ($variables as $variable => $key) { + $template = str_replace($variable, $field->$key, $template); + } + + return $template; + } + + public function fill_template_with_field_data($variables, $fieldVariables, $template, $field) + { + $template = $this->fill_template($variables, $template); + + return $this->fill_field_template($fieldVariables, $template, $field); + } + + public function model_name_from_table_name($tableName) + { + return Str::ucfirst(Str::camel(Str::singular($tableName))); + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Common/TemplatesManager.php b/app/Classes/CodeGenerator/Common/TemplatesManager.php new file mode 100644 index 00000000..48420aff --- /dev/null +++ b/app/Classes/CodeGenerator/Common/TemplatesManager.php @@ -0,0 +1,24 @@ +useLocale; + } + + /** + * @param bool $useLocale + */ + public function setUseLocale(bool $useLocale): void + { + $this->useLocale = $useLocale; + } +} diff --git a/app/Classes/CodeGenerator/Generators/BaseGenerator.php b/app/Classes/CodeGenerator/Generators/BaseGenerator.php new file mode 100644 index 00000000..a2105b2d --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/BaseGenerator.php @@ -0,0 +1,31 @@ +generatorHelpers = new GeneratorHelpers(); + } + + + public function rollbackFile($path, $fileName) + { + if (file_exists($path.$fileName)) { + return FileUtil::deleteFile($path, $fileName); + } + + return false; + } +} diff --git a/app/Classes/CodeGenerator/Generators/FactoryGenerator.php b/app/Classes/CodeGenerator/Generators/FactoryGenerator.php new file mode 100644 index 00000000..8a5f0c94 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/FactoryGenerator.php @@ -0,0 +1,119 @@ +commandData = $commandData; + $this->path = $commandData->config->pathFactory; + $this->fileName = Str::studly(Str::singular($this->commandData->modelName)).'Factory.php'; + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Factories.model_factory'); + + $templateData = $this->fillTemplate($templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandObj->comment("\nFactory created: "); + $this->commandData->commandObj->info($this->fileName); + } + + /** + * @param string $templateData + * + * @return mixed|string + */ + private function fillTemplate($templateData) + { + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace( + '$FIELDS$', + implode(','.$this->generatorHelpers->generator_nl_tab(1, 2), $this->generateFields()), + $templateData + ); + + return $templateData; + } + + /** + * @return array + */ + private function generateFields() + { + $fields = []; + + foreach ($this->commandData->fields as $field) { + if ($field->isPrimary) { + continue; + } + + $fieldData = "'".$field->name."' => ".'$faker->'; + + switch ($field->fieldType) { + case 'integer': + case 'float': + $fakerData = 'randomDigitNotNull'; + break; + case 'string': + $fakerData = 'word'; + break; + case 'text': + $fakerData = 'text'; + break; + case 'datetime': + case 'timestamp': + $fakerData = "date('Y-m-d H:i:s')"; + break; + case 'enum': + $fakerData = 'randomElement('. + GeneratorFieldsInputUtil::prepareValuesArrayStr($field->htmlValues). + ')'; + break; + default: + $fakerData = 'word'; + } + + $fieldData .= $fakerData; + + $fields[] = $fieldData; + } + + return $fields; + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + $this->commandData->commandComment('Factory file deleted: '.$this->fileName); + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/Micros/DataTransferObjectGenerator.php b/app/Classes/CodeGenerator/Generators/Micros/DataTransferObjectGenerator.php new file mode 100644 index 00000000..7e246cbb --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Micros/DataTransferObjectGenerator.php @@ -0,0 +1,140 @@ +commandData = $commandData; + $this->path = app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/DataTransferObjects/'); + $this->fileName = Str::studly(Str::singular($this->commandData->modelName)).'Object.php'; + } + + public function generate() + { + + $templateData = $this->generatorHelpers->get_template('Micros.data_transfer_object'); + + $templateData = $this->fillTemplate($templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\nDataTransferObject created: "); + $this->commandData->commandObj->info($this->fileName); + + } + + /** + * @param string $templateData + * + * @return mixed|string + */ + private function fillTemplate($templateData) + { + $properties = []; + $docs = []; + $injection = []; + $body = []; + $getters = []; + + foreach ($this->commandData->fields as $field) { + if(!in_array($field->name, $this->commandData->config->excludeFields())){ + $docType = $this->getPHPDocType($field->fieldType); + $fieldName = $docType === 'bool' ? 'is'.str::studly($field->name) : str::camel($field->name); + $properties[] = '/** @var '.$docType.' */'.PHP_EOL.$this->generatorHelpers->generator_nl_tab(0, 1).'private $'.str::camel($fieldName).';'; + $docs[] = '* @param '.$docType.' $'.str::camel($fieldName); + $injection[] = $docType.' $'.str::camel($fieldName); + $body[] = '$this->'.str::camel($fieldName).' = $'.str::camel($fieldName).';'; + $getters[] = (new GenerateGetters())->generate($fieldName, $docType); + } + + } + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace( + '$PROPERTIES$', + implode(PHP_EOL.$this->generatorHelpers->generator_nl_tab(1, 1), $properties), + $templateData + ); + + $templateData = str_replace( + '$CONSTRUCTOR_DOCS$', + implode($this->generatorHelpers->generator_nl_tab(1, 2), $docs), + $templateData + ); + + $templateData = str_replace( + '$CONSTRUCTOR_PROPERTIES$', + implode(', ', $injection), + $templateData + ); + + $templateData = str_replace( + '$CONSTRUCTOR_BODY$', + implode($this->generatorHelpers->generator_nl_tab(1, 2), $body), + $templateData + ); + + $templateData = str_replace( + '$GETTER_FUNCTIONS$', + implode($this->generatorHelpers->generator_nl_tab(1, 0), $getters), + $templateData + ); + + return $templateData; + } + + + + private function getPHPDocType($db_type){ + switch ($db_type) { + case 'text': + return 'string'; + case 'datetime': + return '\Carbon\Carbon'; + case 'boolean': + return 'bool'; + default: + return $db_type; + + } + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + File::deleteDirectory($this->path); + $this->commandData->commandComment('DataTransferObject file deleted: '.$this->fileName); + } + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Generators/Micros/ResourceGenerator.php b/app/Classes/CodeGenerator/Generators/Micros/ResourceGenerator.php new file mode 100644 index 00000000..a6db66e8 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Micros/ResourceGenerator.php @@ -0,0 +1,75 @@ +commandData = $commandData; + $this->path = app_path('Http/Resources/'); + $this->fileName = Str::studly(Str::singular($this->commandData->modelName)).'Resource.php'; + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Resource.model_resource'); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace('$FIELDS$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 3), $this->generateFields()), $templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\n Resource Object created: "); + $this->commandData->commandObj->info($this->fileName); + + } + + + private function generateFields() + { + + $fields = []; + + foreach ($this->commandData->fields as $field) { + + $field = "'" . $field->name . "' => " . "$" . "this->" . str::snake($field->name); + $fields[] = $field; + } + + return $fields; + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + $this->commandData->commandComment('Resource Object file deleted: '.$this->fileName); + } + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Generators/Micros/RulesGenerator.php b/app/Classes/CodeGenerator/Generators/Micros/RulesGenerator.php new file mode 100644 index 00000000..be1b72d4 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Micros/RulesGenerator.php @@ -0,0 +1,68 @@ +commandData = $commandData; + $this->path = app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/Standards/Rules/'); + } + + public function generate() + { + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = 'Can'.str::studly($type.$name).'.php'; + $templateData = $this->generatorHelpers->get_template('Rules.can_'.$type); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + FileUtil::createFile($this->path, $filename, $templateData); + + $this->commandData->commandComment("\n" . $type . " Rules created: "); + $this->commandData->commandObj->info($filename); + } + + } + + public function rollback() + { + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename ='Can'.str::studly($type.$name).'.php'; + + if ($this->rollbackFile($this->path, $filename)) { + $this->commandData->commandComment($type . ' Rules file deleted: '.$filename); + } + } + + File::deleteDirectory($this->path); + + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Generators/Micros/ServicesGenerator.php b/app/Classes/CodeGenerator/Generators/Micros/ServicesGenerator.php new file mode 100644 index 00000000..ad45cb0f --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Micros/ServicesGenerator.php @@ -0,0 +1,96 @@ +commandData = $commandData; + $this->path = app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/Services/'); + } + + public function generate() + { + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.($type === 'fetch'?'es':'s').$name).'.php'; + + $templateData = $this->generatorHelpers->get_template("Services.".str::snake($type.'_service')); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace( + '$FIELDS$', + implode($this->generatorHelpers->generator_nl_tab(1, 2), $this->generateFields()), + $templateData + ); + + + FileUtil::createFile($this->path, $filename, $templateData); + + $this->commandData->commandComment("\n" . $type . " service class created: "); + $this->commandData->commandObj->info($filename); + + } + + } + + + private function generateFields() + { + + $fields = []; + + foreach ($this->commandData->fields as $field) { + + if(!in_array($field->name, $this->commandData->config->excludeFields())) { + + $getterName = $field->dbInput === 'boolean' ? 'is' . str::studly($field->name) : 'get' . str::studly($field->name); + + $field = "$" . "model->" . $field->name . " = $" . "object->" . $getterName . "();"; + $fields[] = $field; + } + } + + return $fields; + } + + public function rollback() + { + + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.($type === 'fetch'?'es':'s').$name).'.php'; + if ($this->rollbackFile($this->path, $filename)) { + $this->commandData->commandComment( $type . ' service class file deleted: '.$filename); + } + } + + File::deleteDirectory(($this->path)); + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Generators/Micros/ValidatorsGenerator.php b/app/Classes/CodeGenerator/Generators/Micros/ValidatorsGenerator.php new file mode 100644 index 00000000..d9059548 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Micros/ValidatorsGenerator.php @@ -0,0 +1,112 @@ +commandData = $commandData; + $this->path = app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/Standards/Validators/'); + $this->fileName = Str::studly(Str::singular($this->commandData->modelName)).'Validation.php'; + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Validator.request_validation'); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace('$FIELDS$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 3), $this->generateFields()), $templateData); + $templateData = str_replace('$RULES$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 3), $this->generateRules()), $templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\n Request Validator created: "); + $this->commandData->commandObj->info($this->fileName); + + } + + private function generateRules() + { + $dont_require_fields = []; + + $rules = []; + + foreach ($this->commandData->fields as $field) { + if (!$field->isPrimary && $field->isNotNull && empty($field->validations) && + !in_array($field->name, $dont_require_fields)) { + $field->validations = 'required'; + } + + if (!empty($field->validations)) { + if (Str::contains($field->validations, 'unique:')) { + $rule = explode('|', $field->validations); + // move unique rule to last + usort($rule, function ($record) { + return (Str::contains($record, 'unique:')) ? 1 : 0; + }); + $field->validations = implode('|', $rule); + } + $rule = "'".$field->name."' => '".$field->validations."'"; + $rules[] = $rule; + } + } + + return $rules; + } + + private function generateFields() + { + + $fields = []; + + foreach ($this->commandData->fields as $field) { + + if(!in_array($field->name, $this->commandData->config->excludeFields())) { + + $getterName = $field->dbInput === 'boolean' ? 'is' . str::studly($field->name) : 'get' . str::studly($field->name); + + $field = "'" . $field->name . "' => " . "$" . "object->" . $getterName . "()"; + $fields[] = $field; + } + } + + return $fields; + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + File::deleteDirectory($this->path); + $this->commandData->commandComment('Request Validation file deleted: '.$this->fileName); + } + + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Generators/MigrationGenerator.php b/app/Classes/CodeGenerator/Generators/MigrationGenerator.php new file mode 100644 index 00000000..32adf6c7 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/MigrationGenerator.php @@ -0,0 +1,92 @@ +commandData = $commandData; + $this->path = database_path('migrations/'); + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Migration.migration'); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace('$FIELDS$', $this->generateFields(), $templateData); + + $tableName = $this->commandData->dynamicVars['$TABLE_NAME$']; + + $fileName = date('Y_m_d_His').'_'.'create_'.Str::snake(Str::plural($tableName)).'_table.php'; + + FileUtil::createFile($this->path, $fileName, $templateData); + + $this->commandData->commandComment("\nMigration created: "); + $this->commandData->commandInfo($fileName); + } + + private function generateFields() + { + $fields = []; + $foreignKeys = []; + $createdAtField = null; + $updatedAtField = null; + + $fields[] = '$table->id();'; + + foreach ($this->commandData->fields as $field) { + $fields[] = $field->migrationText; + if (!empty($field->foreignKeyText)) { + $foreignKeys[] = $field->foreignKeyText; + } + } + + $fields[] = '$table->timestamps();'; + + if ($this->commandData->getOption('softDelete')) { + $fields[] = '$table->softDeletes();'; + } + + return implode($this->generatorHelpers->generator_nl_tab(1, 3), array_merge($fields, $foreignKeys)); + } + + public function rollback() + { + $fileName = 'create_'.$this->commandData->config->tableName.'_table.php'; + + $allFiles = File::allFiles($this->path); + + $files = []; + + foreach ($allFiles as $file) { + $files[] = $file->getFilename(); + } + + $files = array_reverse($files); + + foreach ($files as $file) { + if (Str::contains($file, $fileName)) { + if ($this->rollbackFile($this->path, $file)) { + $this->commandData->commandComment('Migration file deleted: '.$file); + } + break; + } + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/ModelGenerator.php b/app/Classes/CodeGenerator/Generators/ModelGenerator.php new file mode 100644 index 00000000..0127d57a --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/ModelGenerator.php @@ -0,0 +1,351 @@ +commandData = $commandData; + $this->path = $commandData->config->pathModel; + $this->fileName = Str::studly(Str::singular($this->commandData->modelName)).'.php'; + $this->table = $this->commandData->dynamicVars['$TABLE_NAME$']; + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Models.model'); + + $templateData = $this->fillTemplate($templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\nModel created: "); + $this->commandData->commandInfo($this->fileName); + } + + private function fillTemplate($templateData) + { + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = $this->fillSoftDeletes($templateData); + + $fillables = []; + + foreach ($this->commandData->fields as $field) { + if ($field->isFillable) { + $fillables[] = "'".$field->name."'"; + } + } + + $templateData = $this->fillDocs($templateData); + + $templateData = $this->fillTimestamps($templateData); + + if ($this->commandData->getOption('primary')) { + $primary = $this->generatorHelpers->generator_tab()."protected \$primaryKey = '".$this->commandData->getOption('primary')."';\n"; + } else { + $primary = ''; + } + + $templateData = str_replace('$PRIMARY$', $primary, $templateData); + + $templateData = str_replace('$FIELDS$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 2), $fillables), $templateData); + + $templateData = str_replace('$RULES$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 2), $this->generateRules()), $templateData); + + $templateData = str_replace('$CAST$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 2), $this->generateCasts()), $templateData); + + $templateData = str_replace( + '$RELATIONS$', + $this->generatorHelpers->fill_template($this->commandData->dynamicVars, implode(PHP_EOL.$this->generatorHelpers->generator_nl_tab(1, 1), $this->generateRelations())), + $templateData + ); + + $templateData = str_replace('$GENERATE_DATE$', date('F j, Y, g:i a T'), $templateData); + + return $templateData; + } + + private function fillSoftDeletes($templateData) + { + if (!$this->commandData->getOption('softDelete')) { + $templateData = str_replace('$SOFT_DELETE_IMPORT$', '', $templateData); + $templateData = str_replace('$SOFT_DELETE$', '', $templateData); + $templateData = str_replace('$SOFT_DELETE_DATES$', '', $templateData); + } else { + $templateData = str_replace( + '$SOFT_DELETE_IMPORT$', + "use Illuminate\\Database\\Eloquent\\SoftDeletes;\n", + $templateData + ); + $templateData = str_replace('$SOFT_DELETE$', $this->generatorHelpers->generator_tab()."use SoftDeletes;\n", $templateData); + $deletedAtTimestamp = 'deleted_at'; + $templateData = str_replace( + '$SOFT_DELETE_DATES$', + $this->generatorHelpers->generator_nl_tab()."protected \$dates = ['".$deletedAtTimestamp."'];\n", + $templateData + ); + } + + return $templateData; + } + + private function fillDocs($templateData) + { + + $docsTemplate = $this->generatorHelpers->get_template('Docs.model'); + $docsTemplate = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $docsTemplate); + + $fillables = ''; + $fieldsArr = []; + $count = 1; + foreach ($this->commandData->relations as $relation) { + $field = $relationText = (isset($relation->inputs[0])) ? $relation->inputs[0] : null; + if (in_array($field, $fieldsArr)) { + $relationText = $relationText.'_'.$count; + $count++; + } + + $fillables .= ' * @property '.$this->getPHPDocType($relation->type, $relation, $relationText).PHP_EOL; + $fieldsArr[] = $field; + } + + foreach ($this->commandData->fields as $field) { + if ($field->isFillable) { + $fillables .= ' * @property '.$this->getPHPDocType($field->fieldType).' '.$field->name.PHP_EOL; + } + } + $docsTemplate = str_replace('$GENERATE_DATE$', date('F j, Y, g:i a'), $docsTemplate); + $docsTemplate = str_replace('$PHPDOC$', $fillables, $docsTemplate); + + $templateData = str_replace('$DOCS$', $docsTemplate, $templateData); + + return $templateData; + } + + /** + * @param $db_type + * @param GeneratorFieldRelation|null $relation + * @param string|null $relationText + * + * @return string + */ + private function getPHPDocType($db_type, $relation = null, $relationText = null) + { + $relationText = (!empty($relationText)) ? $relationText : null; + + switch ($db_type) { + case 'text': + return 'string'; + case 'datetime': + return 'string|\Carbon\Carbon'; + case '1t1': + return '\\'.$this->commandData->config->nsModel.'\\'.$relation->inputs[0].' '.Str::camel($relationText); + case 'mt1': + if (isset($relation->inputs[1])) { + $relationName = str_replace('_id', '', strtolower($relation->inputs[1])); + } else { + $relationName = $relationText; + } + + return '\\'.$this->commandData->config->nsModel.'\\'.$relation->inputs[0].' '.Str::camel($relationName); + case '1tm': + case 'mtm': + case 'hmt': + return '\Illuminate\Database\Eloquent\Collection'.' '.Str::camel(Str::plural($relationText)); + default: + if (!empty($fieldData['fieldType'])) { + return $fieldData['fieldType']; + } + + return $db_type; + } + } + + private function fillTimestamps($templateData) + { + $timestamps = TableFieldsGenerator::getTimestampFieldNames(); + + $replace = ''; + if (empty($timestamps)) { + $replace = $this->generatorHelpers->generator_nl_tab()."public \$timestamps = false;\n"; + } + + if ($this->commandData->getOption('fromTable') && !empty($timestamps)) { + list($created_at, $updated_at) = collect($timestamps)->map(function ($field) { + return !empty($field) ? "'$field'" : 'null'; + }); + + $replace .= $this->generatorHelpers->generator_nl_tab()."const CREATED_AT = $created_at;"; + $replace .= $this->generatorHelpers->generator_nl_tab()."const UPDATED_AT = $updated_at;\n"; + } + + return str_replace('$TIMESTAMPS$', $replace, $templateData); + } + + private function generateRules() + { + $dont_require_fields = []; + + $rules = []; + + foreach ($this->commandData->fields as $field) { + if (!$field->isPrimary && $field->isNotNull && empty($field->validations) && + !in_array($field->name, $dont_require_fields)) { + $field->validations = 'required'; + } + + if (!empty($field->validations)) { + if (Str::contains($field->validations, 'unique:')) { + $rule = explode('|', $field->validations); + // move unique rule to last + usort($rule, function ($record) { + return (Str::contains($record, 'unique:')) ? 1 : 0; + }); + $field->validations = implode('|', $rule); + } + $rule = "'".$field->name."' => '".$field->validations."'"; + $rules[] = $rule; + } + } + + return $rules; + } + + public function generateUniqueRules() + { + $tableNameSingular = Str::singular($this->commandData->config->tableName); + $uniqueRules = ''; + foreach ($this->generateRules() as $rule) { + if (Str::contains($rule, 'unique:')) { + $rule = explode('=>', $rule); + $string = '$rules['.trim($rule[0]).'].","'; + + $uniqueRules .= '$rules['.trim($rule[0]).'] = '.$string.'.$this->route("'.$tableNameSingular.'");'; + } + } + + return $uniqueRules; + } + + public function generateCasts() + { + $casts = []; + + $timestamps = TableFieldsGenerator::getTimestampFieldNames(); + + foreach ($this->commandData->fields as $field) { + if (in_array($field->name, $timestamps)) { + continue; + } + + $rule = "'".$field->name."' => "; + + switch (strtolower($field->fieldType)) { + case 'integer': + case 'increments': + case 'smallinteger': + case 'long': + case 'biginteger': + $rule .= "'integer'"; + break; + case 'double': + $rule .= "'double'"; + break; + case 'float': + case 'decimal': + $rule .= "'float'"; + break; + case 'boolean': + $rule .= "'boolean'"; + break; + case 'datetime': + case 'datetimetz': + $rule .= "'datetime'"; + break; + case 'date': + $rule .= "'date'"; + break; + case 'enum': + case 'string': + case 'char': + case 'text': + $rule .= "'string'"; + break; + default: + $rule = ''; + break; + } + + if (!empty($rule)) { + $casts[] = $rule; + } + } + + return $casts; + } + + private function generateRelations() + { + $relations = []; + + $count = 1; + $fieldsArr = []; + foreach ($this->commandData->relations as $relation) { + $field = (isset($relation->inputs[0])) ? $relation->inputs[0] : null; + + $relationShipText = $field; + if (in_array($field, $fieldsArr)) { + $relationShipText = $relationShipText.'_'.$count; + $count++; + } + + $relationText = $relation->getRelationFunctionText($relationShipText); + if (!empty($relationText)) { + $fieldsArr[] = $field; + $relations[] = $relationText; + } + } + + return $relations; + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + $this->commandData->commandComment('Model file deleted: '.$this->fileName); + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/ControllerLogicGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/ControllerLogicGenerator.php new file mode 100644 index 00000000..dd10bf31 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/ControllerLogicGenerator.php @@ -0,0 +1,83 @@ +commandData = $commandData; + $this->path = app_path('Classes/Modules/'. str::pluralStudly($this->commandData->modelName).'/ControllersLogic/'); + } + + public function generate() + { + + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.$name).'Logic.php'; + + $templateData = $this->generatorHelpers->get_template("Scaffold.ControllersLogic.".$type."_controller_logic"); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace( + '$REQUEST_FIELDS$', + implode(', ', $this->generateFields()), + $templateData + ); + + + FileUtil::createFile($this->path, $filename, $templateData); + + $this->commandData->commandComment("\n" . $type . " Controller logic created: "); + $this->commandData->commandInfo($filename); + } + + } + + private function generateFields(){ + $fields = []; + + foreach ($this->commandData->fields as $field) { + if(!in_array($field->name, $this->commandData->config->excludeFields())) { + $fields[] = '$request->input(\'' . $field->name . '\')'; + } + } + + return $fields; + } + + public function rollback() + { + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.$name).'Logic.php'; + + if ($this->rollbackFile($this->path, $filename)) { + $this->commandData->commandComment($type . ' Controller logic file deleted: '.$filename); + } + } + + File::deleteDirectory($this->path); + + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/ControllersGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/ControllersGenerator.php new file mode 100644 index 00000000..c651a39d --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/ControllersGenerator.php @@ -0,0 +1,64 @@ +commandData = $commandData; + $this->path = $commandData->config->pathController.'/'.str::pluralStudly($this->commandData->modelName).'/'; + } + + public function generate() + { + + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.$name).'Controller.php'; + + $templateData = $this->generatorHelpers->get_template("Scaffold.Controllers.".$type."_controller"); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + FileUtil::createFile($this->path, $filename, $templateData); + + $this->commandData->commandComment("\n" . $type . " Controller created: "); + $this->commandData->commandInfo($filename); + } + + } + + public function rollback() + { + foreach(['create', 'list', 'fetch', 'update', 'delete'] as $type){ + + $name = $type === 'list' ? str::pluralStudly($this->commandData->modelName) : str::singular($this->commandData->modelName); + $filename = str::studly($type.$name).'Controller.php'; + + if ($this->rollbackFile($this->path, $filename)) { + $this->commandData->commandComment($type . ' Controller file deleted: '.$filename); + } + } + + File::deleteDirectory($this->path); + + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/RoutesGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/RoutesGenerator.php new file mode 100644 index 00000000..33daa971 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/RoutesGenerator.php @@ -0,0 +1,55 @@ +commandData = $commandData; + $this->path = base_path('routes/crud.php');; + $this->routeContents = file_get_contents($this->path); + $this->routesTemplate = $this->generatorHelpers->get_template('Routes.route'); + $this->routesTemplate = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $this->routesTemplate); + } + + public function generate() + { + if (Str::contains($this->routeContents, "Route::group(['prefix' => '".$this->commandData->config->mSnake."',")) { + $this->commandData->commandObj->info('Routes for '.$this->commandData->config->mName.' already exists, Skipping Adjustment.'); + + return; + } + + file_put_contents($this->path, $this->routeContents.$this->routesTemplate); + $this->commandData->commandComment("\n".$this->commandData->config->mName.' routes added.'); + } + + public function rollback() + { + if (Str::contains($this->routeContents, $this->routesTemplate)) { + $this->routeContents = str_replace($this->routesTemplate, '', $this->routeContents); + file_put_contents($this->path, $this->routeContents); + $this->commandData->commandComment('Routes deleted'); + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/ViewsGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/ViewsGenerator.php new file mode 100644 index 00000000..bac5b4a1 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/ViewsGenerator.php @@ -0,0 +1,53 @@ +commandData = $commandData; + $this->path = resource_path('views/pages/'.str::plural(str::snake($this->commandData->modelName)).'/'); + $this->fileName = 'index.blade.php'; + } + + public function generate() + { + + $templateData = $this->generatorHelpers->get_template("Views.view"); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\nView created: "); + $this->commandData->commandInfo($this->fileName); + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + $this->commandData->commandComment('View file deleted: '.$this->fileName); + File::deleteDirectory($this->path); + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/VueGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/VueGenerator.php new file mode 100644 index 00000000..0d700371 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/VueGenerator.php @@ -0,0 +1,196 @@ +commandData = $commandData; + $this->path = resource_path('assets/vue/components/'.str::camel($this->commandData->modelName).'/'); + + } + + public function generate() + { + + $fields = []; + $i = 1; + foreach ($this->commandData->fields as $index => $field) { + if (!$field->inIndex) { + continue; + } + + $fieldTemplate = $this->generatorHelpers->get_template("Views.column"); + $fieldTemplate = str_replace('$FIRST_COLUMN_CLASS$', $i === 1 ? 'ist-item-heading truncate' : 'text-small', $fieldTemplate); + $fieldTemplate = str_replace('$COLUMN_SIZE$', $i === 1 ? 'col-3' : 'col', $fieldTemplate); + $fieldTemplate = $this->generatorHelpers->fill_template_with_field_data( + $this->commandData->dynamicVars, + $this->commandData->fieldNamesMapping, + $fieldTemplate, + $field + ); + + $fields[] = $fieldTemplate; + + $i++; + + } + $templateData = $this->generatorHelpers->get_template("VueJs.element_component"); + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + $templateData = str_replace('$FIELD_BODY$', implode($this->generatorHelpers->generator_nl_tab(1, 0), $fields), $templateData); + $fileName = $this->commandData->modelName.'Component.vue'; + FileUtil::createFile($this->path.'elements/', $fileName, $templateData); + + $this->commandData->commandComment("\nvue element created: "); + $this->commandData->commandInfo($fileName); + + $this->generateForm(); + $this->generateFilterForm(); + } + + private function generateForm() + { + + $this->htmlFields = []; + $formFields = []; + $validations = []; + + foreach ($this->commandData->fields as $field) { + if (!$field->inForm) { + continue; + } + + $formFields[] = $field->name.": ''"; + + $validations[] = $field->name . ": { " . implode(', ', explode('|', $field->validations)) ." }"; + + $fieldTemplate = $this->generatorHelpers->get_template('Fields.field'); + + $fieldInputTemplate = HTMLFieldGenerator::generateHTML($field); + + if($field->htmlType === 'selectTable'){ + $fieldTemplate = str_replace('$v.parameters.$FIELD_NAME$', '$v.parameters.'.$field->name, $fieldTemplate); + $fieldTemplate = str_replace('$FIELD_NAME$', Str::replaceLast('_id', '', $field->name), $fieldTemplate); + } + + $fieldTemplate = str_replace('$FIELD$', $fieldInputTemplate, $fieldTemplate); + + + if (!empty($fieldTemplate)) { + $fieldTemplate = $this->generatorHelpers->fill_template_with_field_data( + $this->commandData->dynamicVars, + $this->commandData->fieldNamesMapping, + $fieldTemplate, + $field + ); + + $this->htmlFields[] = $fieldTemplate; + } + } + + $templateData = $this->generatorHelpers->get_template('VueJs.form_component'); + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace('$FIELDS$', implode("\n", $this->htmlFields), $templateData); + $templateData = str_replace('$REQUEST_FIELDS$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 5), $formFields), $templateData); + $templateData = str_replace('$VALIDATION$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 4), $validations), $templateData); + + FileUtil::createFile($this->path.'forms/', $this->commandData->modelName.'FormComponent.vue', $templateData); + $this->commandData->commandComment("\nvue form created: "); + $this->commandData->commandInfo($this->commandData->modelName.'FormComponent.vue'); + } + + private function generateFilterForm() + { + + $filterFields = []; + $filterMap = []; + + foreach ($this->commandData->fields as $field) { + if (!$field->isSearchable) { + continue; + } + + + $filterMap[] = $field->name.": ''"; + + $fieldTemplate = $this->generatorHelpers->get_template('Fields.filter_field'); + + $fieldInputTemplate = HTMLFieldGenerator::generateHTML($field); + + if($field->htmlType === 'selectTable'){ + $fieldTemplate = str_replace('$v.parameters.$FIELD_NAME$', '$v.parameters.'.$field->name, $fieldTemplate); + $fieldTemplate = str_replace('$FIELD_NAME$', Str::replaceLast('_id', '', $field->name), $fieldTemplate); + } + + $fieldTemplate = str_replace('$FIELD$', $fieldInputTemplate, $fieldTemplate); + + + if (!empty($fieldTemplate)) { + $fieldTemplate = $this->generatorHelpers->fill_template_with_field_data( + $this->commandData->dynamicVars, + $this->commandData->fieldNamesMapping, + $fieldTemplate, + $field + ); + + $filterFields[] = $fieldTemplate; + } + } + + $templateData = $this->generatorHelpers->get_template('VueJs.filter_component'); + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + $templateData = str_replace('$FIELDS$', implode("\n", $filterFields), $templateData); + $templateData = str_replace('$REQUEST_FIELDS$', implode(','.$this->generatorHelpers->generator_nl_tab(1, 5), $filterMap), $templateData); + + FileUtil::createFile($this->path.'forms/', $this->commandData->modelName.'FiltersComponent.vue', $templateData); + $this->commandData->commandComment("\nvue filter created: "); + $this->commandData->commandInfo($this->commandData->modelName.'FiltersComponent.vue'); + } + + + + public function rollback() + { + foreach(['elements', 'forms'] as $folderType){ + if($folderType === 'elements'){ + if ($this->rollbackFile($this->path.$folderType.'/', $this->commandData->modelName.'Component.vue')) { + $this->commandData->commandComment('Vue element file deleted: '.$this->commandData->modelName.'Component.vue'); + } + } else { + foreach(['form', 'filter'] as $type){ + if ($this->rollbackFile($this->path.$folderType.'/', $this->commandData->modelName.str::studly($type).'Component.vue')) { + $this->commandData->commandComment('Vue '.$type.' file deleted: '.$this->commandData->modelName.str::studly($type).'Component.vue'); + } + } + + } + File::deleteDirectory($this->path.$folderType.'/'); + } + + File::deleteDirectory($this->path); + } +} diff --git a/app/Classes/CodeGenerator/Generators/Scaffold/WebRouteGenerator.php b/app/Classes/CodeGenerator/Generators/Scaffold/WebRouteGenerator.php new file mode 100644 index 00000000..e32fd4d6 --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/Scaffold/WebRouteGenerator.php @@ -0,0 +1,55 @@ +commandData = $commandData; + $this->path = base_path('routes/web.php');; + $this->routeContents = file_get_contents($this->path); + $this->routesTemplate = $this->generatorHelpers->get_template('Routes.web'); + $this->routesTemplate = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $this->routesTemplate); + } + + public function generate() + { + if (Str::contains($this->routeContents, "Route::get('/".$this->commandData->config->mSnakePlural."'")) { + $this->commandData->commandObj->info('Web route for '.$this->commandData->config->mName.' already exists, Skipping Adjustment.'); + + return; + } + + file_put_contents($this->path, $this->routeContents.$this->routesTemplate); + $this->commandData->commandComment("\n".$this->commandData->config->mName.' web route added.'); + } + + public function rollback() + { + if (Str::contains($this->routeContents, $this->routesTemplate)) { + $this->routeContents = str_replace($this->routesTemplate, '', $this->routeContents); + file_put_contents($this->path, $this->routeContents); + $this->commandData->commandComment('web route deleted'); + } + } +} diff --git a/app/Classes/CodeGenerator/Generators/SeederGenerator.php b/app/Classes/CodeGenerator/Generators/SeederGenerator.php new file mode 100644 index 00000000..9161ea0f --- /dev/null +++ b/app/Classes/CodeGenerator/Generators/SeederGenerator.php @@ -0,0 +1,86 @@ +commandData = $commandData; + $this->path = $commandData->config->pathSeeder; + $this->fileName = Str::studly($this->commandData->config->mPlural).'TableSeeder.php'; + } + + public function generate() + { + $templateData = $this->generatorHelpers->get_template('Seeds.model_seeder'); + + $templateData = $this->generatorHelpers->fill_template($this->commandData->dynamicVars, $templateData); + + FileUtil::createFile($this->path, $this->fileName, $templateData); + + $this->commandData->commandComment("\nSeeder created: "); + $this->commandData->commandInfo($this->fileName); + } + + public function updateMainSeeder() + { + $mainSeederContent = file_get_contents($this->commandData->config->pathDatabaseSeeder); + + $newSeederStatement = '$this->call('.$this->commandData->config->mPlural.'TableSeeder::class);'; + + if (strpos($mainSeederContent, $newSeederStatement) != false) { + $this->commandData->commandObj->info($this->commandData->config->mPlural.'TableSeeder entry found in DatabaseSeeder. Skipping Adjustment.'); + + return; + } + + $newSeederStatement = $this->generatorHelpers->generator_tabs(2).$newSeederStatement.$this->generatorHelpers->generator_nl(); + + preg_match_all('/\\$this->call\\((.*);/', $mainSeederContent, $matches); + + $totalMatches = count($matches[0]); + $lastSeederStatement = $matches[0][$totalMatches - 1]; + + $replacePosition = strpos($mainSeederContent, $lastSeederStatement); + + $mainSeederContent = substr_replace($mainSeederContent, $newSeederStatement, $replacePosition + strlen($lastSeederStatement) + 1, 0); + + file_put_contents($this->commandData->config->pathDatabaseSeeder, $mainSeederContent); + $this->commandData->commandComment('Main Seeder file updated.'); + } + + public function rollback() + { + if ($this->rollbackFile($this->path, $this->fileName)) { + $this->commandData->commandComment('Seeder file deleted: '.$this->fileName); + } + + $mainSeederContent = file_get_contents($this->commandData->config->pathDatabaseSeeder); + $mainSeederContent = str_replace('$this->call('.$this->commandData->config->mPlural.'TableSeeder::class);', '', $mainSeederContent); + file_put_contents($this->commandData->config->pathDatabaseSeeder, $mainSeederContent); + $this->commandData->commandComment('Main Seeder file updated.'); + + } +} diff --git a/app/Classes/CodeGenerator/Schemas/addresses.json b/app/Classes/CodeGenerator/Schemas/addresses.json new file mode 100644 index 00000000..138889e2 --- /dev/null +++ b/app/Classes/CodeGenerator/Schemas/addresses.json @@ -0,0 +1,102 @@ +[ + { + "name": "company_id", + "dbType": "foreignId:foreign,companies,id", + "htmlType": "selectTable:companies:name,id", + "validations": "required", + "searchable": true, + "fillable": false, + "primary": false, + "inForm": false, + "inIndex": true, + "relation": "1t1,Company,company_id,id" + }, + { + "name": "street_one", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "street_two", + "dbType": "string:nullable", + "htmlType": "text", + "validations": "", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "city", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "state", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "post_code", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "country", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "default", + "dbType": "integer", + "htmlType": "number", + "validations": "required", + "searchable": false, + "fillable": false, + "primary": false, + "inForm": false, + "inIndex": false + }, + { + "name": "billing", + "dbType": "integer", + "htmlType": "number", + "validations": "required", + "searchable": false, + "fillable": false, + "primary": false, + "inForm": false, + "inIndex": false + } +] diff --git a/app/Classes/CodeGenerator/Schemas/companies.json b/app/Classes/CodeGenerator/Schemas/companies.json new file mode 100644 index 00000000..53a80132 --- /dev/null +++ b/app/Classes/CodeGenerator/Schemas/companies.json @@ -0,0 +1,35 @@ +[ + { + "name": "reference_no", + "dbType": "integer:unique", + "htmlType": "number", + "validations": "required", + "searchable": true, + "fillable": false, + "primary": false, + "inForm": false, + "inIndex": true + }, + { + "name": "name", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": true, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "type", + "dbType": "integer", + "htmlType": "number", + "validations": "required", + "searchable": true, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + } +] diff --git a/app/Classes/CodeGenerator/Schemas/contacts.json b/app/Classes/CodeGenerator/Schemas/contacts.json new file mode 100644 index 00000000..7b8cf0fc --- /dev/null +++ b/app/Classes/CodeGenerator/Schemas/contacts.json @@ -0,0 +1,70 @@ +[ + { + "name": "company_id", + "dbType": "foreignId:foreign,companies,id", + "htmlType": "selectTable:companies:name,id", + "validations": "required", + "searchable": true, + "fillable": false, + "primary": false, + "inForm": false, + "inIndex": true, + "relation": "1t1,Company,company_id,id" + }, + { + "name": "name", + "dbType": "string", + "htmlType": "text", + "validations": "required", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "designation", + "dbType": "string:nullable", + "htmlType": "text", + "validations": "", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "email", + "dbType": "string:nullable", + "htmlType": "text", + "validations": "", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + } +, + { + "name": "phone", + "dbType": "string:nullable", + "htmlType": "text", + "validations": "", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + }, + { + "name": "wechat_id", + "dbType": "string:nullable", + "htmlType": "text", + "validations": "", + "searchable": false, + "fillable": true, + "primary": false, + "inForm": true, + "inIndex": true + } +] diff --git a/app/Classes/CodeGenerator/Stubs/Docs/model.stub b/app/Classes/CodeGenerator/Stubs/Docs/model.stub new file mode 100644 index 00000000..31e51baa --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Docs/model.stub @@ -0,0 +1,6 @@ +/** + * Class $MODEL_NAME$ + * @package $NAMESPACE_MODEL$ + * @version $GENERATE_DATE$ + * +$PHPDOC$ */ \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Factories/model_factory.stub b/app/Classes/CodeGenerator/Stubs/Factories/model_factory.stub new file mode 100644 index 00000000..94781477 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Factories/model_factory.stub @@ -0,0 +1,12 @@ +define($NAMESPACE_MODEL$\$MODEL_NAME$::class, function (Faker $faker) { + + return [ + $FIELDS$ + ]; +}); diff --git a/app/Classes/CodeGenerator/Stubs/Fields/date.stub b/app/Classes/CodeGenerator/Stubs/Fields/date.stub new file mode 100644 index 00000000..8e7cfd97 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/date.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/email.stub b/app/Classes/CodeGenerator/Stubs/Fields/email.stub new file mode 100644 index 00000000..92b3624f --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/email.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/field.stub b/app/Classes/CodeGenerator/Stubs/Fields/field.stub new file mode 100644 index 00000000..cc689126 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/field.stub @@ -0,0 +1,8 @@ +
+
+ + $FIELD$ + $FIELD_NAME$ + +
+
\ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/filter_field.stub b/app/Classes/CodeGenerator/Stubs/Fields/filter_field.stub new file mode 100644 index 00000000..7cd638ae --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/filter_field.stub @@ -0,0 +1,8 @@ +
+
+ +
+
\ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/password.stub b/app/Classes/CodeGenerator/Stubs/Fields/password.stub new file mode 100644 index 00000000..28078be1 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/password.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/select.stub b/app/Classes/CodeGenerator/Stubs/Fields/select.stub new file mode 100644 index 00000000..801cdf99 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/select.stub @@ -0,0 +1 @@ + diff --git a/app/Classes/CodeGenerator/Stubs/Fields/selectable.stub b/app/Classes/CodeGenerator/Stubs/Fields/selectable.stub new file mode 100644 index 00000000..72336cd7 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/selectable.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/text.stub b/app/Classes/CodeGenerator/Stubs/Fields/text.stub new file mode 100644 index 00000000..49643385 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/text.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Fields/textarea.stub b/app/Classes/CodeGenerator/Stubs/Fields/textarea.stub new file mode 100644 index 00000000..6475c6bf --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Fields/textarea.stub @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Micros/data_transfer_object.stub b/app/Classes/CodeGenerator/Stubs/Micros/data_transfer_object.stub new file mode 100644 index 00000000..1ac0c061 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Micros/data_transfer_object.stub @@ -0,0 +1,24 @@ +$FIELD_NAME$; + } diff --git a/app/Classes/CodeGenerator/Stubs/Migration/migration.stub b/app/Classes/CodeGenerator/Stubs/Migration/migration.stub new file mode 100644 index 00000000..c1cbd22d --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Migration/migration.stub @@ -0,0 +1,31 @@ +$RELATION$(\$NAMESPACE_MODEL$\$RELATION_MODEL_NAME$::class$INPUT_FIELDS$); + } \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Resource/model_resource.stub b/app/Classes/CodeGenerator/Stubs/Resource/model_resource.stub new file mode 100644 index 00000000..53dfa039 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Resource/model_resource.stub @@ -0,0 +1,22 @@ + $this->id, + $FIELDS$ + ]; + } +} diff --git a/app/Classes/CodeGenerator/Stubs/Routes/route.stub b/app/Classes/CodeGenerator/Stubs/Routes/route.stub new file mode 100644 index 00000000..dfdc67f2 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Routes/route.stub @@ -0,0 +1,15 @@ + + +Route::group(['prefix' => '$MODEL_NAME_SNAKE$', 'as' => '$MODEL_NAME_SNAKE$.', 'namespace' => '$MODEL_NAME_PLURAL$'], function () { + + Route::get('/{id}/show', 'Fetch$MODEL_NAME$Controller@fetch')->name('show'); + + Route::get('/list', 'List$MODEL_NAME_PLURAL$Controller@list')->name('list'); + + Route::post('/create', 'Create$MODEL_NAME$Controller@create')->name('create'); + + Route::put('/update/{id}', 'Update$MODEL_NAME$Controller@update')->name('update'); + + Route::delete('/delete/{id}', 'Delete$MODEL_NAME$Controller@destroy')->name('delete'); + +}); \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Routes/web.stub b/app/Classes/CodeGenerator/Stubs/Routes/web.stub new file mode 100644 index 00000000..bc77836a --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Routes/web.stub @@ -0,0 +1,5 @@ + + +Route::get('/$MODEL_NAME_PLURAL_SNAKE$', function () { + return view('pages.$MODEL_NAME_PLURAL_SNAKE$.index'); +})->name('$MODEL_NAME_SNAKE$.dashboard'); \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Rules/can_create.stub b/app/Classes/CodeGenerator/Stubs/Rules/can_create.stub new file mode 100644 index 00000000..7d25d53d --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Rules/can_create.stub @@ -0,0 +1,57 @@ +$MODEL_NAME_CAMEL$Validation = $$MODEL_NAME_CAMEL$Validation; + } + + + /** + * @return bool + */ + protected function authorized(): bool + { + // TODO Set Authorization rules + return true; + + } + + /** + * @param $MODEL_NAME$Object $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->$MODEL_NAME_CAMEL$Validation->validate($object); + + } + + + /** + * @param $MODEL_NAME$Object $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Rules/can_delete.stub b/app/Classes/CodeGenerator/Stubs/Rules/can_delete.stub new file mode 100644 index 00000000..234ff8d2 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Rules/can_delete.stub @@ -0,0 +1,43 @@ +$MODEL_NAME_CAMEL$Validation = $$MODEL_NAME_CAMEL$Validation; + } + + + /** + * @return bool + */ + protected function authorized(): bool + { + // TODO Set Authorization rules + return true; + + } + + /** + * @param $MODEL_NAME$Object $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->$MODEL_NAME_CAMEL$Validation->validate($object); + + } + + + /** + * @param $MODEL_NAME$Object $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/create_controller.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/create_controller.stub new file mode 100644 index 00000000..50336e91 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/create_controller.stub @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/delete_controller.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/delete_controller.stub new file mode 100644 index 00000000..adaea8cb --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/delete_controller.stub @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/fetch_controller.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/fetch_controller.stub new file mode 100644 index 00000000..a88e2c9e --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/fetch_controller.stub @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/list_controller.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/list_controller.stub new file mode 100644 index 00000000..db3dd7dc --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/list_controller.stub @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/update_controller.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/update_controller.stub new file mode 100644 index 00000000..28629ddf --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/Controllers/update_controller.stub @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/create_controller_logic.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/create_controller_logic.stub new file mode 100644 index 00000000..36042f20 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/create_controller_logic.stub @@ -0,0 +1,69 @@ + 'Created $MODEL_NAME_HUMAN$', + 'message' => 'You have successfully created a new $MODEL_NAME_HUMAN$' + ]; + } + + /** @var CanCreate$MODEL_NAME$ */ + private $canCreate$MODEL_NAME$; + + /** @var Creates$MODEL_NAME$ */ + private $creates$MODEL_NAME$; + + /** + * Create$MODEL_NAME$ControllerLogic constructor. + * @param CanCreate$MODEL_NAME$ $canCreate$MODEL_NAME$ + * @param Creates$MODEL_NAME$ $creates$MODEL_NAME$ + */ + public function __construct(CanCreate$MODEL_NAME$ $canCreate$MODEL_NAME$, Creates$MODEL_NAME$ $creates$MODEL_NAME$) + { + $this->canCreate$MODEL_NAME$ = $canCreate$MODEL_NAME$; + $this->creates$MODEL_NAME$ = $creates$MODEL_NAME$; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + try { + + $object = new $MODEL_NAME$Object($REQUEST_FIELDS$); + + $this->canCreate$MODEL_NAME$->passes($object); + + $query = $this->creates$MODEL_NAME$->execute($object); + + return $this->resourceResponse(new $MODEL_NAME$Resource($query)); + + } catch (\Exception $exception){ + throw new ErrorException($exception->getMessage(), $exception->getCode()); + } + + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/delete_controller_logic.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/delete_controller_logic.stub new file mode 100644 index 00000000..ddc6c1f6 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/delete_controller_logic.stub @@ -0,0 +1,73 @@ + 'Deleted $MODEL_NAME_HUMAN$', + 'message' => 'You have successfully deleted a $MODEL_NAME_HUMAN$' + ]; + } + + + /** @var CanDelete$MODEL_NAME$ */ + private $canDelete$MODEL_NAME$; + + /** @var Deletes$MODEL_NAME$ */ + private $deletes$MODEL_NAME$; + + /** @var Fetches$MODEL_NAME$ */ + private $fetches$MODEL_NAME$; + + /** + * Delete$MODEL_NAME$ControllerLogic constructor. + * @param CanDelete$MODEL_NAME$ $canDelete$MODEL_NAME$ + * @param Deletes$MODEL_NAME$ $deletes$MODEL_NAME$ + * @param Fetches$MODEL_NAME$ $fetches$MODEL_NAME$ + */ + public function __construct(CanDelete$MODEL_NAME$ $canDelete$MODEL_NAME$, Deletes$MODEL_NAME$ $deletes$MODEL_NAME$, Fetches$MODEL_NAME$ $fetches$MODEL_NAME$) + { + $this->canDelete$MODEL_NAME$ = $canDelete$MODEL_NAME$; + $this->deletes$MODEL_NAME$ = $deletes$MODEL_NAME$; + $this->fetches$MODEL_NAME$ = $fetches$MODEL_NAME$; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + try { + + $this->canDelete$MODEL_NAME$->passes(); + + $query = $this->fetches$MODEL_NAME$->execute(['id' => $request->route('id')]); + + $this->deletes$MODEL_NAME$->execute($query); + + return $this->response([]); + + } catch (\Exception $exception){ + throw new ErrorException($exception->getMessage(), $exception->getCode()); + } + + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/fetch_controller_logic.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/fetch_controller_logic.stub new file mode 100644 index 00000000..dc4977e4 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/fetch_controller_logic.stub @@ -0,0 +1,67 @@ + 'Retrieved $MODEL_NAME_HUMAN$', + 'message' => 'You have successfully retrieved a $MODEL_NAME_HUMAN$' + ]; + } + + /** @var CanFetch$MODEL_NAME$ */ + private $canFetch$MODEL_NAME$; + + /** @var Fetches$MODEL_NAME$ */ + private $fetches$MODEL_NAME$; + + /** + * Fetch$MODEL_NAME$ControllerLogic constructor. + * @param CanFetch$MODEL_NAME$ $canFetch$MODEL_NAME$ + * @param Fetches$MODEL_NAME$ $fetches$MODEL_NAME$ + */ + public function __construct(CanFetch$MODEL_NAME$ $canFetch$MODEL_NAME$, Fetches$MODEL_NAME$ $fetches$MODEL_NAME$) + { + $this->canFetch$MODEL_NAME$ = $canFetch$MODEL_NAME$; + $this->fetches$MODEL_NAME$ = $fetches$MODEL_NAME$; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + try { + + $this->canFetch$MODEL_NAME$->passes(); + + $query = $this->fetches$MODEL_NAME$->execute(['id' => $request->route('id')]); + + return $this->resourceResponse(new $MODEL_NAME$Resource($query)); + + } catch (\Exception $exception){ + throw new ErrorException($exception->getMessage(), $exception->getCode()); + } + + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/list_controller_logic.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/list_controller_logic.stub new file mode 100644 index 00000000..d2ff7b30 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/list_controller_logic.stub @@ -0,0 +1,66 @@ + 'Retrieved $MODEL_NAME_PLURAL_HUMAN$', + 'message' => 'You have successfully retrieved a list of $MODEL_NAME_PLURAL_HUMAN$' + ]; + } + + /** @var CanList$MODEL_NAME_PLURAL$ */ + private $canList$MODEL_NAME_PLURAL$; + + /** @var Lists$MODEL_NAME_PLURAL$ */ + private $lists$MODEL_NAME_PLURAL$; + + /** + * List$MODEL_NAME_PLURAL$ControllerLogic constructor. + * @param CanList$MODEL_NAME_PLURAL$ $canList$MODEL_NAME_PLURAL$ + * @param Lists$MODEL_NAME_PLURAL$ $lists$MODEL_NAME_PLURAL$ + */ + public function __construct(CanList$MODEL_NAME_PLURAL$ $canList$MODEL_NAME_PLURAL$, Lists$MODEL_NAME_PLURAL$ $lists$MODEL_NAME_PLURAL$) + { + $this->canList$MODEL_NAME_PLURAL$ = $canList$MODEL_NAME_PLURAL$; + $this->lists$MODEL_NAME_PLURAL$ = $lists$MODEL_NAME_PLURAL$; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + try { + + $this->canList$MODEL_NAME_PLURAL$->passes(); + + $query = $this->lists$MODEL_NAME_PLURAL$->execute($this->lists$MODEL_NAME_PLURAL$->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse($MODEL_NAME$Resource::collection($query)); + + } catch (\Exception $exception){ + throw new ErrorException($exception->getMessage(), $exception->getCode()); + } + + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/update_controller_logic.stub b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/update_controller_logic.stub new file mode 100644 index 00000000..3a831722 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Scaffold/ControllersLogic/update_controller_logic.stub @@ -0,0 +1,78 @@ + 'Updated $MODEL_NAME_HUMAN$', + 'message' => 'You have successfully updated the $MODEL_NAME_HUMAN$' + ]; + } + + /** @var CanUpdate$MODEL_NAME$ */ + private $canUpdate$MODEL_NAME$; + + /** @var Updates$MODEL_NAME$ */ + private $updates$MODEL_NAME$; + + /** @var Fetches$MODEL_NAME$ */ + private $fetches$MODEL_NAME$; + + /** + * Update$MODEL_NAME$ControllerLogic constructor. + * @param CanUpdate$MODEL_NAME$ $canUpdate$MODEL_NAME$ + * @param Updates$MODEL_NAME$ $updates$MODEL_NAME$ + * @param Fetches$MODEL_NAME$ $fetches$MODEL_NAME$ + */ + public function __construct(CanUpdate$MODEL_NAME$ $canUpdate$MODEL_NAME$, Updates$MODEL_NAME$ $updates$MODEL_NAME$, Fetches$MODEL_NAME$ $fetches$MODEL_NAME$) + { + $this->canUpdate$MODEL_NAME$ = $canUpdate$MODEL_NAME$; + $this->updates$MODEL_NAME$ = $updates$MODEL_NAME$; + $this->fetches$MODEL_NAME$ = $fetches$MODEL_NAME$; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + try { + + $object = new $MODEL_NAME$Object($REQUEST_FIELDS$); + + $this->canUpdate$MODEL_NAME$->passes($object); + + $query = $this->fetches$MODEL_NAME$->execute(['id' => $request->route('id')]); + + $query = $this->updates$MODEL_NAME$->execute($query, $object); + + return $this->resourceResponse(new $MODEL_NAME$Resource($query)); + + + } catch (\Exception $exception){ + throw new ErrorException($exception->getMessage(), $exception->getCode()); + } + + } + +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Seeds/model_seeder.stub b/app/Classes/CodeGenerator/Stubs/Seeds/model_seeder.stub new file mode 100644 index 00000000..f4aa75d3 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Seeds/model_seeder.stub @@ -0,0 +1,16 @@ +create(); + } +} diff --git a/app/Classes/CodeGenerator/Stubs/Services/create_service.stub b/app/Classes/CodeGenerator/Stubs/Services/create_service.stub new file mode 100644 index 00000000..e4dee8c7 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Services/create_service.stub @@ -0,0 +1,19 @@ +handler($model); + + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Services/delete_service.stub b/app/Classes/CodeGenerator/Stubs/Services/delete_service.stub new file mode 100644 index 00000000..a2b3a2a0 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Services/delete_service.stub @@ -0,0 +1,15 @@ +handler($model); + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Services/fetch_service.stub b/app/Classes/CodeGenerator/Stubs/Services/fetch_service.stub new file mode 100644 index 00000000..bd951400 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Services/fetch_service.stub @@ -0,0 +1,33 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Services/list_service.stub b/app/Classes/CodeGenerator/Stubs/Services/list_service.stub new file mode 100644 index 00000000..36a72e12 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Services/list_service.stub @@ -0,0 +1,33 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Services/update_service.stub b/app/Classes/CodeGenerator/Stubs/Services/update_service.stub new file mode 100644 index 00000000..9460c608 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Services/update_service.stub @@ -0,0 +1,19 @@ +handler($model); + + } +} \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Validator/request_validation.stub b/app/Classes/CodeGenerator/Stubs/Validator/request_validation.stub new file mode 100644 index 00000000..cee7a46c --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Validator/request_validation.stub @@ -0,0 +1,39 @@ + +
+
+
+ $FIELD_NAME$ +
+
+
+
+
+
+ {{$MODEL_NAME_CAMEL$.$FIELD_NAME$}} +
+
+
+ \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/Views/view.stub b/app/Classes/CodeGenerator/Stubs/Views/view.stub new file mode 100644 index 00000000..a5da7a2c --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/Views/view.stub @@ -0,0 +1,31 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
+
+

$MODEL_NAME_PLURAL_HUMAN$

+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + <$MODEL_NAME_DASHED$-filters-component section="$MODEL_NAME_CAMEL$Section"> +@endsection \ No newline at end of file diff --git a/app/Classes/CodeGenerator/Stubs/VueJs/element_component.stub b/app/Classes/CodeGenerator/Stubs/VueJs/element_component.stub new file mode 100644 index 00000000..6fffd407 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/VueJs/element_component.stub @@ -0,0 +1,41 @@ + + diff --git a/app/Classes/CodeGenerator/Stubs/VueJs/filter_component.stub b/app/Classes/CodeGenerator/Stubs/VueJs/filter_component.stub new file mode 100644 index 00000000..41aa3cc9 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/VueJs/filter_component.stub @@ -0,0 +1,49 @@ + + diff --git a/app/Classes/CodeGenerator/Stubs/VueJs/form_component.stub b/app/Classes/CodeGenerator/Stubs/VueJs/form_component.stub new file mode 100644 index 00000000..2b9e5668 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/VueJs/form_component.stub @@ -0,0 +1,63 @@ + + diff --git a/app/Classes/CodeGenerator/Stubs/base_repository.stub b/app/Classes/CodeGenerator/Stubs/base_repository.stub new file mode 100644 index 00000000..cc17ad67 --- /dev/null +++ b/app/Classes/CodeGenerator/Stubs/base_repository.stub @@ -0,0 +1,193 @@ +app = $app; + $this->makeModel(); + } + + /** + * Get searchable fields array + * + * @return array + */ + abstract public function getFieldsSearchable(); + + /** + * Configure the Model + * + * @return string + */ + abstract public function model(); + + /** + * Make Model instance + * + * @throws \Exception + * + * @return Model + */ + public function makeModel() + { + $model = $this->app->make($this->model()); + + if (!$model instanceof Model) { + throw new \Exception("Class {$this->model()} must be an instance of Illuminate\\Database\\Eloquent\\Model"); + } + + return $this->model = $model; + } + + /** + * Paginate records for scaffold. + * + * @param int $perPage + * @param array $columns + * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + */ + public function paginate($perPage, $columns = ['*']) + { + $query = $this->allQuery(); + + return $query->paginate($perPage, $columns); + } + + /** + * Build a query for retrieving all records. + * + * @param array $search + * @param int|null $skip + * @param int|null $limit + * @return \Illuminate\Database\Eloquent\Builder + */ + public function allQuery($search = [], $skip = null, $limit = null) + { + $query = $this->model->newQuery(); + + if (count($search)) { + foreach($search as $key => $value) { + if (in_array($key, $this->getFieldsSearchable())) { + $query->where($key, $value); + } + } + } + + if (!is_null($skip)) { + $query->skip($skip); + } + + if (!is_null($limit)) { + $query->limit($limit); + } + + return $query; + } + + /** + * Retrieve all records with given filter criteria + * + * @param array $search + * @param int|null $skip + * @param int|null $limit + * @param array $columns + * + * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection + */ + public function all($search = [], $skip = null, $limit = null, $columns = ['*']) + { + $query = $this->allQuery($search, $skip, $limit); + + return $query->get($columns); + } + + /** + * Create model record + * + * @param array $input + * + * @return Model + */ + public function create($input) + { + $model = $this->model->newInstance($input); + + $model->save(); + + return $model; + } + + /** + * Find model record for given id + * + * @param int $id + * @param array $columns + * + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|Model|null + */ + public function find($id, $columns = ['*']) + { + $query = $this->model->newQuery(); + + return $query->find($id, $columns); + } + + /** + * Update model record for given id + * + * @param array $input + * @param int $id + * + * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|Model + */ + public function update($input, $id) + { + $query = $this->model->newQuery(); + + $model = $query->findOrFail($id); + + $model->fill($input); + + $model->save(); + + return $model; + } + + /** + * @param int $id + * + * @throws \Exception + * + * @return bool|mixed|null + */ + public function delete($id) + { + $query = $this->model->newQuery(); + + $model = $query->findOrFail($id); + + return $model->delete(); + } +} diff --git a/app/Classes/CodeGenerator/Utils/FileUtil.php b/app/Classes/CodeGenerator/Utils/FileUtil.php new file mode 100644 index 00000000..a5b31b93 --- /dev/null +++ b/app/Classes/CodeGenerator/Utils/FileUtil.php @@ -0,0 +1,37 @@ + db_type html_type(optional) options(optional) + * Options are to skip the field from certain criteria like searchable, fillable, not in form, not in index + * Searchable (s), Fillable (f), In Form (if), In Index (ii) + * Sample Field Inputs + * + * title string text + * body text textarea + * name string,20 text + * post_id integer:unsigned:nullable + * post_id integer:unsigned:nullable:foreign,posts,id + * password string text if,ii,s - options will skip field from being added in form, in index and searchable + */ + + $fieldInputsArr = explode(' ', $fieldInput); + + $field = new GeneratorField(); + $field->name = $fieldInputsArr[0]; + $field->parseDBType($fieldInputsArr[1]); + + if (count($fieldInputsArr) > 2) { + $field->parseHtmlInput($fieldInputsArr[2]); + } + + if (count($fieldInputsArr) > 3) { + $field->parseOptions($fieldInputsArr[3]); + } + + $field->validations = $validations; + + return $field; + } + + public static function prepareKeyValueArrayStr($arr) + { + $arrStr = '['; + foreach ($arr as $key => $item) { + $arrStr .= "'$item' => '$key', "; + } + + $arrStr = substr($arrStr, 0, strlen($arrStr) - 2); + + $arrStr .= ']'; + + return $arrStr; + } + + public static function prepareValuesArrayStr($arr) + { + $arrStr = '['; + foreach ($arr as $item) { + $arrStr .= "'$item', "; + } + + $arrStr = substr($arrStr, 0, strlen($arrStr) - 2); + + $arrStr .= ']'; + + return $arrStr; + } + + public static function prepareKeyValueArrFromLabelValueStr($values) + { + $arr = []; + + foreach ($values as $value) { + $labelValue = explode(':', $value); + + if (count($labelValue) > 1) { + $arr[$labelValue[0]] = $labelValue[1]; + } else { + $arr[$labelValue[0]] = $labelValue[0]; + } + } + + return $arr; + } +} diff --git a/app/Classes/CodeGenerator/Utils/HTMLFieldGenerator.php b/app/Classes/CodeGenerator/Utils/HTMLFieldGenerator.php new file mode 100644 index 00000000..9ff77ac0 --- /dev/null +++ b/app/Classes/CodeGenerator/Utils/HTMLFieldGenerator.php @@ -0,0 +1,85 @@ +htmlType) { + case 'text': + case 'number': + case 'checkbox': + $fieldTemplate = $generatorHelpers->get_template('Fields.text'); + break; + case 'textarea': + case 'date': + case 'file': + case 'email': + case 'password': + $fieldTemplate = $generatorHelpers->get_template('Fields.'.$field->htmlType); + break; + case 'select': + case 'enum': + $fieldTemplate = $generatorHelpers->get_template('Fields.select'); + $radioLabels = GeneratorFieldsInputUtil::prepareKeyValueArrFromLabelValueStr($field->htmlValues); + + $fieldTemplate = str_replace( + '$INPUT_ARR$', + GeneratorFieldsInputUtil::prepareKeyValueArrayStr($radioLabels), + $fieldTemplate + ); + break; + case 'selectTable': + $inputArr = explode(',', $field->htmlValues[1]); + + $selectTable = $field->htmlValues[0]; + + $fieldTemplate = $generatorHelpers->get_template('Fields.selectable'); + $fieldTemplate = str_replace('$SELECT_TABLE$', str::singular($selectTable),$fieldTemplate); + $fieldTemplate = str_replace('$SELECT_TABLE_CAMEL$', str::singular(str::camel($selectTable)),$fieldTemplate); + $fieldTemplate = str_replace('$LABEL_COLUMN$',$inputArr[0],$fieldTemplate); + $fieldTemplate = str_replace('$VALUE_COLUMN$',$inputArr[1],$fieldTemplate); + + break; + + case 'checkbox_2': + $fieldTemplate = $generatorHelpers->get_template('Fields.checkbox'); + if (count($field->htmlValues) > 0) { + $checkboxValue = $field->htmlValues[0]; + } else { + $checkboxValue = 1; + } + $fieldTemplate = str_replace('$CHECKBOX_VALUE$', $checkboxValue, $fieldTemplate); + break; + case 'radio': + $fieldTemplate = $generatorHelpers->get_template('Fields.radio_group'); + $radioTemplate = $generatorHelpers->get_template('Fields.radio'); + + $radioLabels = GeneratorFieldsInputUtil::prepareKeyValueArrFromLabelValueStr($field->htmlValues); + + $radioButtons = []; + foreach ($radioLabels as $label => $value) { + $radioButtonTemplate = str_replace('$LABEL$', $label, $radioTemplate); + $radioButtonTemplate = str_replace('$VALUE$', $value, $radioButtonTemplate); + $radioButtons[] = $radioButtonTemplate; + } + $fieldTemplate = str_replace('$RADIO_BUTTONS$', implode("\n", $radioButtons), $fieldTemplate); + break; + case 'toggle-switch': + $fieldTemplate = $generatorHelpers->get_template('Fields.toggle-switch'); + break; + } + + return $fieldTemplate; + } +} diff --git a/app/Classes/CodeGenerator/Utils/ResponseUtil.php b/app/Classes/CodeGenerator/Utils/ResponseUtil.php new file mode 100644 index 00000000..8e79391f --- /dev/null +++ b/app/Classes/CodeGenerator/Utils/ResponseUtil.php @@ -0,0 +1,41 @@ + true, + 'data' => $data, + 'message' => $message, + ]; + } + + /** + * @param string $message + * @param array $data + * + * @return array + */ + public static function makeError($message, array $data = []) + { + $res = [ + 'success' => false, + 'message' => $message, + ]; + + if (!empty($data)) { + $res['data'] = $data; + } + + return $res; + } +} diff --git a/app/Classes/CodeGenerator/Utils/SchemaUtil.php b/app/Classes/CodeGenerator/Utils/SchemaUtil.php new file mode 100644 index 00000000..6c0cb4ac --- /dev/null +++ b/app/Classes/CodeGenerator/Utils/SchemaUtil.php @@ -0,0 +1,42 @@ +'.$fieldType."('".$fieldName."'"; + + if (count($fieldTypeParams) > 0) { + $fieldStr .= ', '.implode(' ,', $fieldTypeParams); + } + if ($fieldType == 'enum') { + $inputsArr = explode(',', $field['htmlTypeInputs']); + $inputArrStr = GeneratorFieldsInputUtil::prepareValuesArrayStr($inputsArr); + $fieldStr .= ', '.$inputArrStr; + } + + $fieldStr .= ')'; + + if (count($databaseInputs) > 0) { + foreach ($databaseInputs as $databaseInput) { + $databaseInput = explode(',', $databaseInput); + $type = array_shift($databaseInput); + $fieldStr .= "->$type(".implode(',', $databaseInput).')'; + } + } + + $fieldStr .= ';'; + + return $fieldStr; + } +} diff --git a/app/Classes/CodeGenerator/Utils/TableFieldsGenerator.php b/app/Classes/CodeGenerator/Utils/TableFieldsGenerator.php new file mode 100644 index 00000000..3c6bb21f --- /dev/null +++ b/app/Classes/CodeGenerator/Utils/TableFieldsGenerator.php @@ -0,0 +1,541 @@ +tableName = $tableName; + $this->ignoredFields = $ignoredFields; + + if (!empty($connection)) { + $this->schemaManager = DB::connection($connection)->getDoctrineSchemaManager(); + } else { + $this->schemaManager = DB::getDoctrineSchemaManager(); + } + + $platform = $this->schemaManager->getDatabasePlatform(); + $defaultMappings = [ + 'enum' => 'string', + 'json' => 'text', + 'bit' => 'boolean', + ]; + + $mappings = []; + $mappings = array_merge($mappings, $defaultMappings); + foreach ($mappings as $dbType => $doctrineType) { + $platform->registerDoctrineTypeMapping($dbType, $doctrineType); + } + + $columns = $this->schemaManager->listTableColumns($tableName); + + $this->columns = []; + foreach ($columns as $column) { + if (!in_array($column->getName(), $ignoredFields)) { + $this->columns[] = $column; + } + } + + $this->primaryKey = $this->getPrimaryKeyOfTable($tableName); + $this->timestamps = static::getTimestampFieldNames(); + $this->defaultSearchable = false; + } + + /** + * Prepares array of GeneratorField from table columns. + */ + public function prepareFieldsFromTable() + { + foreach ($this->columns as $column) { + $type = $column->getType()->getName(); + + switch ($type) { + case 'integer': + $field = $this->generateIntFieldInput($column, 'integer'); + break; + case 'smallint': + $field = $this->generateIntFieldInput($column, 'smallInteger'); + break; + case 'bigint': + $field = $this->generateIntFieldInput($column, 'bigInteger'); + break; + case 'boolean': + $name = Str::title(str_replace('_', ' ', $column->getName())); + $field = $this->generateField($column, 'boolean', 'checkbox,1'); + break; + case 'datetime': + $field = $this->generateField($column, 'datetime', 'date'); + break; + case 'datetimetz': + $field = $this->generateField($column, 'dateTimeTz', 'date'); + break; + case 'date': + $field = $this->generateField($column, 'date', 'date'); + break; + case 'time': + $field = $this->generateField($column, 'time', 'text'); + break; + case 'decimal': + $field = $this->generateNumberInput($column, 'decimal'); + break; + case 'float': + $field = $this->generateNumberInput($column, 'float'); + break; + case 'string': + $field = $this->generateField($column, 'string', 'text'); + break; + case 'text': + $field = $this->generateField($column, 'text', 'textarea'); + break; + default: + $field = $this->generateField($column, 'string', 'text'); + break; + } + + if (strtolower($field->name) == 'password') { + $field->htmlType = 'password'; + } elseif (strtolower($field->name) == 'email') { + $field->htmlType = 'email'; + } elseif (in_array($field->name, $this->timestamps)) { + $field->isSearchable = false; + $field->isFillable = false; + $field->inForm = false; + $field->inIndex = false; + $field->inView = false; + } + $field->isNotNull = (bool) $column->getNotNull(); + $field->description = $column->getComment(); // get comments from table + + $this->fields[] = $field; + } + } + + /** + * Get primary key of given table. + * + * @param string $tableName + * + * @return string|null The column name of the (simple) primary key + */ + public function getPrimaryKeyOfTable($tableName) + { + $column = $this->schemaManager->listTableDetails($tableName)->getPrimaryKey(); + + return $column ? $column->getColumns()[0] : ''; + } + + /** + * Get timestamp columns from config. + * + * @return array the set of [created_at column name, updated_at column name] + */ + public static function getTimestampFieldNames() + { + $createdAtName = 'created_at'; + $updatedAtName = 'updated_at'; + $deletedAtName = 'deleted_at'; + + return [$createdAtName, $updatedAtName, $deletedAtName]; + } + + /** + * Generates integer text field for database. + * + * @param string $dbType + * @param Column $column + * + * @return GeneratorField + */ + private function generateIntFieldInput($column, $dbType) + { + $field = new GeneratorField(); + $field->name = $column->getName(); + $field->parseDBType($dbType); + $field->htmlType = 'number'; + + if ($column->getAutoincrement()) { + $field->dbInput .= ',true'; + } else { + $field->dbInput .= ',false'; + } + + if ($column->getUnsigned()) { + $field->dbInput .= ',true'; + } + + return $this->checkForPrimary($field); + } + + /** + * Check if key is primary key and sets field options. + * + * @param GeneratorField $field + * + * @return GeneratorField + */ + private function checkForPrimary(GeneratorField $field) + { + if ($field->name == $this->primaryKey) { + $field->isPrimary = true; + $field->isFillable = false; + $field->isSearchable = false; + $field->inIndex = false; + $field->inForm = false; + $field->inView = false; + } + + return $field; + } + + /** + * Generates field. + * + * @param Column $column + * @param $dbType + * @param $htmlType + * + * @return GeneratorField + */ + private function generateField($column, $dbType, $htmlType) + { + $field = new GeneratorField(); + $field->name = $column->getName(); + $field->parseDBType($dbType, $column); + $field->parseHtmlInput($htmlType); + + return $this->checkForPrimary($field); + } + + /** + * Generates number field. + * + * @param Column $column + * @param string $dbType + * + * @return GeneratorField + */ + private function generateNumberInput($column, $dbType) + { + $field = new GeneratorField(); + $field->name = $column->getName(); + $field->parseDBType($dbType.','.$column->getPrecision().','.$column->getScale()); + $field->htmlType = 'number'; + + return $this->checkForPrimary($field); + } + + /** + * Prepares relations (GeneratorFieldRelation) array from table foreign keys. + */ + public function prepareRelations() + { + $foreignKeys = $this->prepareForeignKeys(); + $this->checkForRelations($foreignKeys); + } + + /** + * Prepares foreign keys from table with required details. + * + * @return GeneratorTable[] + */ + public function prepareForeignKeys() + { + $tables = $this->schemaManager->listTables(); + + $fields = []; + + foreach ($tables as $table) { + $primaryKey = $table->getPrimaryKey(); + if ($primaryKey) { + $primaryKey = $primaryKey->getColumns()[0]; + } + $formattedForeignKeys = []; + $tableForeignKeys = $table->getForeignKeys(); + foreach ($tableForeignKeys as $tableForeignKey) { + $generatorForeignKey = new GeneratorForeignKey(); + $generatorForeignKey->name = $tableForeignKey->getName(); + $generatorForeignKey->localField = $tableForeignKey->getLocalColumns()[0]; + $generatorForeignKey->foreignField = $tableForeignKey->getForeignColumns()[0]; + $generatorForeignKey->foreignTable = $tableForeignKey->getForeignTableName(); + $generatorForeignKey->onUpdate = $tableForeignKey->onUpdate(); + $generatorForeignKey->onDelete = $tableForeignKey->onDelete(); + + $formattedForeignKeys[] = $generatorForeignKey; + } + + $generatorTable = new GeneratorTable(); + $generatorTable->primaryKey = $primaryKey; + $generatorTable->foreignKeys = $formattedForeignKeys; + + $fields[$table->getName()] = $generatorTable; + } + + return $fields; + } + + /** + * Prepares relations array from table foreign keys. + * + * @param GeneratorTable[] $tables + */ + private function checkForRelations($tables) + { + // get Model table name and table details from tables list + $modelTableName = $this->tableName; + $modelTable = $tables[$modelTableName]; + unset($tables[$modelTableName]); + + $this->relations = []; + + // detects many to one rules for model table + $manyToOneRelations = $this->detectManyToOne($tables, $modelTable); + + if (count($manyToOneRelations) > 0) { + $this->relations = array_merge($this->relations, $manyToOneRelations); + } + + foreach ($tables as $tableName => $table) { + $foreignKeys = $table->foreignKeys; + $primary = $table->primaryKey; + + // if foreign key count is 2 then check if many to many relationship is there + if (count($foreignKeys) == 2) { + $manyToManyRelation = $this->isManyToMany($tables, $tableName, $modelTable, $modelTableName); + if ($manyToManyRelation) { + $this->relations[] = $manyToManyRelation; + continue; + } + } + + // iterate each foreign key and check for relationship + foreach ($foreignKeys as $foreignKey) { + // check if foreign key is on the model table for which we are using generator command + if ($foreignKey->foreignTable == $modelTableName) { + + // detect if one to one relationship is there + $isOneToOne = $this->isOneToOne($primary, $foreignKey, $modelTable->primaryKey); + if ($isOneToOne) { + $modelName = model_name_from_table_name($tableName); + $this->relations[] = GeneratorFieldRelation::parseRelation('1t1,'.$modelName); + continue; + } + + // detect if one to many relationship is there + $isOneToMany = $this->isOneToMany($primary, $foreignKey, $modelTable->primaryKey); + if ($isOneToMany) { + $modelName = model_name_from_table_name($tableName); + $this->relations[] = GeneratorFieldRelation::parseRelation( + '1tm,'.$modelName.','.$foreignKey->localField + ); + continue; + } + } + } + } + } + + /** + * Detects many to many relationship + * If table has only two foreign keys + * Both foreign keys are primary key in foreign table + * Also one is from model table and one is from diff table. + * + * @param GeneratorTable[] $tables + * @param string $tableName + * @param GeneratorTable $modelTable + * @param string $modelTableName + * + * @return bool|GeneratorFieldRelation + */ + private function isManyToMany($tables, $tableName, $modelTable, $modelTableName) + { + // get table details + $table = $tables[$tableName]; + + $isAnyKeyOnModelTable = false; + + // many to many model table name + $manyToManyTable = ''; + + $foreignKeys = $table->foreignKeys; + $primary = $table->primaryKey; + + // check if any foreign key is there from model table + foreach ($foreignKeys as $foreignKey) { + if ($foreignKey->foreignTable == $modelTableName) { + $isAnyKeyOnModelTable = true; + } + } + + // if foreign key is there + if (!$isAnyKeyOnModelTable) { + return false; + } + + foreach ($foreignKeys as $foreignKey) { + $foreignField = $foreignKey->foreignField; + $foreignTableName = $foreignKey->foreignTable; + + // if foreign table is model table + if ($foreignTableName == $modelTableName) { + $foreignTable = $modelTable; + } else { + $foreignTable = $tables[$foreignTableName]; + // get the many to many model table name + $manyToManyTable = $foreignTableName; + } + + // if foreign field is not primary key of foreign table + // then it can not be many to many + if ($foreignField != $foreignTable->primaryKey) { + return false; + break; + } + + // if foreign field is primary key of this table + // then it can not be many to many + if ($foreignField == $primary) { + return false; + } + } + + if (empty($manyToManyTable)) { + return false; + } + + $modelName = model_name_from_table_name($manyToManyTable); + + return GeneratorFieldRelation::parseRelation('mtm,'.$modelName.','.$tableName); + } + + /** + * Detects if one to one relationship is there + * If foreign key of table is primary key of foreign table + * Also foreign key field is primary key of this table. + * + * @param string $primaryKey + * @param GeneratorForeignKey $foreignKey + * @param string $modelTablePrimary + * + * @return bool + */ + private function isOneToOne($primaryKey, $foreignKey, $modelTablePrimary) + { + if ($foreignKey->foreignField == $modelTablePrimary) { + if ($foreignKey->localField == $primaryKey) { + return true; + } + } + + return false; + } + + /** + * Detects if one to many relationship is there + * If foreign key of table is primary key of foreign table + * Also foreign key field is not primary key of this table. + * + * @param string $primaryKey + * @param GeneratorForeignKey $foreignKey + * @param string $modelTablePrimary + * + * @return bool + */ + private function isOneToMany($primaryKey, $foreignKey, $modelTablePrimary) + { + if ($foreignKey->foreignField == $modelTablePrimary) { + if ($foreignKey->localField != $primaryKey) { + return true; + } + } + + return false; + } + + /** + * Detect many to one relationship on model table + * If foreign key of model table is primary key of foreign table. + * + * @param GeneratorTable[] $tables + * @param GeneratorTable $modelTable + * + * @return array + */ + private function detectManyToOne($tables, $modelTable) + { + $manyToOneRelations = []; + + $foreignKeys = $modelTable->foreignKeys; + + foreach ($foreignKeys as $foreignKey) { + $foreignTable = $foreignKey->foreignTable; + $foreignField = $foreignKey->foreignField; + + if (!isset($tables[$foreignTable])) { + continue; + } + + if ($foreignField == $tables[$foreignTable]->primaryKey) { + $modelName = model_name_from_table_name($foreignTable); + $manyToOneRelations[] = GeneratorFieldRelation::parseRelation( + 'mt1,'.$modelName.','.$foreignKey->localField + ); + } + } + + return $manyToOneRelations; + } +}