Дата обновления перевода: 2021-05-27

Команды консоли

Фреймворк Symfony предоставляет множество команд через скрипт bin/console (например, хорошо известная команда bin/console cache:clear). Эти команды создаются с помощью Компонента консоль. Вы можете также использовать его для создания собственных команд.

Консоль: APP_ENV и APP_DEBUG

Консольные команды выполняются в окружении, определённом в переменной APP_ENV файла .env, по умолчанию - dev. Он также считывает значение APP_DEBUG, чтобы включать и выключать режим “отладки” (по умолчанию - 1, то есть включён).

Чтобы запустить команду в другом окружении или режиме отладки, отредактируйте значение APP_ENV и APP_DEBUG.

Создание команды

Команды определяются в классах, расширяющих Command. Например, вы можете захотеть, чтобы команда создавала пользователя:

// src/Command/CreateUserCommand.php
namespace App\Command;

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

class CreateUserCommand extends Command
{
    // название команды (часть после "bin/console")
    protected static $defaultName = 'app:create-user';

    protected function configure(): void
    {
        // ...
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // ... введите здесь код, чтобы создать пользователя

        // этот метод должен вернуть целое число с "кодом завершения"
        // команды. Вы также можете использовать это константы, чтобы сделать код более читаемым

        // вернуть это, если при выполнении команды не было проблем
        // (равноценно возвращению int(0))
        return Command::SUCCESS;

        // или вернуть это, если во время выполнения возникла ошибка
        // (равноценно возвращению int(1))
        // return Command::FAILURE;

        // или вернуть это, чтобы указать на неправильное использование команды, например, невалидные опции
        // или отсутствующие аргументы (равноценно возвращению int(2))
        // return Command::INVALID
    }
}

New in version 5.1: Константы Command::SUCCESS м Command::FAILURE были представлены в Symfony 5.1.

New in version 5.3: Константа Command::INVALID была представлена в Symfony 5.3

Конфигурация команды

Вы можете по желанию определить сообщение помощи и аргументы и опции ввода:

// ...
protected function configure(): void
{
    $this
        // краткое описание, отображающееся при запуске "php bin/console list"
        ->setDescription('Creates a new user.')

        // полное описание команды, отображающееся при запуске команды
        // с опцией "--help"
        ->setHelp('Эта команда позволяет вам создать пользователя...')
    ;
}

Метод configure() вызывается автоматически в конце конструктора команды. Если ваша команда определяет свой конструктор, сначала установите свойства и вызовите родительский конструктор для того, чтобы эти свойства стали доступны в методе configure():

// ...
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;

class CreateUserCommand extends Command
{
    // ...

    public function __construct(bool $requirePassword = false)
    {
        // хорошей практикой считается вызывать сначала родительский конструктор и
        // потом установка своих свойств. Это не сработает в данном случае
        // потому что configure() нуждается в установленных свойствах в конструкторе
        $this->requirePassword = $requirePassword;

        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            // ...
            ->addArgument('password', $this->requirePassword ? InputArgument::REQUIRED : InputArgument::OPTIONAL, 'User password')
        ;
    }
}

Регистрация команды

Команды Symfony должны быть зарегистрированы как сервисы и отмечены тегом console.command. Если вы используете кофигурацию services.yaml по умолчанию, это уже сделано для вас, благодаря автоконфигурации.

Выполнение команды

После настройки и регистрации команды вы можете выполнить её в терминале:

1
$ php bin/console app:create-user

Как вы могли ожидать эта команда ничего не делает, так как вы пока не прописали никакой логики. Добавьте свою логику в метод execute().

Вывод в консоль

Метод execute() имеет доступ к потоку вывода для того, чтобы писать сообщения в консоль:

// ...
protected function execute(InputInterface $input, OutputInterface $output)
{
    // выводит множество строк в консоль (добавляя "\n" в конце каждой строки)
    $output->writeln([
        'User Creator',
        '============',
        '',
    ]);

    // значение возвращённое someMethod() может быть итератором (https://secure.php.net/iterator)
    // которое генерирует и возвращает сообщение с помощью ключевого слова PHP 'yield'
    $output->writeln($this->someMethod());

    // выводит сообщение с последующим "\n"
    $output->writeln('Ух ты!');

    // выводит сообщение, не добавляя "\n" в конце строки
    $output->write('Вы уже почти ');
    $output->write('создали пользователя.');
}

Теперь, попробуйте выполнить команду:

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

Ух ты!
Вы уже почти создали пользователя.

Секции вывода

New in version 4.1: Секции вывода появились в Symfony 4.1.

Обычный вывод консоли может быть разделён на несколько независимых регионов называемых “секции вывода”. Создайте одну или несколько данных секций, когда вам нужно очистить и перезаписать выводимую информацию.

Секции создаются методом ConsoleOutput::section() который возвращает экземпляр ConsoleSectionOutput:

// ...
use Symfony\Component\Console\Output\ConsoleOutputInterface;

class MyCommand extends Command
{
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        if (!$output instanceof ConsoleOutputInterface) {
            throw new \LogicException('Эта команда принимает только экземпляр "ConsoleOutputInterface".');
        }

        $section1 = $output->section();
        $section2 = $output->section();

        $section1->writeln('Hello');
        $section2->writeln('World!');
        // Вывод отображает "Hello\nWorld!\n"

        // overwrite() заменяет все существующее содержание секции заданным содержанием
        $section1->overwrite('Goodbye');
        // Теперь вывод отображает "Goodbye\nWorld!\n"

