|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace Flowra\Console; |
| 4 | + |
| 5 | +use Illuminate\Console\Command; |
| 6 | +use Illuminate\Filesystem\Filesystem; |
| 7 | +use Illuminate\Support\Str; |
| 8 | + |
| 9 | +class MakeAction extends Command |
| 10 | +{ |
| 11 | + protected $signature = 'flowra:make-action |
| 12 | + {name : Action name, e.g. NotifyUser} |
| 13 | + {--path=app/Workflows/Actions : Directory where the action will be created} |
| 14 | + {--namespace=App\\Workflows\\Actions : Namespace for the generated class} |
| 15 | + {--force : Overwrite if the file already exists}'; |
| 16 | + |
| 17 | + protected $description = 'Create a new Flowra action class.'; |
| 18 | + |
| 19 | + public function handle(Filesystem $files): int |
| 20 | + { |
| 21 | + // Normalize name → ensure it ends with "Action" |
| 22 | + $raw = trim($this->argument('name')); |
| 23 | + $studly = Str::studly($raw); |
| 24 | + if (!Str::endsWith($studly, 'Action')) { |
| 25 | + $studly .= 'Action'; |
| 26 | + } |
| 27 | + |
| 28 | + // Resolve paths & namespace |
| 29 | + $basePath = base_path(Str::finish($this->option('path'), '/')); |
| 30 | + $namespace = rtrim($this->option('namespace'), '\\'); |
| 31 | + $filename = $basePath.$studly.'.php'; |
| 32 | + $class = $studly; |
| 33 | + |
| 34 | + if (!$files->isDirectory($basePath)) { |
| 35 | + $files->makeDirectory($basePath, 0777, true); |
| 36 | + } |
| 37 | + |
| 38 | + // Load stub (published first, then package fallback) |
| 39 | + $stub = $this->getStub('action.stub'); |
| 40 | + |
| 41 | + // Render |
| 42 | + $rendered = strtr($stub, [ |
| 43 | + '{{ namespace }}' => $namespace, |
| 44 | + '{{ class }}' => $class, |
| 45 | + ]); |
| 46 | + |
| 47 | + // Write |
| 48 | + if ($files->exists($filename) && !$this->option('force')) { |
| 49 | + $this->warn("⏭ Skipped (exists): {$filename} (use --force to overwrite)"); |
| 50 | + return self::SUCCESS; |
| 51 | + } |
| 52 | + |
| 53 | + $files->put($filename, $rendered); |
| 54 | + $this->info("✅ Action generated: {$namespace}\\{$class}"); |
| 55 | + $this->line(" • Wrote: <info>{$filename}</info>"); |
| 56 | + |
| 57 | + return self::SUCCESS; |
| 58 | + } |
| 59 | + |
| 60 | + private function getStub(string $name): string |
| 61 | + { |
| 62 | + $name = ltrim($name, '/\\'); |
| 63 | + |
| 64 | + // 1) app-published stubs take precedence |
| 65 | + $appStub = base_path('stubs/flowra/'.$name); |
| 66 | + if (is_file($appStub)) { |
| 67 | + $data = file_get_contents($appStub); |
| 68 | + if ($data !== false) { |
| 69 | + return $data; |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + // 2) package default stub (src/stubs/action.stub) |
| 74 | + $packageStub = dirname(__DIR__, 1).'/stubs/'.$name; // __DIR__ = src/Console |
| 75 | + if (is_file($packageStub)) { |
| 76 | + $data = file_get_contents($packageStub); |
| 77 | + if ($data !== false) { |
| 78 | + return $data; |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + throw new \RuntimeException("Stub not found: {$name}\nLooked in:\n - {$appStub}\n - {$packageStub}"); |
| 83 | + } |
| 84 | +} |
0 commit comments