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 }