Building Commands
Structure
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'app:greet', description: 'Greets a user')]
class GreetCommand extends Command
{
protected function configure(): void
{
$this
->addArgument('name', InputArgument::REQUIRED, 'The name to greet')
->addOption('shout', null, InputOption::VALUE_NONE, 'Shout the greeting');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$greeting = sprintf('Hello, %s!', $input->getArgument('name'));
if ($input->getOption('shout')) {
$greeting = strtoupper($greeting);
}
$io->success($greeting);
return Command::SUCCESS; // non-zero (Command::FAILURE) signals failure to shells/CI
}
}
// php bin/console app:greet Alice
// php bin/console app:greet Alice --shout
// php bin/console app:greet Alice -vvv — verbose diagnostic outputSymfonyStyle Helpers
$io = new SymfonyStyle($input, $output);
$io->title('Import Report');
$io->success('Imported 42 records');
$io->error('Failed to connect to the API');
$io->table(['ID', 'Name'], [[1, 'Alice'], [2, 'Bob']]);
// Confirm before a destructive action — skippable non-interactively with -n
if (!$io->confirm('Delete all cached data?', false)) {
return Command::SUCCESS;
}
// Progress bar around a long-running loop
$io->progressStart(count($items));
foreach ($items as $item) {
process($item);
$io->progressAdvance();
}
$io->progressFinish();Testing Commands
<?php
use Symfony\Component\Console\Tester\CommandTester;
class GreetCommandTest extends TestCase
{
public function testGreet(): void
{
$command = new GreetCommand();
$tester = new CommandTester($command);
$tester->execute(['name' => 'Alice']);
$this->assertSame(Command::SUCCESS, $tester->getStatusCode());
$this->assertStringContainsString('Hello, Alice!', $tester->getDisplay());
}
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free