SlideShare uma empresa Scribd logo
1 de 76
Baixar para ler offline
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	
  

Mais conteúdo relacionado

Mais procurados

Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen 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.16Ricardo Signes
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHPObject Calisthenics Applied to PHP
Object Calisthenics Applied to PHPGuilherme Blanco
 
PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language TriviaNikita 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 clienteLeonardo 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 TownRoss Tuck
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Introdução ao Perl 6
Introdução ao Perl 6Introdução ao Perl 6
Introdução ao Perl 6garux
 
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 softwareJorn Oomen
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark 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 2Kacper 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. - PHPKonfRafael Dohms
 
Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Jsphp 110312161301-phpapp02
Jsphp 110312161301-phpapp02Seri Moth
 

Mais procurados (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
 

Destaque

API 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceAPI 101 Workshop from APIStrat Conference
API 101 Workshop from APIStrat ConferenceKirsten 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 mockingKonstantin 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 PimpleHugo Hamon
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo 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 PerformantHugo Hamon
 
Designing for developers
Designing for developersDesigning for developers
Designing for developersKirsten 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 projectsHugo Hamon
 
Prototyping in the cloud
Prototyping in the cloudPrototyping in the cloud
Prototyping in the cloudKirsten 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éesHugo 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-fitnessKirsten Hunter
 

Destaque (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
 

Semelhante a Symfony2 - extending the console component

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 FunctionsDavid 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 technologyDaniel Knell
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsBastian Feder
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of LithiumNate 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 / XSolveXSolve
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian 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
 
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 tomorrowPete McFarlane
 

Semelhante a 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
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
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
 
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
 

Mais de Hugo Hamon

Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo 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 CIHugo 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 Symfony2Hugo 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 SymfonyHugo Hamon
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2Hugo 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
 

Mais de 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
 

Último

What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 

Último (20)

What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

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