Artisan 控制台
簡介
Artisan 是 laravel 內建的命令列工具介面的名稱。它為應用的開發提供了多種有用的命令工具。Artisan 的底層驅動是強大的 Symfony 控制台組件。你可以使用 list 命令來查看可用的 Artisan 命令:
php artisan list
所有的命令都提供了協助文檔,你可以在相應的命令前使用 help 來查看相關命令的選項和參數:
php artisan help migrate
編寫命令
除了 Artisan 內建的命令之外,laravel 也允許你自行定義自己的命令工具,你可以將自訂的命令工具存放到 app/Console/Commands 目錄下,你當然也可以存放在其他任何想要存放的目錄,只要你所存放的位置能基於 composer.json 的設定進行自動載入就行。
你可以使用 make:console Artisan 命令,來進行新命令工具的產生,這個命令會產生一個命令的樣本來協助你開始:
php artisan make:console SendEmails
上面的命令會產生一個 SendEmails 類,並存放在 app/Console/Commands/SendEmails.php,當你構建命令時,你可以使用 --command 參數來設定命令工具所對應的名稱。
php artisan make:console SendEmails --command=emails:send
命令結構
一旦你的命令被產生,你需要在其中填充 signature 和 description 屬性。這些內容會在你使用 list 命令時在螢幕上顯示。
當你的命令被執行時,會觸發 handle 方法,你可以在這個方法裡編寫相應的命令邏輯。讓我們來看一個命令樣本。
你應該知道我們可以在命令類的建構函式中進行依賴的注入。laravel 服務容器會自動的注入所有在建構函式中使用類型提示的依賴。為了使代碼有更好的重用性,保持控制台命令的輕量,讓它們延遲到應用服務來完成具體的任務是一種很好的實踐。
drip = $drip; } /** * Execute the console command. * * @return mixed */ public function handle() { $this->drip->send(User::find($this->argument('user'))); }}
命令 I/O
定義期望的輸入
當我們編寫命令列工具時,通常都是通過使用者輸入的參數或者選項來收集輸入。laravel 使這一切變的非常簡單。你可以使用 signature 屬性在你的命令中定義你所期望得到的輸入名稱。signature 屬性允許你使用一行富有表現力類路由的文法來定義命令列中的名稱,參數和選項。
所有使用者所提供的參數和選項都被包裹在大括弧內。在下面的樣本中,命令列工具定義了一個必須的參數:user:
/** * The name and signature of the console command. * * @var string */ protected $signature = 'email:send {user}'
你也可以使參數可選,或者為一個可選的參數定義一個預設值:
// Optional argument...email:send {user?}// Optional argument with default value...email:send {user=foo}
選項和參數一樣,它們也是使用者的一種輸入。但是它們在命令列被指定時會使用 -- 作為首碼。我們可以像下面這樣在 signature 中定義選項:
/** * The name and signature of the console command. * * @var string */ protected $signature = 'email:send {user} {--queeue}';
在這個樣本中,--queue 可以在使用 Artisan 命令時被指定。如果指定了 --queque,那麼這個選項的值將會為 true。否則選項的值將為 false:
php artisan emial:send 1 --queue
你也可以通過在選項後面添加 = 號來表明這個選項是需要通過使用者輸入的:
/** * The name and signature of the console command. * * @var string */ protected $signature = 'email:send {user} {--queue=}';
在這個例子中,使用者傳遞一個值到選項像下面這樣:
php artisan email:send 1 --queue=default
你也可以分配一個預設值到選項:
email:send {user} {--queue=default}
你也可以為選項定義一個簡寫,你需要使用 | 來分割簡寫與選項名稱,並將簡寫像下面的樣本一樣前置:
email:send {user} {--Q|queue}
如果你想要定義參數或選項期望得到的是輸入數組,你可以使用 * 萬用字元:
email:send {user*}email:send {user} {--id=*}
輸入說明
你也可以分配描述資訊到選項或者參數中,你需要使用 : 來進行分割描述和選項或參數:
/** * The name and signature of the console command. * * @var string */ protected $signature = 'email:send {user: The ID of the user} {--queue= : Whether the job should be queued}';
檢索輸入
當你的命令工具存在時,你明顯會需要訪問命令列中所期望得到的參數或選項的值。你可以使用 argument 和 option 方法來得到:
/** * Execute the console command. * * @return mixed */ public function handle() { $userId = $this->argument('user'); }
你可以通過調用不帶參數的 argument 方法來擷取所有參數所組成的數組:
$arguments = $this->argument();
選項可以非常簡單的類似參數一樣的通過 option 方法進行檢索。選項可以像參數那樣當調用無參數的 option 方法時返回所有選項所組成的數組:
// Retrieve a specific option...$queueName = $this->option('queue');// Retrieve all options...$options = $this->option();
如果相應的參數或選項沒有被檢索到,會返回 null。
為輸入進行提示
除了顯示輸出之外,你可能也需要在執行你的命令列工具的過程中向使用者索求額外的輸入。你可以使用 ask 方法來進行提示使用者輸入,這個方法將接收使用者的輸入並返回輸入的內容:
/** * Execute the console command. * * @return mixed */ public function handle() { $name = $this->ask('What is your name?'); }
secret 方法與 ask 方法非常相似,只是使用者在控制台中輸入的內容並不是可見的。這個方法通常是詢問使用者密碼相關時使用的:
$password = $this->secret('What is the password?');
要求確認
如果你只是需要使用者的確認,你可以使用 confirm 方法。預設的,該方法返回 false. 但是如果使用者在響應中輸入了 y,該方法將返回 true.
if ($this->confirm('Do you wish to continue? [y|N]')) { //}
給使用者一個選擇
anticipate 方法可以用來對可選的內容進行自動完成的提示。這裡只是對使用者有可能選擇的內容進行自動完成提示,並非強制要求使用者僅選擇可選的內容:
$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);
如果你需要給使用者預置選項你可以使用 choice 方法。使用者必須選中選項中的索引,使用者選中相應的索引的答案的值將會被返回。你可以設定一個預設的索引值,這個索引值將在使用者沒有做出任何選擇時返回:
$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $default);
編寫輸出
你可以使用 line,info,comment,question 和 error 方法發送輸出到控制台。這些方法會使用相應的 ANSI 顏色來表明相應的目的。
你可以使用 info 方法來向使用者顯示一個資訊訊息。通常,這條訊息在控制台中是一個綠色的文本:
/** * Execute the console command. * * @return mixed */ public function handle() { $this->info('Display this on the screen'); }
你可以使用 error 方法來顯示一個錯誤訊息。錯誤訊息通常都是紅色的:
$this->error('Something went wrong!');
你可以使用 line 方法來顯示一個原生的控制台輸出。line 方法並沒有對訊息設定任何的獨特顏色資訊:
$this->line('Display thie on the screen');
表格版面配置
你可以使用 table 方法來簡單的對多行或多列的資料進行格式化布局。你只需要向方法中傳遞標頭部和行資訊到方法中就可以了。寬度和高度將會自動的通過所給定的資料進行計算:
$headers = ['Name', 'Email']; $users = App\User::all(['name', 'email'])->toArray(); $this->table($headers, $users);
進度條
對於一些耗時的任務來說,有一個進度提示是非常有用的。如果使用輸出對象,我們就可以開始,推進和停止進度條。你需要在你開始進度條之前定義步長。然後根據進行的每一步來推進進度條:
$user = App\User::all();$bar = $this->output->createProgressBar(count($users));foreach ($users as $user) { $this->performTask($user); $bar->advance();}$bar->finish();
你可以通過查看 Symfony Progress Bar component documentation 來擷取更多的選項資訊。
註冊命令列
一旦你完成了命令列的編寫,你還需要註冊其在 Artisan 命令中可用。這些需要在 app/Console/Kernel.php 檔案中完成。
在這個檔案中,你會發現 commands 屬性,它是一個命令列類的列表。當 Artisan 啟動時,所有在這個列表中的命令都會通過服務容器解析到 Arisan:
protected $commands = [ Commands\SendEmails::class];
通過代碼調用命令
有時候你可能希望在控制台之外執行 Artisan 命令。比如,你希望在控制器的路由中觸發 Artisan 命令。你可以使用 Artisan 假面的 call 方法來完成這些。call 方法接收一個命令名稱,和一個包含所有參數和選項所組成的數組,命令執行完成之後會返回一個結束代碼:
Route::get('/foo', function () { $exitCode = Artisan::call('email:send', [ 'user' => 1, '--queue' => 'default' ]); //});
通過使用 Artisan 假面的 queue 方法,你甚至可以隊列化 Artisan 命令,在後台進程中隊列工人會按序的幫你執行完成命令:
Route::get('/foo', function () { Artisan::queue('email:send', [ 'user' => 1, '--queue' => 'default' ]); //})
如果你需要強制指定一個不接受字串值的選項的值為一個字串,就像 migrate:refresh 命令,你可以使用 --force 標識並傳遞一個布爾值:
$exitCode = Artisan::call('migrate:refresh', [ '--force' => true,]);
在命令列中調用另外的命令
有時候,你可能希望在命令列工具中調用另外一個已經存在的 Artisan 命令。你可以使用 call 方法來完成這些。call 方法接收命令的名稱和一個包含所有參數和選項的數組:
/** * Execute the console command. * * @return mixed */ public function handle() { $this->call('email:send', [ 'user' => 1, '--queue' => 'default' ]); // }
如果你希望調用另外一個控制台命令而不希望它有任何的輸出,你可以使用 callSilent 方法,callSilent 方法具有 call 方法相同的調用方式:
$this->callSilent('email:send', [ 'user' => 1, '--queue' => 'default']);