Artisan 命令列


互動輸入

編寫輸出

#註冊指令

#以程式設計方式執行指令

從其他指令呼叫指令

####簡介######Artisan 是Laravel 自帶的命令列接口,他提供了許多使用的命令來幫助你構建Laravel 應用。若要查看所有可用的Artisan 指令的列表,可以使用 ###list### 指令:###
php artisan list
###每個指令都包含了「幫助」 介面,它會顯示和概述指令的可用參數及選項。只需要在指令前加上###help### 即可查看指令幫助介面:###
php artisan help migrate
#####################Tinker 指令(REPL )######所有Laravel 應用程式都包含了Tinker,一個基於###PsySH### 套件提供支援的REPL 。 Tinker 讓你可以在命令列中與你整個的 Laravel 應用程式互動 。包括 Eloquent ORM、任務、事件等等。執行 Artisan 指令 ###tinker### 進入 Tinker 環境:###
php artisan tinker
###你可以透過使用 ###vendor:publish### 指令發布 Tinker 設定檔:###
php artisan vendor:publish --provider="Laravel\Tinker\TinkerServiceProvider"
#######

指令白名單

Tinker 透過採用白名單的方式來決定允許哪些 Artisan 指令可以在 shell 中執行。預設情況下,你可以執行clear-compileddownenvinspiremigrate#、 optimize、和up 指令。如果你想要加入更多的白名單指令,可以將它們加入 tinker.php 設定檔中的commands 陣列裡:

'commands' => [ 
   // App\Console\Commands\ExampleCommand::class,
   ],

#黑名單別名

通常,Tinker 會在Tinker 中根據你的需求自動為類別添加別名。然而,你可能不希望為某些類別添加別名。你可以在tinker.php 設定檔中的dont_alias 陣列中列舉這些類別來完成此操作:

'dont_alias' => [ 
   App\User::class,
 ],

寫指令

除Artisan 提供的指令外,你還可以建立自己的自訂指令。指令通常儲存在 app/Console/Commands 目錄中;不過,只要你的指令可以由 Composer 加載,你就可以自由選擇自己的儲存位置。

#產生指令

#要建立一個新的指令,可以使用Artisan 指令make:command。這個指令會在 app/Console/Commands 目錄中建立一個新的指令類別。不必擔心應用程式中不存在這個目錄,因為它會在你第一次執行 Artisan 指令 make:command 時建立。產生的命令會包括所有命令中預設存在的屬性和方法:

php artisan make:command SendEmails

#命令結構

命令運行之後,你應該先填入signaturedescription 屬性以便你在輸入php artisan list 時能夠清楚知道用法。執行指令時會呼叫 handle 方法,你可以在這個方法中放置指令邏輯。

{tip}  為了程式碼更好的複用,最好保持你的控制台程式碼輕量級並且能夠延遲到應用程式服務中完成。在下面的範例中,我們將注入一個服務類別來完成發送郵件的重任。

來看一個簡單的例子。我們可以在 handle 方法中註入我們需要的任何依賴項。 Laravel 服務容器 將會自動注入所有在建構函式中帶型別限制的依賴:

<?php
    namespace App\Console\Commands;
    use App\User;use App\DripEmailer;
    use Illuminate\Console\Command;
    class SendEmails extends Command{   
     /**
     * The name and signature of the console command.
     *
     * @var string
     */   
   protected $signature = 'email:send {user}';  
    /**
     * The console command description.
     *
     * @var string
     */   
    protected $description = 'Send drip e-mails to a user';    
     /**
     * Create a new command instance.
     *
     * @return void
     */  
   public function __construct()    {    
      parent::__construct();   
     }    
     /**
     * Execute the console command.
     *
     * @param  \App\DripEmailer  $drip
     * @return mixed
     */  
   public function handle(DripEmailer $drip)  
     {     
        $drip->send(User::find($this->argument('user')));  
      }
   }

閉包指令

基於閉包的指令提供了一個用類別取代定義控制台指令的方法。同理,閉包路由是控制器的一種替代方法,而閉包命令則可以認為是命令類別的替代方法。在 app/Console/Kernel.php 檔案的commands  方法中,Laravel 載入了routes/console.php  file:

