Creating Your Own Console Commands
Creating Your Own Console Commands
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
We've used bin/console since chapter 3 for Symfony's OWN commands – now let's build our FIRST custom command: listing overdue tasks from chapter 24.
Generating a command
php bin/console make:command app:list-overdue-tasks<?php
declare(strict_types=1);
namespace App\Command;
use App\Repository\TaskRepository;
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:list-overdue-tasks',
description: 'Lists all overdue tasks',
)]
class ListOverdueTasksCommand extends Command
{
public function __construct(
private readonly TaskRepository $taskRepository,
) {
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$tasks = $this->taskRepository->findOverdueTasks();
if (count($tasks) === 0) {
$io->success('No overdue tasks!');
return Command::SUCCESS;
}
$io->warning(sprintf('%d overdue task(s) found:', count($tasks)));
foreach ($tasks as $task) {
$io->writeln(sprintf(
'- %s (due: %s)',
$task->getTitle(),
$task->getDueAt()?->format('Y-m-d') ?? 'unknown',
));
}
return Command::SUCCESS;
}
}EXACTLY like controllers (chapter 8): the __construct() parameter TaskRepository gets resolved automatically via autowiring – console commands are, like EVERYTHING in this course, ORDINARY services (chapters 32-34).
Running the command
php bin/console app:list-overdue-tasksSymfonyStyle: consistent, formatted terminal output
$io->success(...)– green-highlighted success message.$io->warning(...)– yellow-highlighted warning.$io->error(...)– red-highlighted error message.$io->table(...)– formatted table (useful for structured overviews).$io->progressBar(...)– a progress bar for longer-running operations.
SymfonyStyle is the RECOMMENDED way to communicate with the terminal – compared to raw $output->writeln(...), it ensures a consistent, professional look ACROSS all of a project's commands.
Understanding exit codes: Command::SUCCESS and Command::FAILURE
execute()'s return value becomes the actual process exit code – DECISIVE for automation (shell scripts, CI/CD, chapter 41's cron jobs usually check this value):
return Command::SUCCESS; // exit code 0 - all good
return Command::FAILURE; // exit code 1 - something failed
return Command::INVALID; // exit code 2 - wrong input/usagephp bin/console app:list-overdue-tasks
echo $? # shows the last statement's exit code - 0 means successTipp: In a shell script or CI/CD context ("run this command, and abort the whole deployment process on error"), the exit code is the ONLY thing automation relies on – a command that ALWAYS returns Command::SUCCESS, even on an internal error, would make problems INVISIBLE.