Консольные команды
Импорт данных, рассылки, очистку старых записей запускают из терминала или по расписанию. Для таких задач пишут собственные команды bin/console. Команда — тоже сервис: ей доступны репозитории, почта и всё остальное.
Создание
php bin/console make:command app:send-report// src/Command/SendReportCommand.php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:send-report', description: 'Отправляет недельный отчёт')]
class SendReportCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->success('Отчёт отправлен.');
return Command::SUCCESS;
}
}php bin/console app:send-reportИмена своих команд принято начинать с app:.
Аргументы и опции
Их описывают в методе configure():
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
protected function configure(): void
{
$this
->addArgument('format', InputArgument::REQUIRED, 'Формат файла')
->addOption('limit', null, InputOption::VALUE_REQUIRED, 'Сколько записей', 100)
->addOption('active', null, InputOption::VALUE_NONE, 'Только активные');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$format = $input->getArgument('format');
$limit = (int) $input->getOption('limit');
$onlyActive = $input->getOption('active');
return Command::SUCCESS;
}php bin/console app:export-users csv --limit=500 --activeОформление вывода
Класс SymfonyStyle даёт готовые элементы:
$io = new SymfonyStyle($input, $output);
$io->title('Экспорт пользователей');
$io->text('Обычная строка');
$io->warning('Часть записей пропущена');
$io->error('Файл не найден');
$io->table(['Имя', 'Почта'], [['Анна', 'anna@example.com']]);Вопросы
$name = $io->ask('Как назвать файл?', 'users.csv');
if (!$io->confirm('Удалить старые записи?', false)) {
return Command::SUCCESS;
}Индикатор выполнения
foreach ($io->progressIterate($users) as $user) {
$this->export($user);
}Сервисы в команде
Зависимости передают через конструктор:
public function __construct(
private UserRepository $users,
private MailerInterface $mailer,
) {
parent::__construct();
}Запуск по расписанию
На сервере команду добавляют в планировщик cron:
0 9 * * 1 php /var/www/blog/bin/console app:send-reportЭта строка запускает отчёт каждый понедельник в 9:00.
Частая ошибка
Собственный конструктор команды обязан вызвать parent::__construct(). Без этого команда не получит имя, и консоль завершится ошибкой. И не забывайте возвращать Command::FAILURE при сбое: по коду завершения cron и системы размещения понимают, что операция не удалась.