Mercurial > packages > magicforger
comparison src/Generator/BaseGenerator.php @ 34:f65ab84ee47f default
merge with codex
| author | luka |
|---|---|
| date | Wed, 10 Sep 2025 21:00:47 -0400 |
| parents | 555bfaa500ac |
| children |
comparison
equal
deleted
inserted
replaced
| 10:a9ff874afdbd | 34:f65ab84ee47f |
|---|---|
| 1 <?php | 1 <?php |
| 2 | 2 |
| 3 namespace Wizzard\MagicForger\Generator; | 3 namespace Wizard\MagicForger\Generator; |
| 4 | 4 |
| 5 use DB; | |
| 6 use Illuminate\Console\GeneratorCommand; | 5 use Illuminate\Console\GeneratorCommand; |
| 6 use Illuminate\Support\Facades\Schema; | |
| 7 use Symfony\Component\Console\Input\InputInterface; | 7 use Symfony\Component\Console\Input\InputInterface; |
| 8 use Symfony\Component\Console\Input\InputOption; | 8 use Symfony\Component\Console\Input\InputOption; |
| 9 use Symfony\Component\Console\Output\OutputInterface; | 9 use Symfony\Component\Console\Output\OutputInterface; |
| 10 use Wizzard\MagicForger\Replacer\Replacer; | 10 use Wizard\MagicForger\Replacer\Replacer; |
| 11 use Wizzard\MagicForger\Replacer\TableReplacer; | 11 use Wizard\MagicForger\Replacer\TableReplacer; |
| 12 | 12 |
| 13 abstract class BaseGenerator extends GeneratorCommand | 13 abstract class BaseGenerator extends GeneratorCommand |
| 14 { | 14 { |
| 15 use Replacer; | 15 use Replacer; |
| 16 use TableReplacer; | 16 use TableReplacer; |
| 17 | 17 |
| 18 /** | 18 protected $schema = null; |
| 19 * The schema of the database. | 19 |
| 20 * | 20 protected $tables = null; |
| 21 * @var string | 21 |
| 22 */ | 22 protected $currentTable = null; |
| 23 protected $schema; | 23 |
| 24 | 24 protected static $cached_snippets = []; |
| 25 /** | 25 |
| 26 * The tables available in the schema. | |
| 27 * | |
| 28 * @var array | |
| 29 */ | |
| 30 protected $tables; | |
| 31 | |
| 32 /** | |
| 33 * The current Table being used. | |
| 34 * | |
| 35 * @var table | |
| 36 */ | |
| 37 protected $currentTable; | |
| 38 | |
| 39 /** | |
| 40 * Execute the console command. | |
| 41 */ | |
| 42 public function handle() | 26 public function handle() |
| 43 { | 27 { |
| 44 // First we need to ensure that the table exists, then we can | 28 |
| 45 if (!$this->tableExists($this->getTableInput())) { | 29 if (! $this->tableExists($this->getTableInput())) { |
| 46 $this->components->error('The table: "'.$this->getTableInput().'" does not exist in the database.'); | 30 $this->components->error('The table: "'.$this->getTableInput().'" does not exist in the database.'); |
| 47 | 31 |
| 48 return false; | 32 return false; |
| 49 } | 33 } |
| 50 | 34 |
| 51 $this->setCurrentTable($this->getTableInput()); | 35 $this->setCurrentTable($this->getTableInput()); |
| 52 | |
| 53 $path = $this->getPath(); | 36 $path = $this->getPath(); |
| 54 | |
| 55 $file = $this->getFile($path); | 37 $file = $this->getFile($path); |
| 56 | |
| 57 $file = $this->apply_replacements($file); | 38 $file = $this->apply_replacements($file); |
| 58 | |
| 59 $file = $this->apply_inserts($file); | 39 $file = $this->apply_inserts($file); |
| 60 | |
| 61 $this->makeDirectory($path); | 40 $this->makeDirectory($path); |
| 62 | |
| 63 $this->files->put($path, $this->sortImports($file)); | 41 $this->files->put($path, $this->sortImports($file)); |
| 64 | |
| 65 $this->format_file($path); | 42 $this->format_file($path); |
| 66 | 43 $this->components->info(sprintf('%s [%s] created successfully.', $this->type, $path)); |
| 67 $info = $this->type; | 44 } |
| 68 | 45 |
| 69 $this->components->info(sprintf('%s [%s] created successfully.', $info, $path)); | 46 protected function promptForMissingArguments(InputInterface $input, OutputInterface $output): void |
| 70 } | |
| 71 | |
| 72 /** | |
| 73 * Override the original so that we can prompt for a table with autocomplete. | |
| 74 */ | |
| 75 protected function promptForMissingArguments(InputInterface $input, OutputInterface $output) | |
| 76 { | 47 { |
| 77 $prompted = false; | 48 $prompted = false; |
| 78 if (is_null($input->getArgument('table'))) { | 49 if (is_null($input->getArgument('table'))) { |
| 79 $prompted = true; | 50 $prompted = true; |
| 80 $table = null; | 51 $table = null; |
| 81 while (null === $table) { | 52 while ($table === null) { |
| 82 $table = $this->components->askWithCompletion( | 53 $table = $this->components->askWithCompletion( |
| 83 'What Table should we use?', | 54 'What Table should we use?', |
| 84 $this->possibleTables() | 55 $this->possibleTables() |
| 85 ); | 56 ); |
| 86 } | 57 } |
| 87 | |
| 88 $input->setArgument('table', $table); | 58 $input->setArgument('table', $table); |
| 89 } | 59 } |
| 90 | 60 |
| 91 parent::promptForMissingArguments($input, $output); | 61 parent::promptForMissingArguments($input, $output); |
| 92 | 62 |
| 93 // This will get missed if we prompt here but not in the parent | |
| 94 if ($prompted) { | 63 if ($prompted) { |
| 95 $this->afterPromptingForMissingArguments($input, $output); | 64 $this->afterPromptingForMissingArguments($input, $output); |
| 96 } | 65 } |
| 97 } | 66 } |
| 98 | 67 |
| 99 /** | 68 protected function getArguments(): array |
| 100 * Get the console command arguments. | |
| 101 * | |
| 102 * @return array | |
| 103 */ | |
| 104 protected function getArguments() | |
| 105 { | 69 { |
| 106 return [ | 70 return [ |
| 107 ['table', InputOption::VALUE_REQUIRED, 'The table to generate files for.'], | 71 ['table', InputOption::VALUE_REQUIRED, 'The table to generate files for.'], |
| 108 ]; | 72 ]; |
| 109 } | 73 } |
| 110 | 74 |
| 111 /** | 75 protected function promptForMissingArgumentsUsing(): array |
| 112 * Prompt for missing input arguments using the returned questions. | 76 { |
| 113 * | 77 return []; |
| 114 * @return array | 78 } |
| 115 */ | 79 |
| 116 protected function promptForMissingArgumentsUsing() | 80 protected function getOptions(): array |
| 117 { | |
| 118 return [ | |
| 119 ]; | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Get the console command options. | |
| 124 * | |
| 125 * @return array | |
| 126 */ | |
| 127 protected function getOptions() | |
| 128 { | 81 { |
| 129 return [ | 82 return [ |
| 130 ['fresh', 'f', InputOption::VALUE_NONE, 'Start from the stub or use existing if possible.'], | 83 ['fresh', 'f', InputOption::VALUE_NONE, 'Start from the stub or use existing if possible.'], |
| 131 ]; | 84 ]; |
| 132 } | 85 } |
| 133 | 86 |
| 134 /** | 87 protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output): void |
| 135 * Interact further with the user if they were prompted for missing arguments. | 88 { |
| 89 // Additional logic after prompting goes here | |
| 90 } | |
| 91 | |
| 92 protected function fileExists(string $path): bool | |
| 93 { | |
| 94 return $this->files->exists($path); | |
| 95 } | |
| 96 | |
| 97 protected function getFile($name): string | |
| 98 { | |
| 99 if (! ($this->hasOption('fresh') && $this->option('fresh')) && $this->fileExists($name)) { | |
| 100 return $this->files->get($name); | |
| 101 } | |
| 102 | |
| 103 return $this->files->get($this->getStub()); | |
| 104 } | |
| 105 | |
| 106 protected function getTableInput(): string | |
| 107 { | |
| 108 return trim($this->argument('table')); | |
| 109 } | |
| 110 | |
| 111 protected function tableExists(string $table_name): bool | |
| 112 { | |
| 113 return in_array($table_name, $this->getTables()); | |
| 114 } | |
| 115 | |
| 116 protected function possibleTables(): array | |
| 117 { | |
| 118 return $this->getTables(); | |
| 119 } | |
| 120 | |
| 121 protected function getTables(): array | |
| 122 { | |
| 123 if (is_null($this->tables)) { | |
| 124 $this->tables = Schema::getTableListing(schema: config('database.connections.mariadb.database'), schemaQualified: false); | |
| 125 } | |
| 126 | |
| 127 return $this->tables; | |
| 128 } | |
| 129 | |
| 130 protected function getTable(string $table_name) | |
| 131 { | |
| 132 return $this->getSchema()->introspectTable($table_name); | |
| 133 } | |
| 134 | |
| 135 /* | |
| 136 * returns array of columns in the form of: | |
| 136 * | 137 * |
| 137 * @return void | 138 [ |
| 139 "name" => "column_type" | |
| 140 "type_name" => "bigint" | |
| 141 "type" => "bigint(20) unsigned" | |
| 142 "collation" => null | |
| 143 "nullable" => true | |
| 144 "default" => "NULL" | |
| 145 "auto_increment" => false | |
| 146 "comment" => null | |
| 147 "generation" => null | |
| 148 ] | |
| 149 */ | |
| 150 protected static function getTableColumns(string $table_name) | |
| 151 { | |
| 152 return Schema::getColumns($table_name); | |
| 153 } | |
| 154 | |
| 155 /* | |
| 156 * returns array of foreign keys in the form of: | |
| 157 * | |
| 158 [ | |
| 159 "name" => "foreign_key_name" | |
| 160 "columns" => [ | |
| 161 0 => "local_column_name" | |
| 162 ] | |
| 163 "foreign_schema" => "schema_name" | |
| 164 "foreign_table" => "foreign_table_name" | |
| 165 "foreign_columns" => [ | |
| 166 0 => "foreign_column_name" | |
| 167 ] | |
| 168 "on_update" => "restrict" | |
| 169 "on_delete" => "restrict" | |
| 170 ] | |
| 171 * | |
| 138 */ | 172 */ |
| 139 protected function afterPromptingForMissingArguments(InputInterface $input, OutputInterface $output) | 173 protected static function getTableForeignKeys(string $table_name) |
| 140 { | 174 { |
| 141 } | 175 return Schema::getForeignKeys($table_name); |
| 142 | |
| 143 /** | |
| 144 * Determines if the file exists. | |
| 145 */ | |
| 146 protected function fileExists(string $path): bool | |
| 147 { | |
| 148 return $this->files->exists($path); | |
| 149 } | |
| 150 | |
| 151 /** | |
| 152 * Gets the file that will be worked on. If there is already an existing file | |
| 153 * then we can open that. However if we are forcing the operation, then we | |
| 154 * will start with an empty stub. | |
| 155 */ | |
| 156 protected function getFile($name) | |
| 157 { | |
| 158 if (!($this->hasOption('fresh') | |
| 159 && $this->option('fresh')) | |
| 160 && $this->fileExists($name)) { | |
| 161 // Working with an existing file | |
| 162 return $this->files->get($name); | |
| 163 } | |
| 164 | |
| 165 // Working with a stub | |
| 166 return $this->files->get($this->getStub()); | |
| 167 } | |
| 168 | |
| 169 /** | |
| 170 * Get the desired class table from the input. | |
| 171 * | |
| 172 * @return string | |
| 173 */ | |
| 174 protected function getTableInput() | |
| 175 { | |
| 176 return trim($this->argument('table')); | |
| 177 } | |
| 178 | |
| 179 /** | |
| 180 * Determines if the table exists in the current database. | |
| 181 */ | |
| 182 protected function tableExists(string $table_name): bool | |
| 183 { | |
| 184 return in_array($table_name, $this->getTables()); | |
| 185 } | |
| 186 | |
| 187 /** | |
| 188 * Get a list of possible table names. | |
| 189 */ | |
| 190 protected function possibleTables() | |
| 191 { | |
| 192 return $this->getTables(); | |
| 193 } | |
| 194 | |
| 195 /** | |
| 196 * Get the tables in the schema. | |
| 197 */ | |
| 198 protected function getTables() | |
| 199 { | |
| 200 if (is_null($this->tables)) { | |
| 201 $this->tables = collect($this->getSchema()->listTableNames())->all(); | |
| 202 } | |
| 203 | |
| 204 return $this->tables; | |
| 205 } | |
| 206 | |
| 207 /** | |
| 208 * Get the database schema for DB interactions. | |
| 209 */ | |
| 210 protected function getSchema() | |
| 211 { | |
| 212 if (is_null($this->schema)) { | |
| 213 $this->schema = \DB::connection()->getDoctrineSchemaManager(); | |
| 214 } | |
| 215 | |
| 216 return $this->schema; | |
| 217 } | |
| 218 | |
| 219 protected function getTable(string $table_name) | |
| 220 { | |
| 221 return $this->getSchema()->introspectTable($table_name); | |
| 222 } | 176 } |
| 223 | 177 |
| 224 protected function getCurrentTable() | 178 protected function getCurrentTable() |
| 225 { | 179 { |
| 226 return $this->currentTable; | 180 return $this->currentTable; |
| 227 } | 181 } |
| 228 | 182 |
| 229 protected function setCurrentTable(string $table_name) | 183 protected function setCurrentTable(string $table_name): void |
| 230 { | 184 { |
| 231 $table = null; | 185 $this->currentTable = $table_name; |
| 232 if (!is_null($table_name) && '' !== trim($table_name)) { | 186 } |
| 233 $table = $this->getTable($table_name); | 187 |
| 234 } | 188 protected function format_file(string $path): void |
| 235 $this->currentTable = $table; | 189 { |
| 236 } | 190 exec('./vendor/bin/pint '.escapeshellarg($path)); |
| 237 | 191 } |
| 238 protected function format_file(string $path) | 192 |
| 239 { | 193 protected function getSnippet($snippet_name) |
| 240 exec('php-cs-fixer fix '.$path); | 194 { |
| 195 // Cache snippet contents to avoid re-reading files | |
| 196 if (! isset(self::$cached_snippets[$snippet_name])) { | |
| 197 self::$cached_snippets[$snippet_name] = $this->files->get( | |
| 198 $this->resolveStubPath("/snippets/$snippet_name.stub")); | |
| 199 } | |
| 200 | |
| 201 return self::$cached_snippets[$snippet_name]; | |
| 241 } | 202 } |
| 242 } | 203 } |