        // clear() удаляет все содержание раздела...
        $section2->clear();
        // Теперь вывод отображает "Goodbye\n"

        // ...но вы также можете удалить заданное количество строк
        // (этот пример удаляет две последние строки секции)
        $section1->clear(2);
        // Теперь вывод абсолютно пуст!

        return Command::SUCCESS;
    }
}

Note

Новая строка добавляется автоматически при отображении информации в секции.

Секции вывода позволяют вам манипулировать выводом консоли сложными способами, например, отображение нескольких прогрессбаров, которые обновляются независимо друг от друга и добавление строк в таблицы, которые уже были выведены.

Ввод в консоль

Используйте опции или аргументы ввода, чтобы передать информацию в команду:

use Symfony\Component\Console\Input\InputArgument;

// ...
protected function configure()
{
    $this
        // создать аргумент
        ->addArgument('username', InputArgument::REQUIRED, 'The username of the user.')
        // ...
    ;
}

// ...
public function execute(InputInterface $input, OutputInterface $output)
{
    $output->writeln([
        'User Creator',
        '============',
        '',
    ]);

    // получить значение аргумента, используя getArgument()
    $output->writeln('Username: '.$input->getArgument('username'));
}

Теперь вы можете передать имя пользователя в команду:

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

Username: Wouter

See also

Смотрите Console Input (Arguments & Options), чтобы узнать больше информации об опциях и аргументах консоли.

Получение сервисов и сервис-контейнера

Чтобы действительно создать нового пользователя, команда должна получить доступ к некоторым сервисам. Так как ваша команда уже зарегистрирована, как сервис, вы можете использовать нормальное внедрение зависимости. Представьте, что у вас есть сервис App\Service\UserManager, к которому вы хотите получить доступ:

// ...
use App\Service\UserManager;
use Symfony\Component\Console\Command\Command;

class CreateUserCommand extends Command
{
    private $userManager;

    public function __construct(UserManager $userManager)
    {
        $this->userManager = $userManager;

        parent::__construct();
    }

    // ...

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // ...

        $this->userManager->create($input->getArgument('username'));

        $output->writeln('User successfully generated!');

        return Command::SUCCESS;
    }
}

Жизненный цикл команды

Команды имеют три метода жизненного цикла, которые активируются при выполнении команды:

initialize() (необязательный)
Этот метод выполняется до методов interact() и execute(). Его главная цель - инициализировать переменные, используемые в других методах команды.
interact() (необязательный)
Этот метод выполняется после initialize() и до execute(). Его цель - проверка наличия всех опций/аргументов и спросить пользователя значения в диалоговом режиме. Это последнее место, где вы можете запросить отсутствующие опции/аргументы. После этой команды, отсутствующие опции/аргументы будут приводить к ошибке.
execute() (обязательный)
Этот метод выполняется после``interact()`` и initialize(). Он содержит логику, которую вы хотите выполнить с помощью команды.

Тестирование команд

Symfony предоставляет несколько инструментов, чтобы помочь вам тестировать ваши команды. Самая полезная - это класс CommandTester. Он использует специальные классы ввода и вывода, чтобы облегчить тестирование без настоящей консоли:

// tests/Command/CreateUserCommandTest.php
namespace App\Tests\Command;

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()
    {
        $kernel = static::createKernel();
        $application = new Application($kernel);

        $command = $application->find('app:create-user');
        $commandTester = new CommandTester($command);
        $commandTester->execute([
            // передать аргументы помощнику
            'username' => 'Wouter',

            // добавить к ключу префикс с двумя дефисами при передаче опций,
            // например: '--some-option' => 'option_value',
        ));

        // вывод команды в консоли
        $output = $commandTester->getDisplay();
        $this->assertStringContainsString('Username: Wouter', $output);

        // ...
    }
}

Если вы используете приложение одной команды, вызовите setAutoExit(false), чтобы получить результат команды в CommandTester.

New in version 5.2: Метод setAutoExit() для приложений одной команды был представлен в Symfony 5.2.

Tip

Вы также можете тестировать всю консоль приложения, используя ApplicationTester.

Caution

При тестировании команд с использованием класса CommandTester, события консоли не запускаются. Если вам нужно протестировать эти события, используйте вместо этого ApplicationTester.

Caution

При тестировании команд с использованием класса ApplicationTester, не забудьте отключить автоматический выход:

$application = new Application();
$application->setAutoExit(false);

$tester = new ApplicationTester($application);

Note

При использовании компонента Консоль в отдельном проекте, используйте Symfony\Component\Console\Application и расширьте обычный \PHPUnit\Framework\TestCase.

Ведение логов ошибок команды

Какждый раз, когда во время выполнения команды вызывается исключение, Symfony добавляет для него сообщение лога, включая всю неработающую команду. Кроме того, Symfony регистрирует подписчика событий, чтобы слушать ConsoleEvents::TERMINATE event и добавляет сообщение лога каждый раз, когда команда не заканчивается 0 `exit status`_.

Узнать больше

Компонент консоль акже содержит набор “помощников” - разных маленьких инструментов, способных помочь вам с разными заданиями:

  • Question Helper: узнать у пользователя информацию в диалоговом режиме
  • Formatter Helper: настроить расцвеичвание вывода
  • Progress Bar: показать бар прогресса
  • Table: отобразить данные в табличной форме
  • Debug Formatter Helper: предоставляет функции для вывода

информации отладки при запуске внешней программы

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.