/**
 * Register the Closure based commands for the application.
 *
 * @return void
 */
 protected function commands(){ 
    require base_path('routes/console.php');
 }

雖然這個檔案沒有定義HTTP 路由,但是它將基於控制台的入口點(路由)定義到了應用程式中。在這個文件,你可以使用 Artisan::command 方法定義所有的閉包路由。 command 方法接受兩個參數:  指令名稱 和一個接受指令參數及選項的閉包:

Artisan::command('build {project}', function ($project) { 
   $this->info("Building {$project}!");
});

閉包綁定底層的指令實例,因為你可以存取所有能夠在完整命令類別中的所有輔助方法。

類型提示依賴

除了接收命令的參數和選項外,命令閉包也可以使用類型提示從服務容器中解析其他的依賴關係:

use App\User;
use App\DripEmailer;Artisan::command('email:send {user}', function (DripEmailer $drip, $user) { 
   $drip->send(User::find($user));
});

閉包指令描述

當你定義一個閉包指令,你應該使用describe 方法來為指令新增描述。這個描述會在你執行php artisan listphp artisan help 指令時顯示:

Artisan::command('build {project}', function ($project) {
    $this->info("Building {$project}!");
 })->describe('Build the project');

定義輸出期望

在編寫控制台命令時,通常是透過參數和選項來收集使用者輸入的。 Laravel 可以透過 signature 屬性非常方便的定義你期望使用者輸入的內容。 signature 允許使用單一且可讀性高,類似路由的語法定義指令的名稱、參數和選項。

參數

所有使用者提供的參數及選項都被包含在花括號中。在下面的範例中,這個指令定義了一個必須的參數:  user:

/**
 * The name and signature of the console command.
 *
 * @var string
 */
 protected $signature = 'email:send {user}';

你也可以建立可選參數,並定義參數的預設值:

// 可选参数...
email:send {user?}
// 带有默认值的可选参数...
email:send {user=foo}

選項

選項,類似參數,是使用者輸入的另一種格式。當命令列指定選項時,它們以兩個連字符 ( -- ) 作為前綴。有兩種類型的選項:接收值和不接收值。不接收值的選項就像是布林值的「開關」。讓我們來看看這種類型的選項的例子:

/**
 * 命令行的名称及签名。
 *
 * @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*}

呼叫此方法時,該 user 參數的輸入參數可依序傳遞給命令列。例如,下列指令會設定user 的值為 ['foo', 'bar'] :

php artisan email:send foo bar

當定義接收陣列的選項時,傳遞給命令列的每個選項值都應以選項名稱為前綴:

email:send {user} {--id=*}
php artisan email:send --id=1 --id=2

#輸入說明

你可以透過使用冒號來為參數和選項添加說明,並使其將他們分開。如果你需要一點額外的空間來定義你的指令,可以隨意分開在多個行:

/**
 * 命令行的名称及签名。
 *
 * @var string
 */
 protected $signature = 'email:send
                 {user : The ID of the user}
                 {--queue= : Whether the job should be queued}';

#Command I/ O

取得輸入

#在指令執行時,顯然你需要取得指令接收到的參數和選項的值。你可以用 argument 和 option 方法來達到目的:

/**
 * 执行命令。
 *
 * @return mixed
 */
 public function handle(){
     $userId = $this->argument('user');    
     //
 }

如果你想要所有的參數以 array 數組獲取,你可以呼叫 arguments 方法:

$arguments = $this->arguments();

和取得參數類似,option 方法可以非常容易的取得選項的值。要將所有的選項以陣列獲取,使用 options 方法:

// 获取一个指定的选项值
$queueName = $this->option('queue');
// 获取所有的选项值
$options = $this->options();

如果參數或選項不存在,則傳回 null 。

互動式輸入

除了顯示輸出外,你還可以要求使用者在指令執行時提供輸入。 ask 方法將提示使用者輸入並接收,然後使用者的輸入將會傳入你的指令:

/**
 * 执行命令。
 *
 * @return mixed
 */
 public function handle(){
     $name = $this->ask('What is your name?');
 }

secret 方法和 ask方法類似,但當使用者在控制台輸入時他們的輸入內容是不可見的。這個方法適用於需要用戶輸入像密碼這樣的敏感信息的時候:

$password = $this->secret('What is the password?');

請求確認

