控制台命令

3.4 版本
维护中的版本

Symfony框架通过 bin/console 脚本(如,广为人知的 bin/console cache:clear 命令)提供了大量命令。这些命令是通过 Console组件 被创建的。你也可以使用它创建自己的命令。

创建一个命令 

命令通过类来定义,这些类必须存放在你的bundle (如 AppBundle\Command) 的 Command 命名空间下。类名必须是 Command 后缀。

例如,一个名为 CreateUser 的命令必须遵循此结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/AppBundle/Command/CreateUserCommand.php
namespace AppBundle\Command;
 
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
 
class CreateUserCommand extends Command
{
    protected function configure()
    {
        // ...
    }
 
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // ...
    }
}

配置命令 

首先,你必须在 configure() 方法中配置命令的名称。然后可选地定义一个帮助信息(help message)和 输入选项及输入参数(input options and arguments):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
protected function configure()
{
    $this
        // the name of the command (the part after "bin/console")
        // 命令的名字("bin/console" 后面的部分)
        ->setName('app:create-users')
 
        // the short description shown while running "php bin/console list"
        // 运行 "php bin/console list" 时的简短描述
        ->setDescription('Creates new users.')
 
        // the full command description shown when running the command with
        // the "--help" option
        // 运行命令时使用 "--help" 选项时的完整命令描述
        ->setHelp("This command allows you to create users...")
    ;
}

执行命令 

配置命令之后,你就能在终端(terminal)中执行它:

1
$  php bin/console app:create-users

你可能已经预期,这个命令将什么也不做,因为你还没有写入任何逻辑。在 execute() 方法里添加你自己的逻辑,这个方法可以访问到input stream(如,选项和参数)和output stream(以写入信息到命令行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
protected function execute(InputInterface $input, OutputInterface $output)
{
    // outputs multiple lines to the console (adding "\n" at the end of each line)
    // 输出多行到控制台(在每一行的末尾添加 "\n")
    $output->writeln([
        'User Creator',
        '============',
        '',
    ]);
 
    // outputs a message followed by a "\n"
    $output->writeln('Whoa!');
 
    // outputs a message without adding a "\n" at the end of the line
    $output->write('You are about to ');
    $output->write('create a user.');
}

现在,尝试执行此命令:

1
2
3
4
5
6
$  php bin/console app:create-user
User Creator
============
 
Whoa!
You are about to create a user.

控制台输入 

使用input选项或参数来传入信息给命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use Symfony\Component\Console\Input\InputArgument;
 
// ...
protected function configure()
{
    $this
        // configure an argument / 配置一个参数
        ->addArgument('username', InputArgument::REQUIRED, 'The username of the user.')
        // ...
    ;
}
 
// ...
public function execute(InputInterface $input, OutputInterface $output)
{
    $output->writeln([
        'User Creator',
        '============',
        '',
    ]);
 
    // retrieve the argument value using getArgument()
    // 使用 getArgument() 取出参数值
    $output->writeln('Username: '.$input->getArgument('username'));
}

现在,你可以传入用户名到命令中:

1
2
3
4
5
$  php bin/console app:create-user Wouter
User Creator
============
 
Username: Wouter

参考 控制台输出(参数和选项) 以了解更多关于命令行选项和参数的信息。

从服务容器中取得服务 

要真正创建用户,命令必须要访问某些 services(服务)。这可以通过让命令继承 ContainerAwareCommand 来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ...
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
 
class CreateUserCommand extends ContainerAwareCommand
{
    // ...
 
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // ...
 
        // access the container using getContainer()
        // 使用 getContainer() 访问服务容器
        $userManager = $this->getContainer()->get('app.user_manager');
        $userManager->create($input->getArgument('username'));
 
        $output->writeln('User successfully generated!');
    }
}

现在,一旦你创建了所需的服务及其逻辑,命令将执行 app.user_manager 服务的 create() 方法,然后用户会被创建。

命令的生命周期 

命令有三个生命周期方法可以在运行命令时使用:

initialize() (可选)
此方法在 interact()execute() 方法之前执行。它的主要作用是初始化那些用在命令其余方法中的变量。
interact() (可选)
此方法在 initialize() 之后、 execute() 之前执行。它的作用是检查是否错失了某些选项/参数,然后以互动方式向用户请求这些值。这是你可以问询错失的选项/参数的最后一个地方。此后,丢失的选项/参数将导致一个错误。
execute() (必须)
此方法在 interact() and initialize() 之后执行。它包含你希望命令去执行的逻辑。

测试命令 

Symfony提供了几个工具来帮你测试命令。最有用的一个是 CommandTester 类。它使用特殊的input和output类,令“不在真正控制台中”的测试变得容易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// tests/AppBundle/Command/CreateUserCommandTest.php
namespace Tests\AppBundle\Command;
 
use AppBundle\Command\CreateUserCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
 
class CreateUserCommandTest extends KernelTestCase
{
    public function testExecute()
    {
        self::bootKernel();
        $application = new Application(self::$kernel);
 
        $application->add(new CreateUserCommand());
 
        $command = $application->find('app:create-user');
        $commandTester = new CommandTester($command);
        $commandTester->execute(array(
            'command'  => $command->getName(),
 
            // pass arguments to the helper / 传入参数给helper
            'username' => 'Wouter',
 
            // prefix the key with a double slash when passing options,
            // e.g: '--some-option' => 'option_value',
            // 需要选项时,对key加“双中杠”的前缀,如'--some-option' => 'option_value'
        ));
 
        // the output of the command in the console
        // 控制台中的命令输出
        $output = $commandTester->getDisplay();
        $this->assertContains('Username: Wouter', $output);
 
        // ...
    }
}

使用 ApplicationTester 你也可以测试整个控制台程序。

当Console组件被单独使用时,使用 Symfony\Component\Console\Application 和常规的 \PHPUnit_Framework_TestCase

要在你的console tests中使用最完整的服务容器设置,你可以从 KernelTestCase 中继承你的测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ...
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
 
class CreateUserCommandTest extends KernelTestCase
{
    public function testExecute()
    {
        $kernel = $this->createKernel();
        $kernel->boot();
 
        $application = new Application($kernel);
        $application->add(new CreateUserCommand());
 
        $command = $application->find('app:create-user');
        $commandTester = new CommandTester($command);
        $commandTester->execute(array(
            'command'  => $command->getName(),
            'username' => 'Wouter',
        ));
 
        $output = $commandTester->getDisplay();
        $this->assertContains('Username: Wouter', $output);
 
        // ...
    }
}

控制台helpers 

Console组件还包括了一组“助手”(helpers)——不同的小工具可以帮助你完成不同的任务:

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)