Larvel透過GeneratorCommand使用artisan產出php執行檔
基本概念
將原始碼寫在.stub檔中,內容中如果有需要替換的則使用{{ }} 標記,例如 namespace {{ namespace }};
GeneratoreCommand會讀出.stub檔案將需要替換的文字替換完成後依照namespace寫入.php檔案
幾個需要理解的method與參數
首先參數的部分,固定第一個為name,也就是要產出的檔案名稱
1 |
php artisan GeneratorCommand {name} |
method: getStub()
1 |
protected function getStub(): string |
需要return .stub檔案的路徑,如果.stub檔案在vendor資料夾中則可以透過上篇說明來取得package中的檔案
範例可以像這樣子,class中依照上一篇說明定義好get_file_path後,就可以找到指定的Vendor\package\路徑下的檔案了
如果是在同一個專案目錄中,則直接return專案中路徑即可
1 2 3 4 |
protected function getStub(): string { return $this->get_file_path("/http/Controllers"); } |
method: getDefaultNamespace()
1 |
protected function getDefaultNamespace($rootNamespace): string |
需要return 產出php檔正確擺放位置的namespace,例如
1 2 3 4 |
protected function getDefaultNamespace($rootNamespace): string { return $rootNamespace . "\Http\\Controllers"; } |
這樣子就會把產出的php檔案放在app\Http\Controllers中
method: getNameInput()
1 |
protected function getNameInput(): string |
return值作為檔案的名稱,也就是return command第一個參數name就行了,通常會把class name做大駝峰處理,範例如下
1 2 3 4 |
protected function getNameInput(): string { return Str::studly(trim($this->argument('name'))); } |
method: buildClass()
1 |
protected function buildClass($name): array|string |
如果產出的php檔沒有其他需要替換的標記,或者沒有其他邏輯需要處理是可以不必處理buildClass()這個method,這邊提供一個範例
把stub內容中多組tag紀錄在$this->replace_tags中,然後再buildClass method中替換掉他
1 2 3 4 5 6 7 8 9 10 11 12 |
protected function buildClass($name): array|string { $stub = $this->files->get($this->getStub()); $namespace = $this->replaceNamespace($stub, $name)->replaceClass($stub, $name); $replacedStub = $namespace; foreach ($this->replace_tags as $tag => $text){ $replacedStub = str_replace("{{ {$tag} }}", $text, $replacedStub); } return $replacedStub; } |
method: handle()
1 |
public function handle(): ?bool |
如果在產出檔案前,有需要對class的其他參數做調整,可以複寫handle() method,記得最後要return parent::handle()就好
例如像這樣
1 2 3 4 5 6 |
public function handle(): ?bool { #你想要的內容寫在這裡 return parent::handle(); // TODO: Change the autogenerated stub } |
method: interact()
1 |
protected function interact(InputInterface $input, OutputInterface $output) |
假設需要對輸入的參數做一些調整,可以透過複寫interact來達成,下面的範例處理了name參數,讓他變成首字大寫
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * Override * 重新處理name參數 */ protected function interact(InputInterface $input, OutputInterface $output) { parent::interact($input, $output); if ($input->hasArgument('name')) { $name = implode('/',array_map('ucfirst',explode('/',$input->getArgument('name')))); $input->setArgument('name',$name); } } |
最後提供一個完整範例
將virtualorz\mysdk中的 Stuns/http/controllers.stub 生成 /app/Http/Controllers/CustomerController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#command.php <?php namespace App\Console\Commands; use Illuminate\Console\GeneratorCommand; use Illuminate\Support\Str; class MakeCustomerController extends GeneratorCommand { protected $name = 'make:my-controller'; protected $description = 'Create my controller class'; protected string $stub_path = 'http/ClassController'; protected string $target_path = '\Http\\Controllers'; protected array $replace_tags = ['use_string'=>'use App\Services\Config\ConfigService']; protected function getStub(): string { return $this->get_file_path($this->stub_path); } protected function getDefaultNamespace($rootNamespace): string { return $rootNamespace . $this->target_path; } protected function getNameInput(): string { return Str::studly(trim($this->argument('name'))); } protected function buildClass($name): array|string { $stub = $this->files->get($this->getStub()); $namespace = $this->replaceNamespace($stub, $name)->replaceClass($stub, $name); $replacedStub = $namespace; foreach ($this->replace_tags as $tag => $text){ $replacedStub = str_replace("{{ {$tag} }}", $text, $replacedStub); } return $replacedStub; } protected function get_file_path($path): string { $loader = $this->_getClassLoader(); $psr4 = $loader->getPrefixesPsr4(); $namespace = 'virtualorz\\mysdk\\'; $stubFilename = "Stubs/{$path}.stub"; // Stub 檔案名稱 $stub_path_location = ''; foreach ($psr4 as $prefix => $paths) { if (str_starts_with($namespace, $prefix)) { foreach ($paths as $path) { // 處理多個路徑 $relativePath = str_replace($prefix, '', $namespace); $relativePath = str_replace('\\', '/', $relativePath); $stubPath = $path . '/' . $relativePath . $stubFilename; if (file_exists($stubPath)) { $stub_path_location = $stubPath; } } } } return $stub_path_location; } protected function _getClassLoader() { return require base_path('vendor/autoload.php'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
Controllers.stub <?php namespace {{ namespace }}; {{ use_string }} class {{ class }} extends Controller { }值 |
執行命令
1 |
php artisan make:my-controller CustomerController |