Artisan 指令列
介紹
Artisan 是 Laravel 裡的一個指令列介面的名稱。當你在開發你的應用程式時,它提供了許多有用的指令來幫助你開發。它是基於由強大的 Symfony Console 元件來的。你可以使用 list
指令來列出所有可以使用的 Artisan 指令:
php artisan list
每個指令也包含了「help」畫面,它會顯示並敘述指令可以使用的參數及選項。在指令前面加上 help
即可顯示:
php artisan help migrate
撰寫指令
除了使用 Artisan 本身提供的指令外,你也可以建立自定的指令來進行作業。你可以將你的自定指令放在 app/Console/Commands
目錄下;當然,只要指令可以基於 composer.json
的設定自動載入,你可以自由選擇想要放置的地方。
要建立新的指令,可以使用 make:console
Artisan 指令產生一個預設的腳本來作為起頭:
php artisan make:console SendEmails
上面的這個指令會在 app/Console/Commands/SendEmails.php
建立一個類別。當建立指令時,--command
這個選項可以用來指定要使用的終端指令名稱:
php artisan make:console SendEmails --command=emails:send
指令結構
建立指令後,你應該填寫類別的 signature
和 description
這兩個屬性,它們會被顯示在 list
畫面:
當指令被執行的時候,handle
方法會被呼叫,因此你可以將任何的指令邏輯放置在這個方法中,讓我們來看看一個範例。
注意我們可以在建構子中注入任何需要的依賴,Laravel 的服務容器將會自動注入任何型別提示的依賴到建構子中。為了更好的程式碼重用性,保持指令內容 輕量,並利用應用程式服務緩載來完成任務是一個好的實作方式。
<?php
namespace App\Console\Commands;
use App\User;
use App\DripEmailer;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* 指令列的名稱及用法。
*
* @var string
*/
protected $signature = 'email:send {user}';
/**
* 指令列的敘述。
*
* @var string
*/
protected $description = 'Send drip e-mails to a user';
/**
* drip e-mail 服務。
*
* @var DripEmailer
*/
protected $drip;
/**
* 創造新的指令實例。
*
* @param DripEmailer $drip
* @return void
*/
public function __construct(DripEmailer $drip)
{
parent::__construct();
$this->drip = $drip;
}
/**
* 執行指令。
*
* @return mixed
*/
public function handle()
{
$this->drip->send(User::find($this->argument('user')));
}
}
指令的輸入與輸出
定義預期的輸入
撰寫指令列時,經由參數或是選項取得使用者的輸入是很常見的。藉由使用指令的 signature
屬性,Laravel 讓你很方便的定義預期從使用者得到的輸入。signature
屬性允許你用單一、具表現力、與路由相似的語法,並用以定義指令的名字、參數及選項。
所有提供給使用者的參數及選項都在包在大括號中。如下方範例,此指令定義一個必須的參數:user
:
/**
* 指令列的名稱及用法。
*
* @var string
*/
protected $signature = 'email:send {user}';
你也可以使用讓參數是可選的並定義預設的值:
// 可選的的參數...
email:send {user?}
// 可選的的參數及預設的值...
email:send {user=foo}
選項,就跟參數一樣,也是一種使用者輸入,不過使用選項時,需要在選項名稱前加入兩個連字符號(--
),我們可以在 signature 中這樣定義選項:
/**
* 指令列的名稱及用法。
*
* @var string
*/
protected $signature = 'email:send {user} {--queue}';
在這個範例中,當呼叫 Artisan 指令時,--queue
這個選項可以被明確的指定。如果 --queue
被當成輸入時,這個選項的值會是 true
,如果沒有指定時,這個選項的值將會是 false
:
php artisan email:send 1 --queue
你也可以在選項後面加上 =
,表示選項需要明確指定值:
/**
* 指令列的名稱及用法。
*
* @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=*}
輸入的敘述
藉由加入冒號及敘述,你也可以為輸入參數及選項加上敘述:
/**
* 指令列的名稱及用法。
*
* @var string
*/
protected $signature = 'email:send
{user : 使用者的 ID }
{--queue= : 這個工作是否該進入隊列}';
取得輸入
執行指令時,你會需要取得接收的參數及選項。為了達到這個目的,你會需要使用 argument
及 option
方法:
/**
* 執行這個指令列。
*
* @return mixed
*/
public function handle()
{
$userId = $this->argument('user');
//
}
如果你需要將所有的參數匯聚成一個陣列
,只要不加參數呼叫 argument
即可:
$arguments = $this->argument();
而取得選項就跟參數一樣簡單,除了使用的方法變為 option
。就像 argument
方法一樣,你可以呼叫 option
不加任何參數,即可取得所有的選項並將之轉為一個陣列
:
// 取得特定的選擇
$queueName = $this->option('queue');
// 取得所有選擇
$options = $this->option();
如果參數或選項不存在,將會回傳 null
。
為輸入加上提示
除了顯示輸出,你也可以在指令執行期間,要求使用者輸入值。ask
方法將會用提供的問題來提示使用者,並且接受他們的輸入,接著回傳使用者的輸入回指令:
/**
* 執行這個指令列。
*
* @return mixed
*/
public function handle()
{
$name = $this->ask('你是名字是?');
}
secret
方法就如同 ask
方法一般,但是使用者的輸入將不會顯示在指令列。這個方法適合要求提供如密碼的敏感資訊時:
$password = $this->secret('密碼是?');
要求確認
如果你需要使用者做簡單的確認,你可以使用 confirm
方法。預設的情況時,這個方法會回傳 false
。然而,如果使用者對這個提示輸入 y
,那這個方法將會回傳 true
:
if ($this->confirm('你希望繼續嗎? [y|N]')) {
//
}
讓使用者做選擇
anticipate
方法可被用於為可能的選擇提供自動完成。使用者仍可以選擇任何答案,不管這些選擇。
$name = $this->anticipate('你的名字是?', ['Taylor', 'Dayle']);
如果你需要提供使用者一組事先定義的選擇,你可以使用 choice
方法。使用者會選擇答案的索引,但是回傳給你的會是答案的值。你可以設定回傳的預設值來防止沒有任何東西被選擇:
$name = $this->choice('你的名字是?', ['Taylor', 'Dayle'], false);
輸出至畫面
使用 line
、info
、comment
、question
和 error
方法來傳送輸出到終端。每個方法都有適當的 ANSI 顏色來表達它們的目的。
使用 info
方法來傳送資訊訊息給使用者,並以綠色呈現在終端。
/**
* 執行這個指令列。
*
* @return mixed
*/
public function handle()
{
$this->info('把我顯示在畫面上');
}
使用 error
方法來傳送錯誤訊息給使用者,並以紅色呈現在終端。
$this->error('有東西出問題了!');
如果你想顯示原本的控制列輸出,可以使用 line
方法。line
方法不會接收任何特殊的顏色:
$this->line('把我顯示在畫面上');
表格佈局
table
方法讓格式化多行與多列的資料變得簡單。只要傳送標頭和行到這個方法,寬跟高將會基於給的資料做動態的計算:
$headers = ['Name', 'Email'];
$users = App\User::all(['name', 'email'])->toArray();
$this->table($headers, $users);
進度條
對於需要長時間執行的任務,顯示進度指示器將會很有幫助。使用 output 物件,我們可以開始、前進、停止進度條,當開始執行時你需要定義總共有幾個階段,然後每階段完成後就讓進度條前進:
$users = App\User::all();
$bar = $this->output->createProgressBar(count($users));
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();
想得到更多資訊,請看看 Symfony Progress Bar 元件的文件。
註冊指令
一旦你的指令完成,你需要先向 Artisan 註冊它後才能使用。註冊的檔案為 app/Console/Kernel.php
。
在這個檔案中,你會在 commands
屬性找到指令的清單。要註冊你的指令,只要簡單的在此清單加入類別的名稱。當 Artisan 啟動時,所有條列在這個屬性的指令,都會被服務容器解析並向 Artisan 註冊:
protected $commands = [
Commands\SendEmails::class
];
使用程式碼呼叫指令
有時候你想在指令列介面外執行 Artisan 指令。例如,你希望在路由或控制器觸發 Artisan 指令。你只要在 Artisan
facade 使用 call
方法做到。call
方法的第一個參數為指令的名稱,第二個參數為陣列型態的指令輸入。退出碼將會被回傳:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});
在 Artisan
facade 使用 queue
方法,你甚至會將一堆 Artisan 指令放進隊列,好讓它們能在背景被你的隊列作業器 執行:
Route::get('/foo', function () {
Artisan::queue('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});
如果你需要指定非接收字串選項的值,像是 migrate:refresh
指令的 --force
標記,你可以傳遞一個 true
或 false
的布林值:
$exitCode = Artisan::call('migrate:refresh', [
'--force' => true,
]);
在指令中呼叫其他指令
有時候,你會希望在指令中呼叫其他已存在的指令。你可以使用 call
方法來達成。call
方法接受指令名稱和指令參數的陣列:
/**
* 執行這個指令列。
*
* @return mixed
*/
public function handle()
{
$this->call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
}
如果你想要呼叫其他指令並忽視它所有的輸出,你可以使用 callSilent
指令。callSilent
方法有和 call
方法一樣的用法:
$this->callSilent('email:send', [
'user' => 1, '--queue' => 'default'
]);