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),
    '',
));
Symfony2 - extending the console component
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());
}
Symfony2 - extending the console component
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()
        );
    }
}
Symfony2 - extending the console component
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()
        );
    }
}
Symfony2 - extending the console component
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	
  
Ad

More Related Content

What's hot (20)

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 2010
Fabien 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 fixtures
Bill 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 201
Fabien Potencier
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
Fabien 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-phpapp02
Seri Moth
 
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
 
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 2010
Fabien 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 fixtures
Bill Chang
 
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 201
Fabien 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-phpapp02
Seri Moth
 

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
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 Symfony2
Hugo 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 developers
Kirsten 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
Api 101
Kirsten Hunter
 
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
 
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
 
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 Symfony2
Hugo 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
 
Designing for developers
Designing for developersDesigning for developers
Designing for developers
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
 
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
 
Quantifying your-fitness
Quantifying your-fitnessQuantifying your-fitness
Quantifying your-fitness
Kirsten Hunter
 
Ad

Similar to Symfony2 - extending the console component (20)

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
 
Php & my sql
Php & my sqlPhp & my sql
Php & my sql
Norhisyam Dasuki
 
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
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
Stephan Hochdörfer
 
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 PHPUnit
smueller_sandsmedia
 
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
 
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
 
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
 
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 PHPUnit
smueller_sandsmedia
 
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
 
Ad

More from Hugo Hamon (8)

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 Jenkins
Hugo 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 Framework
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 Jenkins
Hugo 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 Framework
Hugo Hamon
 

Recently uploaded (20)

Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath MaestroDev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
UiPathCommunity
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdfComplete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Software Company
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025Splunk Security Update | Public Sector Summit Germany 2025
Splunk Security Update | Public Sector Summit Germany 2025
Splunk
 
Big Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur MorganBig Data Analytics Quick Research Guide by Arthur Morgan
Big Data Analytics Quick Research Guide by Arthur Morgan
Arthur Morgan
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath MaestroDev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
UiPathCommunity
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
Linux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdfLinux Professional Institute LPIC-1 Exam.pdf
Linux Professional Institute LPIC-1 Exam.pdf
RHCSA Guru
 
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptxSpecial Meetup Edition - TDX Bengaluru Meetup #52.pptx
Special Meetup Edition - TDX Bengaluru Meetup #52.pptx
shyamraj55
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?How Can I use the AI Hype in my Business Context?
How Can I use the AI Hype in my Business Context?
Daniel Lehner
 
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdfComplete Guide to Advanced Logistics Management Software in Riyadh.pdf
Complete Guide to Advanced Logistics Management Software in Riyadh.pdf
Software Company
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
Role of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered ManufacturingRole of Data Annotation Services in AI-Powered Manufacturing
Role of Data Annotation Services in AI-Powered Manufacturing
Andrew Leo
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 

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), '', ));
  • 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()); }
  • 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() ); } }
  • 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() ); } }
  • 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