Symfony Console
01 / 02

Building Commands

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 output

SymfonyStyle 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