1: | <?php |
2: | |
3: | namespace Aurora\System\Console\Commands; |
4: | |
5: | use Aurora\System\Api; |
6: | use Illuminate\Filesystem\Filesystem; |
7: | use Illuminate\Support\Str; |
8: | use Symfony\Component\Console\Command\Command; |
9: | use Symfony\Component\Console\Input\InputInterface; |
10: | use Symfony\Component\Console\Output\OutputInterface; |
11: | |
12: | abstract class GeneratorCommand extends Command |
13: | { |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | protected $files; |
20: | |
21: | |
22: | |
23: | |
24: | |
25: | |
26: | protected $type; |
27: | |
28: | |
29: | |
30: | |
31: | |
32: | |
33: | protected $reservedNames = [ |
34: | '__halt_compiler', |
35: | 'abstract', |
36: | 'and', |
37: | 'array', |
38: | 'as', |
39: | 'break', |
40: | 'callable', |
41: | 'case', |
42: | 'catch', |
43: | 'class', |
44: | 'clone', |
45: | 'const', |
46: | 'continue', |
47: | 'declare', |
48: | 'default', |
49: | 'die', |
50: | 'do', |
51: | 'echo', |
52: | 'else', |
53: | 'elseif', |
54: | 'empty', |
55: | 'enddeclare', |
56: | 'endfor', |
57: | 'endforeach', |
58: | 'endif', |
59: | 'endswitch', |
60: | 'endwhile', |
61: | 'eval', |
62: | 'exit', |
63: | 'extends', |
64: | 'final', |
65: | 'finally', |
66: | 'fn', |
67: | 'for', |
68: | 'foreach', |
69: | 'function', |
70: | 'global', |
71: | 'goto', |
72: | 'if', |
73: | 'implements', |
74: | 'include', |
75: | 'include_once', |
76: | 'instanceof', |
77: | 'insteadof', |
78: | 'interface', |
79: | 'isset', |
80: | 'list', |
81: | 'namespace', |
82: | 'new', |
83: | 'or', |
84: | 'print', |
85: | 'private', |
86: | 'protected', |
87: | 'public', |
88: | 'require', |
89: | 'require_once', |
90: | 'return', |
91: | 'static', |
92: | 'switch', |
93: | 'throw', |
94: | 'trait', |
95: | 'try', |
96: | 'unset', |
97: | 'use', |
98: | 'var', |
99: | 'while', |
100: | 'xor', |
101: | 'yield', |
102: | ]; |
103: | |
104: | |
105: | |
106: | |
107: | |
108: | |
109: | |
110: | public function __construct(Filesystem $files) |
111: | { |
112: | parent::__construct(); |
113: | |
114: | $this->files = $files; |
115: | } |
116: | |
117: | |
118: | |
119: | |
120: | |
121: | |
122: | abstract protected function getStub(); |
123: | |
124: | |
125: | |
126: | |
127: | |
128: | |
129: | |
130: | |
131: | protected function execute(InputInterface $input, OutputInterface $output): int |
132: | { |
133: | |
134: | |
135: | |
136: | if ($this->isReservedName($this->getNameInput($input))) { |
137: | $output->writeln('The name "' . $this->getNameInput($input) . '" is reserved by PHP.'); |
138: | |
139: | return false; |
140: | } |
141: | |
142: | $name = $this->qualifyClass($this->getNameInput($input)); |
143: | |
144: | $path = $this->getPath($name); |
145: | |
146: | |
147: | |
148: | |
149: | if ((!$input->hasOption('force') || |
150: | !$input->getOption('force')) && |
151: | $this->alreadyExists($this->getNameInput($input))) { |
152: | $output->writeln('Seed already exists!'); |
153: | |
154: | return false; |
155: | } |
156: | |
157: | |
158: | |
159: | |
160: | $this->makeDirectory($path); |
161: | |
162: | $this->files->put($path, $this->sortImports($this->buildClass($name))); |
163: | |
164: | $output->writeln('Seed created successfully.'); |
165: | |
166: | return true; |
167: | } |
168: | |
169: | |
170: | |
171: | |
172: | |
173: | |
174: | |
175: | protected function qualifyClass($name) |
176: | { |
177: | $name = ltrim($name, '\\/'); |
178: | |
179: | $rootNamespace = Api::RootPath(); |
180: | |
181: | if (Str::startsWith($name, $rootNamespace)) { |
182: | return $name; |
183: | } |
184: | |
185: | $name = str_replace('/', '\\', $name); |
186: | |
187: | return $this->qualifyClass( |
188: | $this->getDefaultNamespace(trim($rootNamespace, '\\')) . '\\' . $name |
189: | ); |
190: | } |
191: | |
192: | |
193: | |
194: | |
195: | |
196: | |
197: | |
198: | protected function getDefaultNamespace($rootNamespace) |
199: | { |
200: | return $rootNamespace; |
201: | } |
202: | |
203: | |
204: | |
205: | |
206: | |
207: | |
208: | |
209: | protected function alreadyExists($rawName) |
210: | { |
211: | return $this->files->exists($this->getPath($this->qualifyClass($rawName))); |
212: | } |
213: | |
214: | |
215: | |
216: | |
217: | |
218: | |
219: | |
220: | |
221: | protected function getPath($name) |
222: | { |
223: | return \Aurora\Api::RootPath() . 'seeds' . DIRECTORY_SEPARATOR . str_replace('\\', '/', $name) . '.php'; |
224: | } |
225: | |
226: | |
227: | |
228: | |
229: | |
230: | |
231: | |
232: | protected function makeDirectory($path) |
233: | { |
234: | if (!$this->files->isDirectory(dirname($path))) { |
235: | $this->files->makeDirectory(dirname($path), 0777, true, true); |
236: | } |
237: | |
238: | return $path; |
239: | } |
240: | |
241: | |
242: | |
243: | |
244: | |
245: | |
246: | |
247: | |
248: | |
249: | protected function buildClass($name) |
250: | { |
251: | $stub = $this->files->get($this->getStub()); |
252: | |
253: | return $this->replaceNamespace($stub, $name)->replaceClass($stub, $name); |
254: | } |
255: | |
256: | |
257: | |
258: | |
259: | |
260: | |
261: | |
262: | |
263: | protected function replaceNamespace(&$stub, $name) |
264: | { |
265: | $searches = [ |
266: | ['DummyNamespace', 'DummyRootNamespace', 'NamespacedDummyUserModel'], |
267: | ['{{ namespace }}', '{{ rootNamespace }}', '{{ namespacedUserModel }}'], |
268: | ['{{namespace}}', '{{rootNamespace}}', '{{namespacedUserModel}}'], |
269: | ]; |
270: | |
271: | foreach ($searches as $search) { |
272: | $stub = str_replace( |
273: | $search, |
274: | [$this->getNamespace($name)], |
275: | $stub |
276: | ); |
277: | } |
278: | |
279: | return $this; |
280: | } |
281: | |
282: | |
283: | |
284: | |
285: | |
286: | |
287: | |
288: | protected function getNamespace($name) |
289: | { |
290: | return trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\'); |
291: | } |
292: | |
293: | |
294: | |
295: | |
296: | |
297: | |
298: | |
299: | |
300: | protected function replaceClass($stub, $name) |
301: | { |
302: | $class = str_replace($this->getNamespace($name) . '\\', '', $name); |
303: | |
304: | return str_replace(['DummyClass', '{{ class }}', '{{class}}'], $class, $stub); |
305: | } |
306: | |
307: | |
308: | |
309: | |
310: | |
311: | |
312: | |
313: | protected function sortImports($stub) |
314: | { |
315: | if (preg_match('/(?P<imports>(?:use [^;]+;$\n?)+)/m', $stub, $match)) { |
316: | $imports = explode("\n", trim($match['imports'])); |
317: | |
318: | sort($imports); |
319: | |
320: | return str_replace(trim($match['imports']), implode("\n", $imports), $stub); |
321: | } |
322: | |
323: | return $stub; |
324: | } |
325: | |
326: | |
327: | |
328: | |
329: | |
330: | |
331: | protected function getNameInput(InputInterface $input) |
332: | { |
333: | return trim($input->getArgument('name')); |
334: | } |
335: | |
336: | |
337: | |
338: | |
339: | |
340: | |
341: | |
342: | protected function isReservedName($name) |
343: | { |
344: | $name = strtolower($name); |
345: | |
346: | return in_array($name, $this->reservedNames); |
347: | } |
348: | } |
349: | |