如果你想要尋求用戶確認一些簡單的信息,你可以使用 confirm 方法。預設情況下,該方法將傳回 false 。但若使用者在回覆中輸入 y 或 yes 則會回傳 true

if ($this->confirm('Do you wish to continue?')) {
    //
 }

自動補全

anticipate 方法可用來提供可能的選擇自動補全功能。使用者仍可忽略自動補全的提示,作任意答案:

$name = $this->anticipate('What is your name?', ['Taylor', 'Dayle']);

多重選擇

如果你要提供使用者一些預設的選擇,可以使用 choice 方法。你也可以設定預設值的索引,用以回應使用者沒有選擇的情境:

$name = $this->choice('What is your name?', ['Taylor', 'Dayle'], $defaultIndex);

寫輸出

可以使用lineinfocommentquestionerror 方法來將輸出傳送到終端。每個方法都使用適當的 ANSI 顏色來表明其目的。例如,讓我們向使用者顯示一些普通訊息,通常來說,最好使用 info 方法,它會在控制台將輸出的內容顯示為綠色:

/**
 * 执行命令。
 *
 * @return mixed
 */
 public function handle(){
     $this->info('Display this on the screen');
 }

顯示錯誤訊息, 使用 error 方法。錯誤訊息則會顯示為紅色:

$this->error('Something went wrong!');

如果你想在控制台顯示無顏色設定的輸出,請使用 line 方法:

$this->line('Display this on the screen');

表格佈局
###對於多行列資料的格式化輸出,###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));
$bar->start();foreach ($users as $user) { 
   $this->performTask($user);    
   $bar->advance();
}$bar->finish();
###參閱 ###Symfony Progress Bar component documentation###   取得更多進階用法。 #####################

註冊命令

app/Console/Commands 目錄下的命令都會被註冊,這是由於控制台內核的commands 方法呼叫了 load。實際上,可隨意呼叫load 來掃描其他目錄下的Artisan 指令:

/**
 * 注册应用的命令
 *
 * @return void
 */
 protected function commands(){ 
    $this->load(__DIR__.'/Commands');    
    $this->load(__DIR__.'/MoreCommands'); 
   // ...
}

也可以在app/Console/Kernel.php 檔案的 $commands 屬性中手動註冊指令的類別名稱。 Artisan 啟動時,這個屬性所列的指令都會由服務容器解析並透過Artisan 進行註冊:

protected $commands = [ 
   Commands\SendEmails::class
  ];

##程式呼叫指令

有時需要在CLI 之外執行Artisan 指令,例如,在路由或控制器裡觸發Artisan 指令。要實現調用,可以使用

Artisan 門面的 call 方法。 call 方法的第一個參數接受指令名,第二個參數接受陣列形式的指令參數。退出碼將會回傳:

Route::get('/foo', function () { 
   $exitCode = Artisan::call('email:send', [  
         'user' => 1,
          '--queue' => 'default' 
       ]);  
     //
 });

另外,你可以將整個Artisan 指令當作字串傳遞給

call 方法:

Artisan::call('email:send 1 --queue=default');

Artisan 門面的queue 方法可以將Artisan 指令佇列化,交由佇列工作進程進行後台處理。使用此方法之前,請務必設定好佇列以及執行佇列監聽器:

Route::get('/foo', function () { 
   Artisan::queue('email:send', [   
        'user' => 1,
         '--queue' => 'default' 
        ]); 
      //
});

你也可以指定Artisan 指令派發的連線或任務:

Artisan::queue('email:send', [ 
   'user' => 1, 
   '--queue' => 'default'
 ])->onConnection('redis')->onQueue('commands');

#傳遞陣列值

如果定義了接受數組的選項,可以直接傳遞數組到該選項:

Route::get('/foo', function () { 
   $exitCode = Artisan::call('email:send', [    
       'user' => 1,
        '--id' => [5, 13]   
      ]);
 });

傳遞布林值

需要指定沒有選項值的選項時,例如,

migrate:refresh 指令的--force 選項,就可以傳入truefalse

$exitCode = Artisan::call('migrate:refresh', [
    '--force' => true,
  ]);

指令的互相呼叫

call 方法可以實作呼叫其它Artisan 指令。 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'
 ]);

本文章首發在
LearnKu.com 網站上。