Loïc Faugeron Technical Blog

The Ultimate Developer Guide to Symfony - Console 02/03/2016

Reference: This article is intended to be as complete as possible and is kept up to date.

TL;DR: $statusCode = $application->run($input);

In this guide we explore the standalone libraries (also known as "Components") provided by Symfony to help us build applications.

We've already seen:

We're now about to check the last one: Console.

In the next articles we'll also see how HttpKernel enables reusable code with Bundles, and the different ways to organize our application tree directory.

Finally we'll finish by putting all this knowledge in practice by creating a "fortune" project with:

Application

Symfony provides a Console component which allows us to create CLI commands. Its main class is Application:

<?php

namespace Symfony\Component\Console;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Command\Command;

class Application
{
    public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN');

    public function add(Command $command);
    public function setDefaultCommand($commandName);
    public function run(InputInterface $input = null, OutputInterface $output = null);

    public function setAutoExit($boolean);
}

Note: This snippet is a truncated version. Please note that Application is (unfortunately) not an interface.

We can create it as follow:

<?php
// /tmp/console.php

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;

$application = new Application('My Application', 'v4.2.3');
$application->add($command);
$application->setDefaultCommand($command->getName());

$application->run(new ArgvInput());

Which can then be used as follow:

php /tmp/console.php

Note: After running the command, Application will automatically stop using exit. As it can sometimes be inconvenient (for example in tests), we can disable it with this line: $application->setAutoExit(false);

Out of the box, Application has two commands:

Command

In order for Application to be useful, we need to create commands. This can be done by extending Command:

<?php

namespace Symfony\Component\Console\Command;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class Command
{
    public function run(InputInterface $input, OutputInterface $output);
    // Called by run
    protected function execute(InputInterface $input, OutputInterface $output);
    protected function interact(InputInterface $input, OutputInterface $output);

    protected function configure();
    // To be called in configure
    public function setName($name);
    public function addArgument($name, $mode = null, $description = '', $default = null);
    public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null);
    public function setDescription($description);
    public function setHelp($help);
    public function setAliases($aliases);
}

We can configure the command (name, arguments, options, description, etc) in the configure method, we can define more options to be asked interractively in the interact method (e.g. Are you sure? (Y/n)) and finally we can write the command logic in the execute method.

Commands are to Console what Controllers are to HttpKernel: their responsibility is to extract input parameters, pass them to a service and then put the service's returned value in the output.

Input

Input parameters are wrapped in the following interface:

<?php

namespace Symfony\Component\Console\Input;

interface InputInterface
{
    public function getArgument($name);
    public function getOption($name);
}

Out of the box we have the following implementations:

Application will take care of validating InputInterface parameters against the Command configuration (e.g. if required arguments present).

Output

While InputInterface can be seen as a value object, OutputInterface should be seen as a service able to send informations to a stream:

<?php

namespace Symfony\Component\Console\Output;

abstract class Output implements OutputInterface
{
    public function writeln($messages, $type = self::OUTPUT_NORMAL);
}

The writeln method allows us to write a new line (with a newline character at the end). If the given message is an array, it will print each elements on a new line.

The given message can contain tags (e.g. Arthur <info>Dent</info>), which can be used to format it. Out of the box it will color the followings:

Conclusion

The Console component allows us to create CLI applications. Its Commands are a thin layer which gathers the input and call services. Those services can then output messages to the user.

Note: Since Symfony follows a Console Output Formating Style Guide, the Console component provides the following helper class:

<?php

namespace Symfony\Component\Console\Style;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;

class SymfonyStyle
{
    public function __construct(InputInterface $input, OutputInterface $output);

    public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false);
    public function title($message);
    public function section($message);
    public function listing(array $elements);
    public function text($message);

    public function comment($message);
    public function success($message);
    public function error($message);
    public function warning($message);
    public function note($message);
    public function caution($message);

    public function table(array $headers, array $rows);

    public function ask($question, $default = null, $validator = null);
    public function askHidden($question, $validator = null);
    public function confirm($question, $default = true);
    public function choice($question, array $choices, $default = null);
    public function askQuestion(Question $question);

    public function progressStart($max = 0);
    public function progressAdvance($step = 1);
    public function progressFinish();
    public function createProgressBar($max = 0);

    public function writeln($messages, $type = self::OUTPUT_NORMAL);
    public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL);
    public function newLine($count = 1);
}