自訂命令列介面指令

雖然像其他路由一樣使用命令列指令很方便,但你可以會發現有的時候你需要一些不同的東西,命令列指令說不定就可以幫助到你。它們是一些簡單的類別,不需要定義路由,這使得它們非常適合用於建構工具。開發者可以透過它處理資料庫遷移、資料庫填充、檢查排程工作狀態,甚至是替公司建構出自訂的程式碼生成器來簡化工作。

執行指令

定位在根目錄下(就是擁有 /app/system 的那個目錄),指令就能在命令列中執行。 CodeIgniter 已經提供了一個內建腳本 spark ,可以用於執行命令列指令:

> php spark

當你不指定任何指令時,會顯示一個簡單的提示資訊,並提供一個可用的指令列表,你應該以指令的名稱作為第一參數來執行你想使用的指令:

> php spark migrate

有些時候指令需要額外的參數,這些參數應該直接在指令後用空格隔開:

> php spark db:seed DevUserSeeder

你可以隨時透過 --no-header 來抑制標頭的輸出,這可以幫助你解析結果:

> php spark cache:clear --no-header

對於 CodeIgniter 所提供的指令,如果你沒有鍵入它所需要的參數,你將會被提示正確執行指令應該需要的要求:

> php spark migrate:version
> Version?

呼叫指令

指令也可以從你的程式中執行。通常會出現在控制器中執行 cronjob 任務,但它們也可以在任何時候使用。你可以透過使用 command() 函數來達成。你可以在任何時候呼叫這個函數。

echo command('migrate:create TestMigration');

這個函數唯一的參數是字串,就是需要被呼叫命令以及所需要的參數。這與你從命令列介面中呼叫它時的用法完全一樣。

當不從命令列執行時,執行指令的所有輸出都會被蒐集起來。這些輸出會在指令執行後被回傳,這樣你就可以選擇是否顯示它們。

使用提示指令

你可以使用下列的提示指令來獲得在命令列介面中任何指令的提示資訊:

> php spark help db:seed

使用 list 指令可以得到一个依照類别排序的可用指令與描述的列表。你也可以使用 spark list --simple 取得依字母順序排序的可用指令原始列表。

建立新的指令

若是你在開發中需要,那麼建立新的指令真的非常容易。每個新的指令都必須繼承 CodeIgniter\CLI\BaseCommand 類別,並且實作 run() 方法。

你應該要在你的新指令類別檔案中實現下列屬性,以及這些指令的使用方式,這樣它就能在命令列指令列表中出現:

  • $group: 字串,用來描述該指令在指令表中被歸類的群組。例如:資料庫 Database
  • $name: 描述指令名稱的字串,例如: migrate:create
  • $description: 簡單描述指令效果的字串,例如:建立一個新的遷移檔案。
  • $usage: 描述指令使用方式的字串,例如: migrate:create [migration_name] [Options]
  • $arguments: 描述每個指令參數的鍵值陣列,例如:'name' => 'The migration file name'
  • $options: 描述每個指令選項的鍵值陣列,例如:'-n' => 'Set migration namespace'

提示列表或提示指令所顯示的內容將會從上述的屬性中產出。

檔案位置

你的指令檔案必須儲存在一個名為 Commands 的資料夾下,但是這個資料夾可以位於 自動載入器 可以找的到的任何地方。這個目錄可以位於 /app/Commands ,也位於專案開發資料夾中你所自訂的目錄,比如說: Acme/Commands

備註

當指令被執行時,完整的 CodeIgniter 命令列環境將被載入,這樣就可以獲得環境訊息、路徑訊息,以及任何在製作控制器時你所使用的工具。

範例指令

讓我們透過一個示範指令來演示功能。這個指令唯一的作用是產出應用程式本身的基本資訊報告。首先,先至 /app/Commands/AppInfo.php 創建一個含有以下程式碼的檔案:

<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

class AppInfo extends BaseCommand
{
    protected $group       = 'demo';
    protected $name        = 'app:info';
    protected $description = 'Displays basic application information.';

    public function run(array $params)
    {
        // ...
    }
}

如果以下了 list 指令,你會看到新的指令已經被列在 demo 群組下,仔細地瞧瞧,你應該會發現這十分容易。 $group 屬性的作用是將這個指令與其它指令組織起來,告訴你它應該被列在哪個群組底下。

$name 則是這個指令可以被呼叫的名稱,唯一的要求就是不可以含有空格,並且所有字元必須在命令列中有效。不過,按照慣例,指令應該都要是小寫的,在指令名稱中使用冒號進行更進一步的分組,這有助於防止指令名稱的衝突 。

最後的屬性 $description 則是一個簡單的字串,將在指令 列表 中顯示,它應該要能好好地描述指令的效果。

run()

run() 方法是執行指令時會呼叫的方法,$params 陣列是指令名稱後可以接著使用的參數列表:

> php spark foo bar baz

那麼 foo 就是指令的名稱, $params 陣列則是:

$params = ['bar', 'baz'];

你也可以透過 命令列程式庫 存取,但 $params 已經替你從使用者輸入的字串中提煉出了已經定義好的參數,你可以透過 $params 中記錄的參數自訂腳本的行為。

我們的演示用指令有一個 run 方法,就像這樣:

public function run(array $params)
{
    CLI::write('PHP Version: '. CLI::color(phpversion(), 'yellow'));
    CLI::write('CI Version: '. CLI::color(\CodeIgniter\CodeIgniter::CI_VERSION, 'yellow'));
    CLI::write('APPPATH: '. CLI::color(APPPATH, 'yellow'));
    CLI::write('SYSTEMPATH: '. CLI::color(SYSTEMPATH, 'yellow'));
    CLI::write('ROOTPATH: '. CLI::color(ROOTPATH, 'yellow'));
    CLI::write('Included files: '. CLI::color(count(get_included_files()), 'yellow'));
}

BaseCommand 類別

所有的指令都必須繼承 BaseCommand 類別,這個類別有幾個食用的方法,在創建自己的指令時你應該要熟悉這些方法。這個類別也有一個 日誌記錄器 ,你可以透過 $this->logger 呼叫它。

CodeIgniter\CLI\BaseCommand
call(string $command[, array $params=[]])
參數:
  • $command (string) – 另一個要呼叫的指令名稱
  • $params (array) – 向這個指令提供額外的參數。

這個方法允許你在執行當前指令時呼叫其他指令:

$this->call('command_one');
$this->call('command_two', $params);
showError(Exception $e)
參數:
  • $e (Exception) – 用於錯誤報告的例外拋出。

一種便捷的方法,保值一致且清晰的錯誤輸出給命令列介面:

try {
    . . .
} catch (\Exception $e) {
    $this->showError($e);
}
showHelp()

一個顯示指令提示的方法:(用法、參數、描述,和選項)

getPad($array, $pad)
參數:
  • $array (array) – 鍵值陣列
  • $pad (integer) – 填充空間

計算鍵值陣列輸出的內距的方法。這個內距可以用來在命令列介面中輸出一個格式化的表格:

$pad = $this->getPad($this->options, 6);

foreach ($this->options as $option => $description) {
    CLI::write($tab . CLI::color(str_pad($option, $pad), 'green') . $description, 'yellow');
}

// 輸出就像這樣
-n                  Set migration namespace
-r                  override file