Create Custom CLI Commands Using the Symfony Console Component

PHP:7.2

symfony/console:5.2.3

在軟體開發的生涯中,很多時候開發一些小工具可以幫助我們快速處理一些 routine 的事情,但當小工具一多,若是沒有整理的話,要使用時都得重新看一次 code 才能知道在做什麼,再加上這些工具的使用說明往往不夠明確,也不一定可以交接給別人使用。

symfony/consoleSymfony Framework 中的一個套件,專門用來實作 CLI CommandsLaravelartisan 也是透過該套件實作,功能及結構相對比較完善,因此我們可以透過單獨使用 symfony/console 來實作較為完整的小工具。

Installation and Configuration

Install symfony/console

composer require symfony/console

Configure your Structure

由於 symfony/console 是結構非常完整的套件,因此就算只是開發小工具,目錄結構和 dependency 也要調整好才能運作。

先將 composer.json 的 autoload 調整好。

{
    "require": {
        "symfony/console": "^5.2"
    },
    "autoload": {
        "psr-4": {
            "BallBallTools\\": "src/"
        }
    }
}

接著按照你的需求設計目錄結構。

├── bin
│   └── console
├── composer.json
├── composer.lock
├── src
│   └── Command
│       └── CreateUserCommand.php
└── vendor

bin/console 會是我們的 CLI command 的進入點,相關的 Command 設定我都會放在 src/Command 底下。

最後再更新一下 composer

composer dump-autoload

Create the Console Application

在建立第一個 Command 之前,我們需要先寫好進入點。

bin/console

#!/usr/bin/env php
<?php

require __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\Console\Application;

// 使用 Symfony 的 Console Object 當進入點
$application = new Application();
$application->run();

Notice: 記得把權限調整成 755 方便執行。

執行以後就會看到基本的 Command 運作。

bin/console
Console Tool

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display help for the given command. When no command is given display help for the list command
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  help              Displays help for a command
  list              Lists commands

Create the Command File

在進入點完成之後,就可以開始實作想要的功能,本篇就以實作一個 CreateUserCommand 為例。

src/Command/CreateUserCommand.php

namespace BallBallTools\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;

class CreateUserCommand extends Command
{
    // 定義該 Command 的名字,會在執行 "bin/console" 時顯示
    protected static $defaultName = 'User:create-user';

    // configure() 是用來設定參數的函式
    protected function configure()
    {
        $this
            // 該 Command 的說明簡介
            ->setDescription('Creates a new user')

            // 使用 "--help" option 時的說明
            ->setHelp('This command allows you to create a user...')

            // 加入 Option 設定
            // addOption(<long-options>, <options>, <options variants>, <message>, <default value>)
            // Support --production
            ->addOption('production', null, InputOption::VALUE_NONE, 'Enable production')
            // Support -c or --colors
            // Support array. Can run command --colors=red --colors=green
            ->addOption('colors', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Enter your color', ['red', 'yellow'])

            // 加入 Argument 設定
            // addArgument(<argument>, <argument variants>, <message>, <default value>)
            ->addArgument('username', InputArgument::REQUIRED, 'Enter the username.')
            // Support array. Can run command argument1 argument2 argument3 ...
            ->addArgument('his-girlfriends', InputArgument::IS_ARRAY, 'Separate multiple names with a space');
    }

    // execute() 是用來描述 Command 執行動作的函式
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // Get optoins and arguments by InputInterface
        $colors = $input->getOption('colors');
        $username = $input->getArgument('username');

        // Output by OutputInterface
        $output->writeln(sprintf('Hello World!, %s', $username));

        return Command::SUCCESS;
        // return Command::FAILURE;
    }
}

Options Variants

Type Name 功能
InputArgument::REQUIRED 必填欄位
InputArgument::OPTIONAL 選填欄位
InputArgument::IS_ARRAY 支援陣列

Arguments Variants

Type Name 功能
InputOption::VALUE_IS_ARRAY 支援陣列(e.g. --dir=/foo --dir=/bar)
InputOption::VALUE_NONE 可不填入值 (e.g. --production)
InputOption::VALUE_REQUIRED 必填欄位
InputOption::VALUE_OPTIONAL 選填欄位

最後要把你開發好的 Command 註冊到進入點。

bin/console

use BallBallTools\Command\CreateUserCommand;

$application = new Application();
// Register
$application->add(new CreateUserCommand());
$application->run();

Run your Command

bin/console User:create-user --help
Categories: PHP