SlideShare a Scribd company logo
Extending and Leveraging
the Power of the CLI.
Who’s talking?


           Hugo
          Hamon
Follow me on Twitter…


        @hhamon
Introduction to the Console
Component
Redondant and
tedious tasks.

CRON jobs and
batch processing.
Code generation.
Interactive setup tools.
Cache clearing / warming.
…
Improve your
productivity and effiency.
Be proud to
be lazy J
Creating new command
line tools in bundles
The Command folder
src/Sensio/Bundle/
HangmanBundle/Command/
GameHangmanCommand.php
Bootstrapping a new command
namespace SensioBundleHangmanBundleCommand;

use SymfonyComponentConsoleCommandCommand;

class GameHangmanCommand extends Command
{
    protected function configure()
    {
        $this
            ->setName('game:hangman')
            ->setDescription('Play the famous hangman game from the CLI')
        ;
    }
}
Adding usage manual
protected function configure()
{
    $this->setHelp(<<<EOF
The <info>game:hangman</info> command starts a new game of the
famous hangman game:

<info>game:hangman 8</info>

Try to guess the hidden <comment>word</comment> whose length is
<comment>8</comment> before you reach the maximum number of
<comment>attempts</comment>.

You can also configure the maximum number of attempts
with the <info>--max-attempts</info> option:

<info>game:hangman 8 --max-attempts=5</info>
EOF);
}
Adding arguments & options
$this->setDefinition(array(

    new InputArgument('length',
InputArgument::REQUIRED, 'The length of the word to
guess'),

     new InputOption('max-attempts', null,
InputOption::VALUE_OPTIONAL, 'Max number of
attempts', 10),

));
$ php app/console help game:hangman
Executing a command
protected function execute(
    InputInterface $input,
    OutputInterface $output)
{

    // the business logic goes here...

}
InputInterface
namespace SymfonyComponentConsoleInput;

interface InputInterface
{
    function getFirstArgument();
    function hasParameterOption($values);
    function getParameterOption($values, $default = false);
    function bind(InputDefinition $definition);
    function validate();
    function isInteractive();

    function   getArguments();
    function   getArgument($name);
    function   getOptions();
    function   getOption($name);
}
OutputInterface
interface OutputInterface
{
    function write($messages, $newline, $type);
    function writeln($messages, $type = 0);

    function   setVerbosity($level);
    function   getVerbosity();
    function   setDecorated($decorated);
    function   isDecorated();
    function   setFormatter($formatter);
    function   getFormatter();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
    $dictionary = array(
        7 => array('program', 'speaker', 'symfony'),
        8 => array('business', 'software', 'hardware'),
        9 => array('algorithm', 'framework', 'developer')
    );

    // Read the input
    $length = $input->getArgument('length');
    $attempts = $input->getOption('max-attempts');

    // Find a word to guess
    $words = $dictionary[$length];
    $word = $words[array_rand($words)];

    // Write the output
    $output->writeln(sprintf('The word to guess is %s.', $word));
    $output->writeln(sprintf('Max number of attempts is %u.', $attempts));
}
Validating the input
arguments and options.
Validating input parameters
// Read the input
$length = $input->getArgument('length');
$attempts = $input->getOption('max-attempts');
$lengths = array_keys($dictionary);

if (!in_array($length, $lengths)) {
    throw new InvalidArgumentException(sprintf('The length "%s" must be
an integer between %u and %u.', $length, min($lengths), max($lengths)));
}

if ($attempts < 1) {
    throw new InvalidArgumentException(sprintf('The attempts "%s" must
be a valid integer greater than or equal than 1.', $attempts));
}
$ php app/console game:hangman foo




$ php app/console game:hangman 8 --max-attempts=bar
Formatting the output.
The formatter helper

class FormatterHelper extends Helper
{
    public function formatSection($section, $message, $style);

    public function formatBlock($messages, $style, $large);
}
$formatter->formatBlock('A green information', 'info');

$formatter->formatBlock('A yellow comment', 'comment');

$formatter->formatBlock('A red error', 'error');

$formatter->formatBlock('A custom style', 'bg=blue;fg=white');
// Get the formatter helper
$formatter = $this->getHelperSet()->get('formatter');

// Write the output
$output->writeln(array(
    '',
    $formatter->formatBlock('Welcome in the Hangman Game',
'bg=blue;fg=white', true),
    '',
));

$output->writeln(array(
    $formatter->formatSection('Info', sprintf('You have %u
attempts to guess the hidden word.', $attempts), 'info', true),
    '',
));
Make the command
interact with the end user.
Dialog Helper
class DialogHelper extends Helper
{
    public function ask(...);

    public function askConfirmation(...);

    public function askAndValidate(...);
}
class Command
{
    // ...

    protected function interact(
        InputInterface $input,
        OutputInterface $output
    )
    {
        $dialog = $this->getHelperSet()->get('dialog');

        $answer = $dialog->ask($output, 'Do you enjoy
your Symfony Day 2011?');
    }
}
$dialog = $this->getHelperSet()->get('dialog');

$won = false;
$currentAttempt = 1;

do {

    $letter = $dialog->ask(
        $output, 'Type a letter or a word... '
    );

    $currentAttempt++;

} while (!$won && $currentAttempt <= $attempts);
Asking and validating the answer
do {

    $answer = $dialog->askAndValidate(
        $output,
        'Type a letter or a word... ',
        array($this, 'validateLetter')
    );

    $currentAttempt++;

} while ($currentAttempt <= $attempts);
Asking and validating the answer
public function validateLetter($letter)
{
    $ascii = ord(mb_strtolower($letter));

    if ($ascii < 97 || $ascii > 122) {
        throw new InvalidArgumentException('The expected
letter must be a single character between A and Z.');
    }

    return $letter;
}
Asking and validating the answer
Refactoring your code is
good for your command.
Think your commands as
controllers.
Request <-> Response
  Input <-> Output
The Dictionary class
namespace SensioBundleHangmanBundleGame;

class Dictionary implements Countable
{
    private $words;

      public function addWord($word);

      public function count();

      public function getRandomWord($length);
}
The Game class
namespace SensioBundleHangmanBundleGame;

class Game
{
    public   function   __construct($word, $maxAttempts);
    public   function   getWord();
    public   function   getHiddenWord();
    public   function   getAttempts();
    public   function   tryWord($word);
    public   function   tryLetter($letter);
    public   function   isOver();
    public   function   isWon();
}
Command class refactoring
protected function interact(InputInterface $input, OutputInterface $output)
{
    $length = $input->getArgument('length');
    $attempts = $input->getOption('max-attempts');

    $this->dictionary = new Dictionary();
    $this->dictionary
        ->addWord('program')
         ...
    ;

    $word = $dictionary->getRandomWord($length);
    $this->game = new Game($word, $attempts);
    $this->writeIntro($output, 'Welcome in the Hangman Game');
    $this->writeInfo($output, sprintf('%u attempts to guess the word.', $attempts));
    $this->writeInfo($output, implode(' ', $this->game->getHiddenWord()));
}
Command class refactoring
protected function interact(InputInterface $input, OutputInterface $output)
{
    // ...
    $dialog = $this->getHelperSet()->get('dialog');

     do {
         if ($letter = $dialog->ask($output, 'Type a letter... ')) {
             $this->game->tryLetter($letter);
             $this->writeInfo($output, implode(' ', $this->game->getHiddenWord()));
         }

         if (!$letter && $word = $dialog->ask($output, 'Try a word... ')) {
             $this->game->tryWord($word);
         }
     } while (!$this->game->isOver());
}
Unit testing console
commands
Unit testing is
about testing
your model
classes.
Unit testing the Game class
namespace SensioBundleHangmanBundleTestsGame;

use SensioBundleHangmanBundleGameGame;

class GameTest extends PHPUnit_Framework_TestCase
{
    public function testGameIsWon()
    {
        $game = new Game('foo', 10);
        $game->tryLetter('o');
        $game->tryLetter('f');

         $this->assertEquals(array('f', 'o', 'o'), $game->getHiddenWord());
         $this->assertTrue($game->isWon());
     }
}
Functional testing console
commands
Run the command and
check the output.
The SayHello command
namespace SensioBundleDemoBundleCommand;

class HelloWorldCommand extends Command
{
    // ...

     protected function execute($input, $output)
     {
         $name = $input->getOption('name');

         $output->writeln('Your name is <info>'. $name .'</info>');
     }
}
StreamOutput
class SayHelloCommandTest extends CommandTester
{
    public function testSayHello()
    {
        $input = new ArrayInput(array('name' => 'Hugo'));
        $input->setInteractive(false);

        $output = new StreamOutput();

        $command = new SayHelloCommand();
        $command->run($input, $output);

        $this->assertEquals(
            'Your name is <info>Hugo</info>',
            $output->getStream()
        );
    }
}
CommandTester
namespace SymfonyComponentConsoleTester;

class CommandTester
{
    public function __construct(Command $command);

    public function execute($input, $options);

    public function getDisplay();

    public function getInput();

    public function getOutput();
}
class SayHelloCommandTest extends CommandTester
{
    public function testSayHello()
    {
        $tester = new CommandTester(new SayHelloCommand());

        $tester->execute(array('name' => 'Hugo'), array(
            'interactive' => false
        ));

        $this->assertEquals(
            'Your name is <info>Hugo</info>',
            $tester->getDisplay()
        );
    }
}
Being the God of the
command line J
Container
ContainerAwareInterface
namespace SymfonyComponentDependencyInjection;

interface ContainerAwareInterface
{
    /**
     * Sets the Container.
     *
     * @param ContainerInterface $container
     *
     * @api
     */
    function setContainer(ContainerInterface $container = null);
}
namespace SensioBundleHangmanBundleCommand;

//...
class GameHangmanCommand extends Command implements ContainerAwareInterface
{
    // ...
    private $container;

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $service = $this->container->get('my_service');
    }
}
ContainerAwareCommand
namespace SymfonyBundleFrameworkBundleCommand;

use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentDependencyInjectionContainerInterface;
use SymfonyComponentDependencyInjectionContainerAwareInterface;

abstract class ContainerAwareCommand extends Command implements
ContainerAwareInterface
{
    private $container;

    protected function getContainer()
    {
        if (null === $this->container) {
            $this->container = $this->getApplication()->getKernel()->getContainer();
        }

        return $this->container;
    }

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }
}
Reading the con guration


$container = $this->getContainer();

$max = $container->getParameter('hangman.max_attempts');
Accessing the Doctrine registry
$container = $this->getContainer();

$doctrine = $container->get('doctrine');
$em = $doctrine->getEntityManager('default');

$score = new Score();
$score->setScore(10);
$score->setPlayer('hhamon');

$em->persist($score);
$em->flush();
Rendering Twig templates

$container = $this->getContainer();

$templating = $container->get('templating'):

$content = $templating->render(
    'SensioHangmanBundle:Game:finish.txt.twig',
    array('game' => $this->game)
);
Generating urls
$container = $this->getContainer();

$router = $container->get('router'):

$url = $router->generate(
    'game_finish',
    array('user' => 'hhamon'),
    true
);
Translating messages
$container = $this->getContainer();

$translator = $container->get('translator'):

$content = $translator->trans(
    'Hello %user%!',
    array('user' => 'hhamon'),
    null,
    'fr'
);
Writing logs

$container = $this->getContainer();

$logger = $container->get('logger');

$logger->info('Game finished!');
Dealing with the lesystem

$container = $this->getContainer();

$fs = $container->get('filesystem');

$fs->touch('/path/to/toto.txt');
Conclusion
Questions & Answers


 Ask a (little) ninja J
•  Calling	
  a	
  command	
  from	
  a	
  command	
  
•  Calling	
  a	
  command	
  in	
  a	
  command	
  
•  Sending	
  an	
  email	
  

More Related Content

What's hot

Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
Jeroen van Dijk
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
Ricardo Signes
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHPObject Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
Guilherme Blanco
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
Marcello Duarte
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
Sérgio Rafael Siqueira
 
PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language Trivia
Nikita Popov
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien Potencier
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
Ross Tuck
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Elixir cheatsheet
Elixir cheatsheetElixir cheatsheet
Elixir cheatsheet
Héla Ben Khalfallah
 
Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6
garux
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
Jorn Oomen
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
Mark Baker
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
Kacper Gunia
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
Rafael Dohms
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 

What's hot (20)

Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHPObject Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
 
PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language Trivia
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Elixir cheatsheet
Elixir cheatsheetElixir cheatsheet
Elixir cheatsheet
 
Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02
 

Viewers also liked

API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat Conference
Kirsten Hunter
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
Konstantin Kudryashov
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
Kirsten Hunter
 
Quantifying fitness
Quantifying fitnessQuantifying fitness
Quantifying fitness
Kirsten Hunter
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
Hugo Hamon
 
API First
API FirstAPI First
API First
Kirsten Hunter
 
Facebook appsincloud
Facebook appsincloudFacebook appsincloud
Facebook appsincloud
Kirsten Hunter
 
Designing for developers
Designing for developersDesigning for developers
Designing for developersKirsten Hunter
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
Kirsten Hunter
 
Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
Hugo Hamon
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloud
Kirsten Hunter
 
Api 101
Api 101Api 101
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
Mark Heckler
 
Symfony2 en pièces détachées
Symfony2 en pièces détachéesSymfony2 en pièces détachées
Symfony2 en pièces détachées
Hugo Hamon
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
Hugo Hamon
 
Polyglot copy
Polyglot copyPolyglot copy
Polyglot copy
Kirsten Hunter
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitness
Kirsten Hunter
 

Viewers also liked (20)

API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat Conference
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
 
Quantifying fitness
Quantifying fitnessQuantifying fitness
Quantifying fitness
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
API First
API FirstAPI First
API First
 
Facebook appsincloud
Facebook appsincloudFacebook appsincloud
Facebook appsincloud
 
Designing for developers
Designing for developersDesigning for developers
Designing for developers
 
Liberating your data
Liberating your dataLiberating your data
Liberating your data
 
Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloud
 
Api 101
Api 101Api 101
Api 101
 
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
This stuff is cool, but...HOW CAN I GET MY COMPANY TO DO IT?
 
Symfony2 en pièces détachées
Symfony2 en pièces détachéesSymfony2 en pièces détachées
Symfony2 en pièces détachées
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
 
Polyglot copy
Polyglot copyPolyglot copy
Polyglot copy
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitness
 

Similar to Symfony2 - extending the console component

Php functions
Php functionsPhp functions
Php functions
JIGAR MAKHIJA
 
Taking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsTaking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order Functions
David Golden
 
Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"
Fwdays
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
Daniel Knell
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
Bastian Feder
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
Jace Ju
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
Abbas Ali
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
Nate Abele
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Kang-min Liu
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
Lars Jankowfsky
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
XSolve
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitsmueller_sandsmedia
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
Value objects
Value objectsValue objects
Value objects
Barry O Sullivan
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
Pete McFarlane
 

Similar to Symfony2 - extending the console component (20)

Php functions
Php functionsPhp functions
Php functions
 
Taking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsTaking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order Functions
 
Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Value objects
Value objectsValue objects
Value objects
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 

More from Hugo Hamon

Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
Hugo Hamon
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
Hugo Hamon
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsHugo Hamon
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
Hugo Hamon
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
Hugo Hamon
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkHugo Hamon
 

More from Hugo Hamon (8)

Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
 

Recently uploaded

Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
Vlad Stirbu
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
James Anderson
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 

Recently uploaded (20)

Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
Alt. GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using ...
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 

Symfony2 - extending the console component

  • 1. Extending and Leveraging the Power of the CLI.
  • 2. Who’s talking? Hugo Hamon
  • 3. Follow me on Twitter… @hhamon
  • 4. Introduction to the Console Component
  • 5. Redondant and tedious tasks. CRON jobs and batch processing.
  • 6. Code generation. Interactive setup tools. Cache clearing / warming. …
  • 8. Be proud to be lazy J
  • 9. Creating new command line tools in bundles
  • 12. Bootstrapping a new command namespace SensioBundleHangmanBundleCommand; use SymfonyComponentConsoleCommandCommand; class GameHangmanCommand extends Command { protected function configure() { $this ->setName('game:hangman') ->setDescription('Play the famous hangman game from the CLI') ; } }
  • 14. protected function configure() { $this->setHelp(<<<EOF The <info>game:hangman</info> command starts a new game of the famous hangman game: <info>game:hangman 8</info> Try to guess the hidden <comment>word</comment> whose length is <comment>8</comment> before you reach the maximum number of <comment>attempts</comment>. You can also configure the maximum number of attempts with the <info>--max-attempts</info> option: <info>game:hangman 8 --max-attempts=5</info> EOF); }
  • 15. Adding arguments & options $this->setDefinition(array( new InputArgument('length', InputArgument::REQUIRED, 'The length of the word to guess'), new InputOption('max-attempts', null, InputOption::VALUE_OPTIONAL, 'Max number of attempts', 10), ));
  • 16. $ php app/console help game:hangman
  • 17. Executing a command protected function execute( InputInterface $input, OutputInterface $output) { // the business logic goes here... }
  • 19. namespace SymfonyComponentConsoleInput; interface InputInterface { function getFirstArgument(); function hasParameterOption($values); function getParameterOption($values, $default = false); function bind(InputDefinition $definition); function validate(); function isInteractive(); function getArguments(); function getArgument($name); function getOptions(); function getOption($name); }
  • 21. interface OutputInterface { function write($messages, $newline, $type); function writeln($messages, $type = 0); function setVerbosity($level); function getVerbosity(); function setDecorated($decorated); function isDecorated(); function setFormatter($formatter); function getFormatter(); }
  • 22. protected function execute(InputInterface $input, OutputInterface $output) { $dictionary = array( 7 => array('program', 'speaker', 'symfony'), 8 => array('business', 'software', 'hardware'), 9 => array('algorithm', 'framework', 'developer') ); // Read the input $length = $input->getArgument('length'); $attempts = $input->getOption('max-attempts'); // Find a word to guess $words = $dictionary[$length]; $word = $words[array_rand($words)]; // Write the output $output->writeln(sprintf('The word to guess is %s.', $word)); $output->writeln(sprintf('Max number of attempts is %u.', $attempts)); }
  • 24. Validating input parameters // Read the input $length = $input->getArgument('length'); $attempts = $input->getOption('max-attempts'); $lengths = array_keys($dictionary); if (!in_array($length, $lengths)) { throw new InvalidArgumentException(sprintf('The length "%s" must be an integer between %u and %u.', $length, min($lengths), max($lengths))); } if ($attempts < 1) { throw new InvalidArgumentException(sprintf('The attempts "%s" must be a valid integer greater than or equal than 1.', $attempts)); }
  • 25. $ php app/console game:hangman foo $ php app/console game:hangman 8 --max-attempts=bar
  • 27. The formatter helper class FormatterHelper extends Helper { public function formatSection($section, $message, $style); public function formatBlock($messages, $style, $large); }
  • 28. $formatter->formatBlock('A green information', 'info'); $formatter->formatBlock('A yellow comment', 'comment'); $formatter->formatBlock('A red error', 'error'); $formatter->formatBlock('A custom style', 'bg=blue;fg=white');
  • 29. // Get the formatter helper $formatter = $this->getHelperSet()->get('formatter'); // Write the output $output->writeln(array( '', $formatter->formatBlock('Welcome in the Hangman Game', 'bg=blue;fg=white', true), '', )); $output->writeln(array( $formatter->formatSection('Info', sprintf('You have %u attempts to guess the hidden word.', $attempts), 'info', true), '', ));
  • 30.
  • 31. Make the command interact with the end user.
  • 33. class DialogHelper extends Helper { public function ask(...); public function askConfirmation(...); public function askAndValidate(...); }
  • 34. class Command { // ... protected function interact( InputInterface $input, OutputInterface $output ) { $dialog = $this->getHelperSet()->get('dialog'); $answer = $dialog->ask($output, 'Do you enjoy your Symfony Day 2011?'); } }
  • 35. $dialog = $this->getHelperSet()->get('dialog'); $won = false; $currentAttempt = 1; do { $letter = $dialog->ask( $output, 'Type a letter or a word... ' ); $currentAttempt++; } while (!$won && $currentAttempt <= $attempts);
  • 36. Asking and validating the answer do { $answer = $dialog->askAndValidate( $output, 'Type a letter or a word... ', array($this, 'validateLetter') ); $currentAttempt++; } while ($currentAttempt <= $attempts);
  • 37. Asking and validating the answer public function validateLetter($letter) { $ascii = ord(mb_strtolower($letter)); if ($ascii < 97 || $ascii > 122) { throw new InvalidArgumentException('The expected letter must be a single character between A and Z.'); } return $letter; }
  • 38. Asking and validating the answer
  • 39. Refactoring your code is good for your command.
  • 40. Think your commands as controllers.
  • 41. Request <-> Response Input <-> Output
  • 42. The Dictionary class namespace SensioBundleHangmanBundleGame; class Dictionary implements Countable { private $words; public function addWord($word); public function count(); public function getRandomWord($length); }
  • 43. The Game class namespace SensioBundleHangmanBundleGame; class Game { public function __construct($word, $maxAttempts); public function getWord(); public function getHiddenWord(); public function getAttempts(); public function tryWord($word); public function tryLetter($letter); public function isOver(); public function isWon(); }
  • 44. Command class refactoring protected function interact(InputInterface $input, OutputInterface $output) { $length = $input->getArgument('length'); $attempts = $input->getOption('max-attempts'); $this->dictionary = new Dictionary(); $this->dictionary ->addWord('program') ... ; $word = $dictionary->getRandomWord($length); $this->game = new Game($word, $attempts); $this->writeIntro($output, 'Welcome in the Hangman Game'); $this->writeInfo($output, sprintf('%u attempts to guess the word.', $attempts)); $this->writeInfo($output, implode(' ', $this->game->getHiddenWord())); }
  • 45. Command class refactoring protected function interact(InputInterface $input, OutputInterface $output) { // ... $dialog = $this->getHelperSet()->get('dialog'); do { if ($letter = $dialog->ask($output, 'Type a letter... ')) { $this->game->tryLetter($letter); $this->writeInfo($output, implode(' ', $this->game->getHiddenWord())); } if (!$letter && $word = $dialog->ask($output, 'Try a word... ')) { $this->game->tryWord($word); } } while (!$this->game->isOver()); }
  • 46.
  • 48. Unit testing is about testing your model classes.
  • 49. Unit testing the Game class namespace SensioBundleHangmanBundleTestsGame; use SensioBundleHangmanBundleGameGame; class GameTest extends PHPUnit_Framework_TestCase { public function testGameIsWon() { $game = new Game('foo', 10); $game->tryLetter('o'); $game->tryLetter('f'); $this->assertEquals(array('f', 'o', 'o'), $game->getHiddenWord()); $this->assertTrue($game->isWon()); } }
  • 51. Run the command and check the output.
  • 52. The SayHello command namespace SensioBundleDemoBundleCommand; class HelloWorldCommand extends Command { // ... protected function execute($input, $output) { $name = $input->getOption('name'); $output->writeln('Your name is <info>'. $name .'</info>'); } }
  • 54. class SayHelloCommandTest extends CommandTester { public function testSayHello() { $input = new ArrayInput(array('name' => 'Hugo')); $input->setInteractive(false); $output = new StreamOutput(); $command = new SayHelloCommand(); $command->run($input, $output); $this->assertEquals( 'Your name is <info>Hugo</info>', $output->getStream() ); } }
  • 55.
  • 57. namespace SymfonyComponentConsoleTester; class CommandTester { public function __construct(Command $command); public function execute($input, $options); public function getDisplay(); public function getInput(); public function getOutput(); }
  • 58. class SayHelloCommandTest extends CommandTester { public function testSayHello() { $tester = new CommandTester(new SayHelloCommand()); $tester->execute(array('name' => 'Hugo'), array( 'interactive' => false )); $this->assertEquals( 'Your name is <info>Hugo</info>', $tester->getDisplay() ); } }
  • 59.
  • 60. Being the God of the command line J
  • 63. namespace SymfonyComponentDependencyInjection; interface ContainerAwareInterface { /** * Sets the Container. * * @param ContainerInterface $container * * @api */ function setContainer(ContainerInterface $container = null); }
  • 64. namespace SensioBundleHangmanBundleCommand; //... class GameHangmanCommand extends Command implements ContainerAwareInterface { // ... private $container; public function setContainer(ContainerInterface $container = null) { $this->container = $container; } protected function execute(InputInterface $input, OutputInterface $output) { $service = $this->container->get('my_service'); } }
  • 66. namespace SymfonyBundleFrameworkBundleCommand; use SymfonyComponentConsoleCommandCommand; use SymfonyComponentDependencyInjectionContainerInterface; use SymfonyComponentDependencyInjectionContainerAwareInterface; abstract class ContainerAwareCommand extends Command implements ContainerAwareInterface { private $container; protected function getContainer() { if (null === $this->container) { $this->container = $this->getApplication()->getKernel()->getContainer(); } return $this->container; } public function setContainer(ContainerInterface $container = null) { $this->container = $container; } }
  • 67. Reading the con guration $container = $this->getContainer(); $max = $container->getParameter('hangman.max_attempts');
  • 68. Accessing the Doctrine registry $container = $this->getContainer(); $doctrine = $container->get('doctrine'); $em = $doctrine->getEntityManager('default'); $score = new Score(); $score->setScore(10); $score->setPlayer('hhamon'); $em->persist($score); $em->flush();
  • 69. Rendering Twig templates $container = $this->getContainer(); $templating = $container->get('templating'): $content = $templating->render( 'SensioHangmanBundle:Game:finish.txt.twig', array('game' => $this->game) );
  • 70. Generating urls $container = $this->getContainer(); $router = $container->get('router'): $url = $router->generate( 'game_finish', array('user' => 'hhamon'), true );
  • 71. Translating messages $container = $this->getContainer(); $translator = $container->get('translator'): $content = $translator->trans( 'Hello %user%!', array('user' => 'hhamon'), null, 'fr' );
  • 72. Writing logs $container = $this->getContainer(); $logger = $container->get('logger'); $logger->info('Game finished!');
  • 73. Dealing with the lesystem $container = $this->getContainer(); $fs = $container->get('filesystem'); $fs->touch('/path/to/toto.txt');
  • 75. Questions & Answers Ask a (little) ninja J
  • 76. •  Calling  a  command  from  a  command   •  Calling  a  command  in  a  command   •  Sending  an  email