Mercurial > packages > magicforger
changeset 13:7ee152c22478 main-dev
Merging
| author | luka |
|---|---|
| date | Wed, 24 Apr 2024 20:11:52 -0400 |
| parents | 3426c7e91c24 (diff) 4bb4daa9e3f1 (current diff) |
| children | c969ed13c570 |
| files | .php-cs-fixer.cache src/Generator/Generator.php |
| diffstat | 24 files changed, 1041 insertions(+), 361 deletions(-) [+] |
line wrap: on
line diff
--- a/.php-cs-fixer.cache Wed Apr 24 19:52:35 2024 -0400 +++ b/.php-cs-fixer.cache Wed Apr 24 20:11:52 2024 -0400 @@ -1,1 +1,1 @@ -{"php":"8.3.6","version":"3.50.0","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_parentheses":true,"no_blank_lines_after_class_opening":true,"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"src\/Generator\/Controller\/ControllerGenerator.php":"075e65a43e5ecc55fbc4dcd7636dfcc1","src\/Generator\/Model\/ModelGenerator.php":"e78c07fc13bd9c379991e8b01b13c672","src\/Generator\/Replacer.php":"5a7f98d22504edb6aba92b061ddd9803","src\/Generator\/Generator.php":"794271f48bed8f156878fc36a25ff60f","src\/Generator\/BaseGenerator.php":"409aadd181fbd4f216fe31f4f42ca3e2","src\/Replacer.php":"c6b5f421259f41016014c00270ca001c","src\/MagicForgerServiceProvider.php":"302d8a09dd351d150ee6cc7988dc447f","src\/Helpers\/FileModifier.php":"13d8f773a55604641ce1e89b28de2922","src\/Test.php":"bac04f2095478ff481ad176918e42db2"}} \ No newline at end of file +{"php":"8.2.7","version":"3.19.1","indent":" ","lineEnding":"\n","rules":{"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_typehint":true,"curly_braces_position":{"allow_single_line_empty_anonymous_classes":true},"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"visibility_required":true,"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true},"hashes":{"src\/Generator\/BaseGenerator.php":"409aadd181fbd4f216fe31f4f42ca3e2","src\/Replacer.php":"c6b5f421259f41016014c00270ca001c","src\/MagicForgerServiceProvider.php":"e56f92adc0181e9b7681de8ca8aca6eb","src\/Generator\/Controller\/ControllerGenerator.php":"075e65a43e5ecc55fbc4dcd7636dfcc1","src\/Generator\/Generator.php":"794271f48bed8f156878fc36a25ff60f","src\/Generator\/Replacer.php":"5a7f98d22504edb6aba92b061ddd9803","src\/Generator\/Model\/ModelGenerator.php":"e78c07fc13bd9c379991e8b01b13c672"}}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.php-cs-fixer.dist.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,14 @@ +<?php + +$finder = PhpCsFixer\Finder::create() + ->in(__DIR__) + ->exclude('.hg') +; + +$config = new PhpCsFixer\Config(); +return $config->setRules([ + '@Symfony' => true, + 'full_opening_tag' => false, + ]) + ->setFinder($finder) +;
--- a/composer.json Wed Apr 24 19:52:35 2024 -0400 +++ b/composer.json Wed Apr 24 20:11:52 2024 -0400 @@ -9,7 +9,8 @@ }, "minimum-stability": "stable", "require": { - "laravel/framework": ">=10.3" + "laravel/framework": ">=10.3", + "doctrine/dbal": "^3.6" }, "extra": { "laravel": {
--- a/examples/ExampleGenerator.php.stub Wed Apr 24 19:52:35 2024 -0400 +++ b/examples/ExampleGenerator.php.stub Wed Apr 24 20:11:52 2024 -0400 @@ -1,6 +1,6 @@ <?php -namespace Wizzard\MagicForger\Generator\Controller; +namespace Wizzard\MagicForger\Generator\{{ Class Name }}; use Symfony\Component\Console\Attribute\AsCommand; use Wizzard\MagicForger\Generator\BaseGenerator;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ConfigHelper.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,200 @@ +<?php + +namespace Wizzard\MagicForger; + +use Illuminate\Support\Collection; + +class ConfigHelper +{ + // Config array + public static $config = []; + + // Config file name constant + public const CONFIG_FILE_NAME = 'mf_config.php'; + + // Config path variable + public static string $config_path; + + /** + * Set up configuration path. + * @return void + */ + public static function setup_config_path(string $base_path): void + { + self::$config_path = $base_path.'/'.self::CONFIG_FILE_NAME; + } + + /** + * Get configuration path. + * + * @return string + */ + protected static function get_config_path(): string + { + return self::$config_path; + } + + /** + * Write configuration into a file. + * @return void + */ + public static function write_config(): void + { + $path = self::get_config_path(); + $str = '<?php + return '.self::varexport(self::$config, true).';'; + + file_put_contents($path, $str); + // After writing the file, format it + self::format_file($path); + } + + /** + * Read configuration from a file. + * @return void + */ + public static function read_config(): void + { + $path = self::get_config_path(); + self::$config = include $path; + } + + /** + * Print configuration. + * @return void + */ + public static function print_config(): void + { + self::varexport(self::$config); + } + + /** + * PHP var_export() function with short array syntax (square brackets) indented 2 spaces. + * + * NOTE: The only issue is when a string value has `=>\n[`, it will get converted to `=> [` + * + * @see https://www.php.net/manual/en/function.var-export.php + * + * @param bool $return + * @return string|string[]|null + */ + public static function varexport(mixed $expression, $return = false): string|array|null + { + $export = var_export($expression, true); + $patterns = [ + "/array \(/" => '[', + "/^([ ]*)\)(,?)$/m" => '$1]$2', + "/=>[ ]?\n[ ]+\[/" => '=> [', + "/([ ]*)(\'[^\']+\') => ([\[\'])/" => '$1$2 => $3', + ]; + $export = preg_replace(array_keys($patterns), array_values($patterns), $export); + if ((bool) $return) { + return $export; + } else { + echo $export; + } + return null; + } + + /** + * Format the given file. + * @return void + */ + protected static function format_file(string $path): void + { + exec('php-cs-fixer fix '.$path); + } + + /** + * Set up tables. + */ + public static function set_up_tables(): Collection + { + $schema = \DB::connection()->getDoctrineSchemaManager(); + $tables = collect($schema->listTableNames())->all(); + $table_foreign_keys = []; + foreach ($tables as $table) { + $table_foreign_keys[$table] = $schema->listTableForeignKeys($table); + } + + $insert_tables = []; + foreach ($tables as $table) { + $columns = []; + $table_columns = $schema->listTableColumns($table); + + // Initiate new arrays for foreign keys + $foreign_keys = []; + $foreign_keys_reverse = []; + + // Check foreign key references from this table + $foreign_keys_list = $table_foreign_keys[$table]; + foreach ($foreign_keys_list as $fk) { + $foreign_keys[$fk->getLocalColumns()[0]] = [ + 'foreign_table' => $fk->getForeignTableName(), + 'foreign_column' => $fk->getForeignColumns()[0], + ]; + } + + foreach ($table_columns as $column) { + $full_class = get_class($column->getType()); + $class_parts = explode('\\', $full_class); + $class_name = end($class_parts); + + $columns[$column->getName()] = [ + 'type' => $class_name, + 'should_insert' => [ + 'controller' => true, + 'model' => true, + 'requests' => true, + 'views' => true, + ], + ]; + } + // Check foreign key references to this table + foreach ($tables as $other_table) { + if ($other_table != $table) { + $foreign_keys_list = $table_foreign_keys[$other_table]; + foreach ($foreign_keys_list as $fk) { + if ($fk->getForeignTableName() == $table) { + $foreign_keys_reverse[] = [ + 'table' => $other_table, + 'column' => $fk->getLocalColumns()[0], + ]; + } + } + } + } + $insert_tables[$table] = []; + $insert_tables[$table]['columns'] = $columns; + $insert_tables[$table]['foreign_keys'] = $foreign_keys; // Foreign keys FROM this table + $insert_tables[$table]['foreign_keys_reverse'] = $foreign_keys_reverse; // Foreign keys TO this table + $insert_tables[$table]['type'] = 'default'; + } + + self::merge_array_priority(self::$config['tables'], $insert_tables); + + return $tables; + } + + /** + * Merge two arrays and ensure priority values do not get overwritten. + * + * @param array $priority + * @param array $merged + * @return void + */ + private static function merge_array_priority(&$priority, $merged): void + { + foreach ($merged as $key => $value) { + // if the priority key is not set, automatically add the merged values + if (!isset($priority[$key])) { + $priority[$key] = $value; + } else { + // if the value is an array recursively merge with priority + if (is_array($value) && is_array($priority[$key])) { + self::merge_array_priority($priority[$key], $value); + } + } + } + } +}
--- a/src/Generator/BaseGenerator.php Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/BaseGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -3,58 +3,67 @@ namespace Wizzard\MagicForger\Generator; use DB; - use Illuminate\Console\GeneratorCommand; -use Illuminate\Support\Str; -use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; - -use Wizzard\MagicForger\Generator\Replacer; +use Wizzard\MagicForger\Replacer\Replacer; +use Wizzard\MagicForger\Replacer\TableReplacer; abstract class BaseGenerator extends GeneratorCommand { use Replacer; + use TableReplacer; /** - * The console command description. + * The schema of the database. * * @var string */ protected $schema; /** - * The console command description. + * The tables available in the schema. * - * @var string + * @var array */ protected $tables; /** + * The current Table being used. + * + * @var table + */ + protected $currentTable; + + /** * Execute the console command. */ public function handle() { - - // First we need to ensure that the table exists, then we can - if (! $this->tableExists($this->getTableInput())) { + if (!$this->tableExists($this->getTableInput())) { $this->components->error('The table: "'.$this->getTableInput().'" does not exist in the database.'); return false; } + $this->setCurrentTable($this->getTableInput()); + $path = $this->getPath(); $file = $this->getFile($path); $file = $this->apply_replacements($file); + $file = $this->apply_inserts($file); + $this->makeDirectory($path); $this->files->put($path, $this->sortImports($file)); + $this->format_file($path); + $info = $this->type; $this->components->info(sprintf('%s [%s] created successfully.', $info, $path)); @@ -62,15 +71,14 @@ /** * Override the original so that we can prompt for a table with autocomplete. - * */ protected function promptForMissingArguments(InputInterface $input, OutputInterface $output) { $prompted = false; - if(is_null($input->getArgument('table'))) { + if (is_null($input->getArgument('table'))) { $prompted = true; $table = null; - while ($table === null) { + while (null === $table) { $table = $this->components->askWithCompletion( 'What Table should we use?', $this->possibleTables() @@ -83,7 +91,7 @@ parent::promptForMissingArguments($input, $output); // This will get missed if we prompt here but not in the parent - if($prompted) { + if ($prompted) { $this->afterPromptingForMissingArguments($input, $output); } } @@ -133,7 +141,7 @@ } /** - * Determines if the file exists + * Determines if the file exists. */ protected function fileExists(string $path): bool { @@ -144,18 +152,17 @@ * Gets the file that will be worked on. If there is already an existing file * then we can open that. However if we are forcing the operation, then we * will start with an empty stub. - * */ protected function getFile($name) { - if ((! $this->hasOption('fresh') || - ! $this->option('fresh')) && - $this->fileExists($name)) { - //Working with an existing file + if (!($this->hasOption('fresh') + && $this->option('fresh')) + && $this->fileExists($name)) { + // Working with an existing file return $this->files->get($name); } - //Working with a stub + // Working with a stub return $this->files->get($this->getStub()); } @@ -169,9 +176,8 @@ return trim($this->argument('table')); } - /** - * Determines if the table exists in the current database + * Determines if the table exists in the current database. */ protected function tableExists(string $table_name): bool { @@ -187,7 +193,7 @@ } /** - * Get the tables in the schema + * Get the tables in the schema. */ protected function getTables() { @@ -199,14 +205,38 @@ } /** - * Get the database schema for DB interactions + * Get the database schema for DB interactions. */ protected function getSchema() { if (is_null($this->schema)) { - $this->schema = DB::connection()->getDoctrineSchemaManager(); + $this->schema = \DB::connection()->getDoctrineSchemaManager(); } return $this->schema; } + + protected function getTable(string $table_name) + { + return $this->getSchema()->introspectTable($table_name); + } + + protected function getCurrentTable() + { + return $this->currentTable; + } + + protected function setCurrentTable(string $table_name) + { + $table = null; + if (!is_null($table_name) && '' !== trim($table_name)) { + $table = $this->getTable($table_name); + } + $this->currentTable = $table; + } + + protected function format_file(string $path) + { + exec('php-cs-fixer fix '.$path); + } }
--- a/src/Generator/Controller/ControllerGenerator.php Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Controller/ControllerGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -4,8 +4,6 @@ use Symfony\Component\Console\Attribute\AsCommand; use Wizzard\MagicForger\Generator\BaseGenerator; -use Wizzard\MagicForger\Replacer; -use Illuminate\Support\Str; #[AsCommand(name: 'mf:controller')] class ControllerGenerator extends BaseGenerator @@ -52,7 +50,8 @@ /** * Resolve the fully-qualified path to the stub. * - * @param string $stub + * @param string $stub + * * @return string */ protected function resolveStubPath($stub) @@ -74,6 +73,6 @@ */ protected function getPath($name = null) { - return str_replace(['App\\', '\\'], ['app/', '/'], $this->getControllerNamespace() . '/' . $this->controller_name($this->getTableInput()) . '.php'); + return str_replace(['App\\', '\\'], ['app/', '/'], $this->getControllerNamespace().'/'.$this->controller_name($this->getTableInput()).'.php'); } }
--- a/src/Generator/Controller/stubs/controller.stub Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Controller/stubs/controller.stub Wed Apr 24 20:11:52 2024 -0400 @@ -35,10 +35,13 @@ */ public function store({{ storeRequest }} $request) { + $validated = $request->validated(); + // ${{ modelVariable }} = new {{ model }}(); //insert the values into the model + ${{ modelVariable }}->map_values($validated); ${{ modelVariable }}->save(); @@ -74,7 +77,11 @@ */ public function update({{ updateRequest }} $request, {{ model }} ${{ modelVariable }}) { + $validated = $request->validated(); + // Set the variables + ${{ modelVariable }}->map_values($validated); + ${{ modelVariable }}->save(); return redirect()->route('{{ tableName }}.index');
--- a/src/Generator/Generator.php Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Generator.php Wed Apr 24 20:11:52 2024 -0400 @@ -2,16 +2,10 @@ namespace Wizzard\MagicForger\Generator; -use DB; - use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Illuminate\Support\Str; - -use Wizzard\MagicForger\Generator\BaseGenerator; -use Wizzard\MagicForger\Replacer; #[AsCommand(name: 'mf')] class Generator extends BaseGenerator @@ -30,13 +24,11 @@ */ protected $description = 'Generates any (or all) of the available files.'; - /** * Execute the console command. */ public function handle() { - // First we need to ensure that the table exists, then we can if (!$this->tableExists($this->getTableInput())) { $this->components->error('The table: "'.$this->getTableInput().'" does not exist in the database.'); @@ -44,12 +36,17 @@ return false; } + /* $this->setCurrentTable($this->getTableInput()); */ + /* dd($this->getCurrentTable()->getForeignKeys()); */ + if ($this->option('all')) { /* $this->input->setOption('factory', true); */ /* $this->input->setOption('seed', true); */ /* $this->input->setOption('migration', true); */ $this->input->setOption('controller', true); $this->input->setOption('model', true); + $this->input->setOption('request', true); + $this->input->setOption('route', true); } /* if ($this->option('factory')) { */ @@ -72,6 +69,13 @@ $this->createModel(); } + if ($this->option('request')) { + $this->createRequest(); + } + + if ($this->option('route')) { + $this->createRoute(); + } } /** @@ -81,11 +85,13 @@ */ protected function getOptions() { - return [ + return array_merge(parent::getOptions(), [ ['all', 'a', InputOption::VALUE_NONE, 'Generate a migration, seeder, factory, policy, resource controller, and form request classes for the table.'], ['controller', 'c', InputOption::VALUE_NONE, 'Generate a controller class for the table.'], - ['model', 'm', InputOption::VALUE_NONE, 'Generate a controller class for the table.'], - ]; + ['model', 'm', InputOption::VALUE_NONE, 'Generate a model class for the table.'], + ['request', 'r', InputOption::VALUE_NONE, 'Generate base request classes for the table.'], + ['route', 'w', InputOption::VALUE_NONE, 'Generate base routes classes for the table.'], + ]); } /** @@ -103,6 +109,21 @@ protected function createController() { - $this->call('mf:controller', ['table' => $this->getTableInput()]); + $this->call('mf:controller', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]); + } + + protected function createModel() + { + $this->call('mf:model', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]); + } + + protected function createRequest() + { + $this->call('mf:request', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh'), '--all' => true]); + } + + protected function createRoute() + { + $this->call('mf:route', ['table' => $this->getTableInput(), '--fresh' => $this->option('fresh')]); } }
--- a/src/Generator/Model/ModelGenerator.php Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Model/ModelGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -1,11 +1,9 @@ <?php -namespace Wizzard\MagicForger\Generator\Controller; +namespace Wizzard\MagicForger\Generator\Model; use Symfony\Component\Console\Attribute\AsCommand; use Wizzard\MagicForger\Generator\BaseGenerator; -use Wizzard\MagicForger\Replacer; -use Illuminate\Support\Str; #[AsCommand(name: 'mf:model')] class ModelGenerator extends BaseGenerator @@ -52,7 +50,8 @@ /** * Resolve the fully-qualified path to the stub. * - * @param string $stub + * @param string $stub + * * @return string */ protected function resolveStubPath($stub) @@ -74,6 +73,6 @@ */ protected function getPath($name = null) { - return str_replace(['App\\', '\\'], ['app/', '/'], $this->getModelNamespace() . '/' . $this->model_name($this->getTableInput()) . '.php'); + return str_replace(['App\\', '\\'], ['app/', '/'], $this->getModelNamespace().'/'.$this->model_name($this->getTableInput()).'.php'); } }
--- a/src/Generator/Model/stubs/model.pivot.stub Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Model/stubs/model.pivot.stub Wed Apr 24 20:11:52 2024 -0400 @@ -7,4 +7,15 @@ class {{ class }} extends Pivot { // + + /** + * Indicates if the model should be timestamped. + * By default our pivots will not use timestamps + * + * @var bool + */ + public $timestamps = false; + + + }
--- a/src/Generator/Model/stubs/model.stub Wed Apr 24 19:52:35 2024 -0400 +++ b/src/Generator/Model/stubs/model.stub Wed Apr 24 20:11:52 2024 -0400 @@ -4,8 +4,49 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class {{ class }} extends Model { - use HasFactory; + //use HasFactory; + use SoftDeletes; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = '{{ tableName }}'; + + /** + * The model's default values for attributes. + * + * @var array + */ + protected $attributes = [ + # {{ atributeInsertPoint }} + ]; + + + public static function boot() : void { + parent::boot(); + + self::creating(function ($item) { + $item->created_by = \Auth::user()->id; + $item->updated_by = \Auth::user()->id; + }); + + self::saving(function ($item) { + $item->updated_by = \Auth::user()->id; + }); + } + + + //relations + + // BelongsTo + + // HasMany + + }
--- a/src/Generator/Replacer.php Wed Apr 24 19:52:35 2024 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -<?php - -namespace Wizzard\MagicForger\Generator; - -use Illuminate\Support\Str; - -trait Replacer -{ - /** - * Prefix and Suffix for controller. - * Usage is up to the user. - * - * @var string - */ - protected $controller_prefix = ""; - - - /** - * Prefix and Suffix for controller. - * Usage is up to the user. - * - * @var string - */ - protected $controller_suffix = "Controller"; - - - /** - * Finds all places in a string that could be replaced. - * Returns an array of all potential replacements as they - * appear in the target. - */ - public function get_all_inserts(string $target): array - { - //find all the matches to our expected syntax - $matches = []; - preg_match_all('/{{[\sa-zA-Z\-_]+}}/', $target, $matches); - // sort the array and return unique values - sort($matches[0]); - return array_values(array_unique($matches[0])); - } - - - public function apply_replacements(string $target): string - { - $inserts = $this->get_all_inserts($target); - $available_replacements = $this->get_available_replacements(); - - $target = str_replace( - array_keys($available_replacements), - $available_replacements, - $target - ); - - return $target; - } - /** - * @return array<string,mixed> - */ - public function get_available_replacements() - { - $table_name = $this->getTableInput(); - $replacements = [ - "{{ class }}" => $this->getClassName($table_name), - "{{ model }}" => $this->model_name($table_name), - "{{ modelVariable }}" => $this->model_variable($table_name), - "{{ namespace }}" => $this->{'get' . $this->type . 'Namespace'}(), - "{{ namespacedModel }}" => $this->getModelNamespace(), - "{{ requestUses }}" => $this->getRequestUses($table_name), - "{{ rootNamespace }}" => $this->getRootNamespace(), - "{{ storeRequest }}" => $this->store_request_name($table_name), - "{{ tableName }}" => $table_name, - "{{ updateRequest }}" => $this->update_request_name($table_name), - ]; - - return $replacements; - } - - //////////////////////////////////////////// - // Internals and Classes // - //////////////////////////////////////////// - - /** - * Model names are generated in uppercase first Camel case - */ - public function model_name(string $name): string - { - return Str::singular(Str::studly($name)); - } - - /** - * Model variable is standardly just a singular version of the table name - */ - public function model_variable(string $name): string - { - return Str::singular($name); - } - - /** - * Controller names are generated in uppercase first Camel case - * and wrapped in the prefix and suffix - */ - public function controller_name(string $name): string - { - return $this->controller_prefix . - $this->model_name($name) . - $this->controller_suffix; - } - - public function store_request_name(string $name): string - { - return 'Store' . $this->model_name($name); - } - - public function update_request_name(string $name): string - { - return 'Update' . $this->model_name($name); - } - - - //////////////////////////////////////////// - // Namespaces // - //////////////////////////////////////////// - - public function getRootNamespace() - { - return $this->laravel->getNamespace(); - } - - public function getModelNamespace() - { - return $this->getRootNamespace() . 'Models'; - } - - public function getControllerNamespace() - { - return $this->getRootNamespace() . 'Http\\Controllers'; - } - - public function getRequestNamespace(string $name) - { - return $this->getRootNamespace() . 'Http\\Requests\\' . $this->model_name($name); - } - /** - * @return string - */ - public function getRequestUses(string $name) - { - return implode("\n", [ - "use " . $this->getRequestNamespace($name) . '\\' . $this->store_request_name($name), - "use " . $this->getRequestNamespace($name) . '\\' . $this->update_request_name($name), - ]); - } - - - //////////////////////////////////////////// - // Language and Presentables // - //////////////////////////////////////////// - - /** - * Breaks up a string and makes it human readable - * - * This function assumes that the inputted name is camel case - */ - public function human_readable(string $name): string - { - return Str::title(Str::replace('_', ' ', $name)); - } - - /** - * Breaks up a string and makes it human readable and lowecase - * - * This function assumes that the inputted name is camel case - */ - public function human_readable_lc(string $name): string - { - return Str::lower($this->human_readable($name)); - } -} - -class Replacer -{ - /** - * @return void - */ - public function get_available_replacements(): array - { - } - - public function getRequestUses(): string - { - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Requests/RequestGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,102 @@ +<?php + +namespace Wizzard\MagicForger\Generator\Requests; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Wizzard\MagicForger\Generator\BaseGenerator; + +#[AsCommand(name: 'mf:request')] +class RequestGenerator extends BaseGenerator +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $name = 'mf:request'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generates the Request File for a table.'; + + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'Request'; + + /** + * Execute the console command. + */ + public function handle() + { + // First we need to ensure that the table exists, then we can + if (!$this->tableExists($this->getTableInput())) { + $this->components->error('The table: "'.$this->getTableInput().'" does not exist in the database.'); + + return false; + } + + if ($this->option('all')) { + $this->input->setOption('store_request', true); + $this->input->setOption('update_request', true); + } + + if ($this->option('store_request')) { + $this->createStoreRequest(); + } + + if ($this->option('update_request')) { + $this->createUpdateRequest(); + } + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return array_merge(parent::getOptions(), [ + ['all', 'a', InputOption::VALUE_NONE, 'Generate all request classes for the table.'], + ['store_request', 's', InputOption::VALUE_NONE, 'Generate store request class for the table.'], + ['update_request', 'u', InputOption::VALUE_NONE, 'Generate update request class for the table.'], + ]); + } + + /** + * Interact further with the user if they were prompted for missing arguments. + * + * @return void + */ + protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output) + { + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + } + + protected function createStoreRequest() + { + $this->call('mf:store_request', ['table' => $this->getTableInput()]); + } + + protected function createUpdateRequest() + { + $this->call('mf:update_request', ['table' => $this->getTableInput()]); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Requests/StoreRequestGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,78 @@ +<?php + +namespace Wizzard\MagicForger\Generator\Requests; + +use Symfony\Component\Console\Attribute\AsCommand; +use Wizzard\MagicForger\Generator\BaseGenerator; + +#[AsCommand(name: 'mf:store_request')] +class StoreRequestGenerator extends BaseGenerator +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $name = 'mf:store_request'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generates the StoreRequest File for a table.'; + + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'StoreRequest'; + + /** + * Execute the console command. + */ + public function handle() + { + parent::handle(); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + return $this->resolveStubPath('/stubs/request.stub'); + } + + /** + * Resolve the fully-qualified path to the stub. + * + * @param string $stub + * + * @return string + */ + protected function resolveStubPath($stub) + { + return is_file($customPath = $this->laravel->basePath(trim($stub, '/'))) + ? $customPath + : __DIR__.$stub; + } + + protected function getClassName($name) + { + return $this->store_request_name($name); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getPath($name = null) + { + return str_replace(['App\\', '\\'], ['app/', '/'], $this->getRequestNamespace($this->getTableInput()).'/'.$this->store_request_name($this->getTableInput()).'.php'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Requests/UpdateRequestGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,78 @@ +<?php + +namespace Wizzard\MagicForger\Generator\Requests; + +use Symfony\Component\Console\Attribute\AsCommand; +use Wizzard\MagicForger\Generator\BaseGenerator; + +#[AsCommand(name: 'mf:update_request')] +class UpdateRequestGenerator extends BaseGenerator +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $name = 'mf:update_request'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generates the UpdateRequest File for a table.'; + + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'UpdateRequest'; + + /** + * Execute the console command. + */ + public function handle() + { + parent::handle(); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + return $this->resolveStubPath('/stubs/request.stub'); + } + + /** + * Resolve the fully-qualified path to the stub. + * + * @param string $stub + * + * @return string + */ + protected function resolveStubPath($stub) + { + return is_file($customPath = $this->laravel->basePath(trim($stub, '/'))) + ? $customPath + : __DIR__.$stub; + } + + protected function getClassName($name) + { + return $this->update_request_name($name); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getPath($name = null) + { + return str_replace(['App\\', '\\'], ['app/', '/'], $this->getRequestNamespace($this->getTableInput()).'/'.$this->update_request_name($this->getTableInput()).'.php'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Requests/stubs/request.stub Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,28 @@ +<?php + +namespace {{ namespace }}; + +use Illuminate\Foundation\Http\FormRequest; + +class {{ class }} extends FormRequest +{ + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string> + */ + public function rules(): array + { + return [ + // {{ valuesForValidation }} + ]; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Route/RouteGenerator.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,78 @@ +<?php + +namespace Wizzard\MagicForger\Generator\Route; + +use Symfony\Component\Console\Attribute\AsCommand; +use Wizzard\MagicForger\Generator\BaseGenerator; + +#[AsCommand(name: 'mf:routes')] +class RouteGenerator extends BaseGenerator +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $name = 'mf:routes'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Generates the Route File for a table.'; + + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'Route'; + + /** + * Execute the console command. + */ + public function handle() + { + parent::handle(); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + return $this->resolveStubPath('/stubs/routes.stub'); + } + + /** + * Resolve the fully-qualified path to the stub. + * + * @param string $stub + * + * @return string + */ + protected function resolveStubPath($stub) + { + return is_file($customPath = $this->laravel->basePath(trim($stub, '/'))) + ? $customPath + : __DIR__.$stub; + } + + protected function getClassName($name) + { + return $this->routes_name($name); + } + + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getPath($name = null) + { + return str_replace(['App\\', '\\'], ['app/', '/'], $this->getRouteNamespace().'/'.$this->routes_name($this->getTableInput()).'.php'); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Generator/Route/stubs/route.stub Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,13 @@ +<?php +Route::controller({{ controllerName }}::class) + ->prefix('{{ tableName }}') + ->alias('{{ tableName }}.') + ->group( function () { + Route::get('/', 'index')->name('index'); + Route::get('/create', 'create')->name('create'); + Route::get('/edit', 'edit')->name('edit'); + + Route::post('/store', 'store')->name('store'); + Route::put('/udpate/{id}', 'update')->name('update'); + Route::delete('/delete/{id}', 'delete')->name('delete'); + });
--- a/src/Helpers/Replacer.php Wed Apr 24 19:52:35 2024 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -<?php - -namespace Magicforger\Helpers; - - -/* - * Replacer - * - * A class that handles all replacements necessary - * - * General flow: - * Read a line looking for a replacement string - * - * A replacement string will consist of 2 values - * Reference Object, and Replacement Function - * - * After the replacement is made, the Object, function - * are stored in an array to be cached for future replacements - * - * Basically lazy loading the replacements. - * */ -class Replacer { - - -/* - * The array of cached replacements - * - * Object name => [ - * function => replacement text, - * ] - * - * */ -protected $replacement_cache []; - - -/* - * Static instance of inflector for - * string manipulation. - * - * */ -private static $inflector = null; - -public function __construct() { - if(is_null(self::$inflector)) { - self::$inflector = InflectorFactory::create()->build(); - } -} - - - - -protected function extract_replacement_values(string $replacement_string): string { - $matches = []; - preg_match('/o:([^\s]+)\s+f:([^\s]+)/', $replacement_string, $matches); - $name = $matches[1]; - $function = $matches[2]; - - return ['name' => $name, 'function' => $function]; -} - -protected function get_replacement(string $replacement_string): string { - - - - - return $replacement; -} - - - - -}
--- a/src/MagicForgerServiceProvider.php Wed Apr 24 19:52:35 2024 -0400 +++ b/src/MagicForgerServiceProvider.php Wed Apr 24 20:11:52 2024 -0400 @@ -3,9 +3,13 @@ namespace Wizzard\MagicForger; use Illuminate\Support\ServiceProvider; +use Wizzard\MagicForger\Generator\Controller\ControllerGenerator; use Wizzard\MagicForger\Generator\Generator; -use Wizzard\MagicForger\Generator\Controller\ControllerGenerator; use Wizzard\MagicForger\Generator\Model\ModelGenerator; +use Wizzard\MagicForger\Generator\Requests\RequestGenerator; +use Wizzard\MagicForger\Generator\Requests\StoreRequestGenerator; +use Wizzard\MagicForger\Generator\Requests\UpdateRequestGenerator; +use Wizzard\MagicForger\Generator\Route\RouteGenerator; class MagicForgerServiceProvider extends ServiceProvider { @@ -19,7 +23,18 @@ Generator::class, ControllerGenerator::class, ModelGenerator::class, + RequestGenerator::class, + StoreRequestGenerator::class, + UpdateRequestGenerator::class, + RouteGenerator::class, ]); } + + $this->register_config_helper(); + } + + public function register_config_helper() + { + ConfigHelper::setup_config_path(base_path()); } }
--- a/src/Replacer.php Wed Apr 24 19:52:35 2024 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -<?php - -namespace Wizzard\MagicForger; - -use Illuminate\Support\Str; - -class Replacer -{ - /** - * Cached replacements for re-use. - * - * @var array - */ - protected $replacement_cache = []; - - - - - /** - * The lowest level to show log outputs. - * - * @var int - */ - private $log_level = 1; - - - public function __construct() - { - /* parent::__construct(); */ - } - - - /** - * Outputs a log for the replacements based on log level. - */ - public function log(string $str, int $log_level = 1): void - { - - if($this->log_level <= $log_level) { - print($str . "\n"); - } - - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Replacer/Replacer.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,192 @@ +<?php + +namespace Wizzard\MagicForger\Replacer; + +use Illuminate\Support\Str; + +trait Replacer +{ + /** + * Prefix and Suffix for controller. + * Usage is up to the user. + * + * @var string + */ + protected $controller_prefix = ''; + + /** + * Prefix and Suffix for controller. + * Usage is up to the user. + * + * @var string + */ + protected $controller_suffix = 'Controller'; + + /** + * Finds all places in a string that could be replaced. + * Returns an array of all potential replacements as they + * appear in the target. + */ + public function get_all_keywords(string $target): array + { + // find all the matches to our expected syntax + $matches = []; + preg_match_all('/{{[\sa-zA-Z\-_]+}}/', $target, $matches); + // sort the array and return unique values + sort($matches[0]); + + return array_values(array_unique($matches[0])); + } + + public function apply_replacements(string $target): string + { + $inserts = $this->get_all_keywords($target); + $available_replacements = $this->get_available_replacements(); + + $target = str_replace( + array_keys($available_replacements), + $available_replacements, + $target + ); + + return $target; + } + + public function get_available_replacements() + { + $table_name = $this->getTableInput(); + $replacements = [ + '{{ class }}' => $this->getClassName($table_name), + '{{ controllerName }}' => $this->controller_name($table_name), + '{{ model }}' => $this->model_name($table_name), + '{{ modelVariable }}' => $this->model_variable($table_name), + '{{ namespace }}' => $this->{'get'.$this->type.'Namespace'}($table_name), + '{{ namespacedModel }}' => $this->getNamespacedModel($table_name), + '{{ requestUses }}' => $this->getRequestUses($table_name), + '{{ rootNamespace }}' => $this->getRootNamespace(), + '{{ storeRequest }}' => $this->store_request_name($table_name), + '{{ tableName }}' => $table_name, + '{{ updateRequest }}' => $this->update_request_name($table_name), + ]; + + return $replacements; + } + + // ////////////////////////////////////////// + // Internals and Classes // + // ////////////////////////////////////////// + + /** + * Model names are generated in uppercase first Camel case. + */ + public function model_name(string $name): string + { + return Str::singular(Str::studly($name)); + } + + /** + * Model variable is standardly just a singular version of the table name. + */ + public function model_variable(string $name): string + { + return Str::singular($name); + /* return 'item'; */ + } + + /** + * Controller names are generated in uppercase first Camel case + * and wrapped in the prefix and suffix. + */ + public function controller_name(string $name): string + { + return $this->controller_prefix. + $this->model_name($name). + $this->controller_suffix; + } + + public function store_request_name(string $name): string + { + return 'Store'.$this->model_name($name).'Request'; + } + + public function update_request_name(string $name): string + { + return 'Update'.$this->model_name($name).'Request'; + } + + // ////////////////////////////////////////// + // Namespaces // + // ////////////////////////////////////////// + + public function getRootNamespace() + { + return $this->laravel->getNamespace(); + } + + public function getModelNamespace(string $name = '') + { + return $this->getRootNamespace().'Models'; + } + + public function getNamespacedModel(string $name = '') + { + return $this->getModelNamespace().'\\'.$this->model_name($name); + } + + public function getControllerNamespace(string $name = '') + { + return $this->getRootNamespace().'Http\\Controllers'; + } + + public function getRequestNamespace(string $name) + { + return $this->getRootNamespace().'Http\\Requests\\'.$this->model_name($name); + } + + public function getStoreRequestNamespace(string $name) + { + return $this->getRequestNamespace($name); + } + + public function getUpdateRequestNamespace(string $name) + { + return $this->getRequestNamespace($name); + } + + public function getRequestUses(string $name) + { + return implode("\n", [ + 'use '.$this->getRequestNamespace($name).'\\'.$this->store_request_name($name).';', + 'use '.$this->getRequestNamespace($name).'\\'.$this->update_request_name($name).';', + ]); + } + + public function getRouteNamespace(string $name = '') + { + return $this->getRootNamespace().'Http\\Controllers'; + } + + // ////////////////////////////////////////// + // Language and Presentables // + // ////////////////////////////////////////// + + /** + * Breaks up a string and makes it human readable. + * + * This function assumes that the inputted name is camel case + */ + public function human_readable(string $name): string + { + return Str::title(Str::replace('_', ' ', $name)); + } + + /** + * Breaks up a string and makes it human readable and lowecase. + * + * This function assumes that the inputted name is camel case + */ + public function human_readable_lc(string $name): string + { + return Str::lower($this->human_readable($name)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Replacer/TableReplacer.php Wed Apr 24 20:11:52 2024 -0400 @@ -0,0 +1,81 @@ +<?php + +namespace Wizzard\MagicForger\Replacer; + +trait TableReplacer +{ + protected $columns; + + protected function get_columns() + { + if (is_null($this->columns)) { + $this->columns = $this->getCurrentTable()->getColumns(); + } + + return $this->columns; + } + + protected function get_attributes() + { + } + + protected function getValuesForCreation() + { + $insert = ''; + foreach ($this->get_columns() as $column) { + $insert .= '$item->'.$column->getName().' = $validated["'.$column->getName().'"] ?? NULL;'."\n"; + } + + return $insert; + } + + protected function getAttributes() + { + $insert = ''; + foreach ($this->get_columns() as $column) { + $insert .= "'".$column->getName()."' => '',\n"; + } + + return $insert; + } + + protected function getValuesForValidation() + { + $insert = ''; + foreach ($this->get_columns() as $column) { + $insert .= "'".$column->getName()."' => 'nullable',\n"; + } + + return $insert; + } + + public function apply_inserts(string $target): string + { + $inserts = $this->get_all_keywords($target); + $available_replacements = $this->get_available_inserts(); + + $target = str_replace( + array_keys($available_replacements), + $available_replacements, + $target + ); + + return $target; + } + + public function get_available_inserts() + { + $table_name = $this->getTableInput(); + $replacements = [ + '// {{ valuesForCreation }}' => self::getValuesForCreation(), + '# {{ atributeInsertPoint }}' => self::getAttributes(), + '// {{ valuesForValidation }}' => self::getValuesForValidation(), + ]; + + foreach ($replacements as $key => &$replacement) { + $replacement = $replacement."\n".$key; + } + + return $replacements; + } +}
