Создание консольной команды CLI в Symfony 3.4

В отличии от Laravel, в Symfony создание консольных команд доведено до абсурда. Чтобы создать заготовку команды нужно выполнить:

php bin/console generate:command MyBundle command:name

Где нужно указать имя бандла в котором будет создана команда и имя команды, по которому она будет вызываться. Если запустить generate:command без аргументов, то в интерактивном режиме будут запрошены Bundle name и Command name, а затем ещё и подтвердить всё намерение: Do you confirm generation [yes]? После чего будет создана папка src/MyBundle/Command/ (если её ещё нет) и файл в ней: src/MyBundle/Command/CommandNameCommand.php

Теперь можно вызвать свою команду так:

php bin/console command:name

Важный момент, указанный бандл уже должен существовать, иначе будет ошибка Bundle «UnknownBundle» does not exist и предложение ввести его ещё раз. Задание опций и аргументов команды аналогично тому, как это делается в Laravel. Ещё бы, ведь Laravel использует те же самые Symfony-компоненты.

Интеграция Symfony CLI с NewRelic

Если вы используете системы мониторинга типа NewRelic или подобных, то по-умолчанию запускаемые консольные скрипты будут помечаться в разделе Transactions как unknown, что сильно усложнит их мониторинг. Обойти это можно вот таким костылём: в теле метода execute каждой команды нужно перед началом выполнения дописать такие строки:

if(extension_loaded('newrelic') ) {
    newrelic_name_transaction($this->getName() );
}

Ленивая загрузка Symfony-команд

На самом деле не совсем понял зачем это нужно, но можно провернуть такой трюк. В методе configure команды убрать вызов setName, а для указания имени команды использовать статическое свойство $defaultName

protected static $defaultName = 'command:name';

Затем в файле config.php бандла указать:

$container
    ->register(\MyBundle\Command\CommandNameCommand::class)
    ->addTag('command.name', ['command' => \MyBundle\Command\CommandNameCommand::getDefaultName()])
;

Однако, зачем это нужно, не совсем понял, возможно есть какой-то профит в производительности.

Доступ к сервис-контейнеру из комманды

Прокинуть зависимости в команду через конструктор не получится, так как каждая команда должна наследоваться от класса ContainerAwareCommand, который в свою очередь отнаследован от Symfony\Component\Console\Command с такой сигнатурой конструктора:

public function __construct($name = null)

Но можно делать в методе execute() команды так:

$Class = $this->getContainer()->get(Class::class);

А для получения EntityManager — так:

$EntityManager = $this->getContainer()->get('doctrine.orm.entity_manager');