Symfony2 Console Component

PHP CLI Scripts reloaded





Liip Techtalk, 13.6.2013 © David Buchmann, Liip AG

Symfony2 Console Component

Minimal Command

namespace Acme\DemoBundle\Command;

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

class GreetCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('demo:greet')
            ->setDescription('Greet someone')
        ;
    }

    protected function execute(InputInterface $input,
                               OutputInterface $output)
    {
        $output->writeln('Hello');
    }
}
            

Define Command Arguments

protected function configure()
{
    $this
        ...
        ->addArgument(
            'name',
            InputArgument::OPTIONAL,
            'Who do you want to greet?'
        )
        ->addOption(
            'yell',
            null,
           InputOption::VALUE_NONE,
           'If set, the task will yell in uppercase letters'
        )
    ;
}

        

Using Command Arguments

protected function execute(InputInterface $input,
                           OutputInterface $output)
{
    $name = $input->getArgument('name');
    if ($name) {
        $text = 'Hello '.$name;
    } else {
        $text = 'Hello';
    }

    if ($input->getOption('yell')) {
        $text = strtoupper($text);
    }

    $output->writeln($text);
}
        

Color Output

protected function execute(InputInterface $input,
                           OutputInterface $output)
{
    $output->writeln("<error>Something went wrong</error>");
    $output->writeln("<info>Some information</info>");
}
        

You can also configure custom tags with custom colors.

Accessing the container

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;

class GreetCommand extends ContainerAwareCommand
{
    protected function execute(InputInterface $input,
                               OutputInterface $output)
    {
        $message = \Swift_Message::newInstance()
            ->setSubject('Test Email')
            ->setFrom('david@liip.ch')
            ->setTo('tech@liip.ch')
            ->setBody('Hello World')
        ;

        $mailer = $this->getContainer()->get('mailer);
        $mailer->send($message);
    }
}
            

Or implement ContainerAwareInterface and copy the methods from ContainerAwareCommand.

Console Helpers

Dialog Helper Confirmation

if (!$dialog->askConfirmation(
    $output,
    '<question>Continue with this action?</question>',
    false
)) {
    return 1;
}
        

Dialog Helper Autocomplete Information

$dialog = $this->getHelperSet()->get('dialog');
$targets = array('David', 'Dash', 'Liip');
$name = $dialog->ask(
    $output,
    'Who does this concern',
    'Fabien',
    $targets
);
            

Command Tester

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Acme\DemoBundle\Command\GreetCommand;

class GreetCommandTest extends \PHPUnit_Framework_TestCase
{
    public function testNameIsOutput()
    {
        $application = new Application();
        $application->add(new GreetCommand());

        $command = $application->find('demo:greet');
        $commandTester = new CommandTester($command);
        $commandTester->execute(array(
            'command' => $command->getName(),
            'name' => 'Fabien',
        ));

        $this->assertRegExp('/Fabien/',
                            $commandTester->getDisplay());
    }
}
            

Testing interactive input

public function testExecute()
{
    $commandTester = new CommandTester($command);

    $dialog = $command->getHelper('dialog');
    $dialog->setInputStream($this->getInputStream('yes\n'));
    // Equals to a user inputing "yes" and hitting ENTER

    $commandTester->execute(
        array('command' => $command->getName())
    );
    // assertions on output
}

protected function getInputStream($input)
{
    $stream = fopen('php://memory', 'r+', false);
    fputs($stream, $input);
    rewind($stream);

    return $stream;
}
            

Console stand alone

#!/usr/bin/env php
<?php
// bin/console
use Symfony\Component\Console\Application;
use Acme\DemoBundle\Command\GreetCommand;

// use composer to generate your autoload
require __DIR__ '/../vendor/autoload.php';

$cli = new Application('Test Command Line Interface', '0.1');
$cli->setCatchExceptions(true);
$cli->addCommands(array(
    new GreetCommand(),
    // more commands...
));
$cli->run();
            

Provide a helper

// bin/console
use Symfony\Component\Console\Helper\HelperSet;
use PHPCR\Util\Console\Helper\PhpcrHelper;

...

$helperSet = new HelperSet(array(
    'session' => new PhpcrHelper($session)
));

/** @var $cli Application */
$cli->setHelperSet($helperSet);
            

Stand alone console

RTFM :-)



symfony.com/doc/master/components/console


Look at some real commands

Thank you!



Questions / Input / Feedback ?



@dbu