Skip to content

[RFC][Console] Added console style guide helpers #12035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 24 commits into from
Closed

[RFC][Console] Added console style guide helpers #12035

wants to merge 24 commits into from

Conversation

kbond
Copy link
Member

@kbond kbond commented Sep 25, 2014

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? todo
Fixed tickets #12014
License MIT
Doc PR todo

Proposed API

Code

// Symfony command
protected function execute(InputInterface $input, OutputInterface $output)
{
    $output = new StandardOutputStyle($output);

    $output->title('Lorem Ipsum Dolor Sit Amet');
    $output->text(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat'
    ));
    $output->ln();

    $output->table(array('Name', 'Method', 'Scheme', 'Host', 'Path'), array(
            array('admin_post_new', 'ANY', 'ANY', 'ANY', '/admin/post/new'),
            array('admin_post_show', 'GET', 'ANY', 'ANY', '/admin/post/{id}'),
            array('admin_post_edit', 'ANY', 'ANY', 'ANY', '/admin/post/{id}/edit'),
            array('admin_post_delete', 'DELETE', 'ANY', 'ANY', '/admin/post/{id}'),
        ));

    $output->caution(array(
            'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.',
            'foo'
        ));
    $output->section('Consectetur Adipisicing Elit Sed Do Eiusmod');
    $output->listing(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod, tempor incididunt ut labore et dolore magna aliqua.',
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.',
        'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
    ));

    $customValidator = function ($value) {
        if ($value == 'foo') {
            throw new \Exception('cannot be foo');
        }

        return $value;
    };

    // hidden question
    $output->note($output->askHidden('Hidden question'));

    // choice questions
    $output->note($output->choice('Choice question no default', array('choice1', 'choice2')));
    $output->note($output->choice('Choice question with default', array('choice1', 'choice2'), 'choice1'));

    // confirmation questions
    $output->note($output->confirm('Confirmation with yes default', true) ? 'yes' : 'no');
    $output->note($output->confirm('Confirmation with no default', false) ? 'yes' : 'no');

    // standard questions
    $output->note($output->ask('Question no default'));
    $output->note($output->ask('Question no default and custom validator', null, $customValidator));
    $output->note($output->ask('Question with default', 'default'));
    $output->note($output->ask('Question with default and custom validator', 'default', $customValidator));

    $output->note('Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.');
    $output->success('Lorem ipsum dolor sit amet, consectetur adipisicing elit');
    $output->error('Duis aute irure dolor in reprehenderit in voluptate velit esse.');
    $output->warning('Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.');
}

Output

$ php app/console command

Lorem Ipsum Dolor Sit Amet
==========================

 // Duis aute irure dolor in reprehenderit in voluptate velit esse
 // cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat

 ------------------- -------- -------- ------ ----------------------- 
  Name                Method   Scheme   Host   Path                   
 ------------------- -------- -------- ------ ----------------------- 
  admin_post_new      ANY      ANY      ANY    /admin/post/new        
  admin_post_show     GET      ANY      ANY    /admin/post/{id}       
  admin_post_edit     ANY      ANY      ANY    /admin/post/{id}/edit  
  admin_post_delete   DELETE   ANY      ANY    /admin/post/{id}       
 ------------------- -------- -------- ------ -----------------------

 ! [CAUTION] Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et    
 ! dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, 
 ! consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim    
 ! veniam, quis nostrud exercitation ullamco laboris.                                                                   
 !                                                                                                                      
 ! foo                                                                                                                  

Consectetur Adipisicing Elit Sed Do Eiusmod
-------------------------------------------

 * Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod, tempor incididunt ut labore et dolore magna aliqua.

 * Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

 * Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Hidden question:
 > <f><o><o><enter>

 ! [NOTE] foo

 Choice question no default:
  [0] choice1
  [1] choice2
 > <enter>

 [ERROR] Value "" is invalid                                                                                            

 Choice question no default:
  [0] choice1
  [1] choice2
 > 0<enter>

 ! [NOTE] choice1                                                                                                       

 Choice question with default [choice1]:
  [0] choice1
  [1] choice2
 > 1<enter>

 ! [NOTE] choice2                                                                                                       

 Confirmation with yes default (yes/no) [yes]:
 > <enter>

 ! [NOTE] yes                                                                                                           

 Confirmation with no default (yes/no) [no]:
 > <enter>

 ! [NOTE] no                                                                                                            

 Question no default:
 > <enter>

 [ERROR] A value is required.                                                                                           

 Question no default:
 > foo<enter>

 ! [NOTE] foo                                                                                                           

 Question no default and custom validator:
 > foo<enter>

 [ERROR] cannot be foo                                                                                                  

 Question no default and custom validator:
 > <enter>

 [ERROR] A value is required.                                                                                           

 Question no default and custom validator:
 > foo<enter>

 [ERROR] cannot be foo                                                                                                  

 Question no default and custom validator:
 > bar<enter>

 ! [NOTE] bar                                                                                                           

 Question with default [default]:
 > <enter>

 ! [NOTE] default                                                                                                       

 Question with default and custom validator [default]:
 > <enter>

 ! [NOTE] default                                                                                                       

 ! [NOTE] Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.        
 ! Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu   
 ! fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit  
 ! esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.                                      

 [OK] Lorem ipsum dolor sit amet, consectetur adipisicing elit                                                          

 [ERROR] Duis aute irure dolor in reprehenderit in voluptate velit esse.                                                

 [WARNING] Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.                                     

Screenshots

screen1

screen2

screen3

protected $messages;
protected $style;
protected $large;
protected $padLength;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these should be private

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need the messages property in a subclass... should I make a getter?

@javiereguiluz
Copy link
Member

Thanks @kbond for your work!! I'd like to propose you something: as we are talking about DX, the internal source code of these helpers doesn't matter a this moment. What I'd like to see is the real code that developers must write to apply this style guide. The public API must be concise, beautiful, memorable, etc. Otherwise, this initiative will fail.

That's why I've prepared a Full Sample Command which contains all the elements of the command output. This is the image of how it would look:

full_sample_command

This is the full text that should be output to the console:

$ php app/console command

Lorem Ipsum Dolor Sit Amet
==========================

 // Duis aute irure dolor in reprehenderit in voluptate velit esse
 // cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat

 Name               Method  Scheme  Host  Path
 -----------------  ------  ------  ----  ---------------------
 admin_post_new     ANY     ANY     ANY   /admin/post/new
 admin_post_show    GET     ANY     ANY   /admin/post/{id}
 admin_post_edit    ANY     ANY     ANY   /admin/post/{id}/edit
 admin_post_delete  DELETE  ANY     ANY   /admin/post/{id}
 -----------------  ------  ------  ----  ---------------------

 ! [CAUTION] Lorem ipsum dolor sit amet, consectetur adipisicing elit,
 ! sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
 ! Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

Consectetur Adipisicing Elit Sed Do Eiusmod
-------------------------------------------

 * Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
   tempor incididunt ut labore et dolore magna aliqua.

 * Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
   aliquip ex ea commodo.

 * Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
   mollit anim id est laborum.

 Bundle namespace:
 > AppBundle <Enter>

 Bundle name [AcmeAppBundle]:
 > <Enter>

 Configuration format (yml, xml, php, annotation) [annotation]:
 > <Enter>

 Do you want to enable the bundle? (yes/no) [yes]:
 > <Enter>

 Configuration format (select one) [annotation]:
 > yml
 > xml
 > php
 > annotation

 ! [NOTE] Duis aute irure dolor in reprehenderit in voluptate velit esse
 ! cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.


 [OK] Lorem ipsum dolor sit amet, consectetur adipisicing elit


 [ERROR] Duis aute irure dolor in reprehenderit in voluptate velit esse.


 [WARNING] Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.

And what I ask you, if you agree, is that you provide the source code needed to do that. It doesn't matter that the real methods don't exist. I'm not going to execute the code. I just want to see it.

{
return array(
sprintf('<fg=blue>%s</fg=blue>', $this->title),
sprintf('<fg=blue>%s</fg=blue>', str_repeat('-', strlen($this->title))),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be better to create a <title> style to make it easier to use it directly (these classes should be optional to make it easier to write bigger messages)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean adding <title> to OutputFormatter?

@stof
Copy link
Member

stof commented Sep 25, 2014

I don't like the fact that you need to instantiate many new objects for each places needing to be formatted.
IMO, it will be easier to define a few methods on the FormatterHelper instead for the different use cases

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

@stof, see the first commit on this PR - is that what you mean? I added the second commit per @iltar's suggestion. I didn't like it at first but it does make it much more flexible...

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

@javiereguiluz sure, I can do that - where do you want me to post the code? to this PR?

@stof
Copy link
Member

stof commented Sep 25, 2014

@kbond yeah, I think it will be much more usable.

I suggest you do the work asked by @javiereguiluz with both implementations, so that it can be compared easily.
for the code, I suggest you put it in a comment in the discussion

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

Well the code should be the same for both implementations. The FormatterHelper methods remain the same. I will post the code.

@stof
Copy link
Member

stof commented Sep 25, 2014

@kbond The suggestion done by @iltar included using the Formatter objects in the code. If the only place where you use them is inside the FormatterHelper, they are useless compared to putting the code directly in the FormatterHelper (and they add overhead)

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

Their usage in the FormatterHelper is simply a convenience for the default ones to make a clean API. You can still add your own or use the default ones in your code.

@stof
Copy link
Member

stof commented Sep 25, 2014

@kbond and given that FormatterHelper->format() does strictly nothing except calling your own format method, you don't need it to be able to use your own formatting

@webmozart
Copy link
Contributor

This is awesome! :)

@linaori
Copy link
Contributor

linaori commented Sep 25, 2014

My suggestion was mainly to allow the following

  • Have people apply their own style and add their own formats for projects, I can imagine Drupal, PHPBB, Composer etc want that option
  • Allow additional processing in a custom formatter, like escaping certain output chars
  • Better maintainability for the FormatterHelper, easier to extend
  • Proper typehinting for your methods as using them now requires extensive documentation searching or sniffing through the code manually

Just a small example of what it allows people to do:

class AuthorFormatter implements FormatterInterface
{
    private $entity;

    public function __construct(UserEntity $entity)
    {
        $this->entity = $entity;
    }

    public function format()
    {
        return sprintf('%s <info>(%s)</info>', $this->entity->getUsername(), $this->entity->getEmail());
    }
}

Now lets say I wanted to print this to a file, I can implement my own formatter to remove all the console output to define colors and styles before actually returning it. Currently that's impossible.

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

FormatterHelper->format() is purely for conveinience, instead of:

$formatter = new MyFormatter('foo bar');
$output->writeln($formatter->format());

You can do:

$output->writeln($formatterHelper->format(new MyFormatter('foo bar')));

@javiereguiluz
Copy link
Member

I wish the final public API doesn't look like that :(

I was thinking about something like:

// the content is title-cased automatically
$output->title("Lorem ipsum dolor sit amet");

// the content is auto wrapped to the right length
$output->info('Duis aute irure dolor in reprehenderit in voluptate velit esse ... ');

// the [OK] prefix and the padding spaces are automatically added
$output->success('Lorem ipsum dolor sit amet, consectetur adipisicing elit');

@stof
Copy link
Member

stof commented Sep 25, 2014

@iltar if you want to write to a file, just use a non-decorated output, and it will disable all colors without having to change any code in the commands. This even works out of the box if you use php app/console router:debug > output.log on Unix systems (not on Windows as it has no way to detect this and relies on environment variables to guess the color support, so it requires passing --no-ansi to disable it explicitly)

@javiereguiluz we cannot add new methods on the OutputInterface, and it would be bad to force each output implementation to reimplement the styleguide formatting (the OutputInterface is responsible of writing to the output, which can be done either with a StreamOutput, a BufferOutput or a NullOutput currently in core)

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

For the code to generate @javiereguiluz's requirement, this the what I have so far (missing Questions and Table):

protected function execute(InputInterface $input, OutputInterface $output)
{
    /** @var FormatterHelper $formatter */
    $formatter = $this->getHelper('formatter');

    $output->writeln($formatter->formatTitle('Lorem Ipsum Dolor Sit Amet'));
    $output->writeln($formatter->formatText(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat'
    )));
    $output->writeln('');

    // TODO table

    $output->writeln($formatter->formatCautionBlock(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit,',
        'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.'
    )));
    $output->writeln($formatter->formatSectionTitle('Consectetur Adipisicing Elit Sed Do Eiusmod'));
    $output->writeln($formatter->formatListElement(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod',
        'tempor incididunt ut labore et dolore magna aliqua.'
    )));
    $output->writeln($formatter->formatListElement(array(
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut',
        'aliquip ex ea commodo.'
    )));
    $output->writeln($formatter->formatListElement(array(
        'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt',
        'mollit anim id est laborum.'
    )));

    // TODO questions

    $output->writeln($formatter->formatNoteBlock(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.'
    )));
    $output->writeln($formatter->formatSuccessResultBar('Lorem ipsum dolor sit amet, consectetur adipisicing elit'));
    $output->writeln($formatter->formatErrorResultBar('Duis aute irure dolor in reprehenderit in voluptate velit esse.'));
    $output->writeln($formatter->formatWarningResultBar('Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.'));
}

@javiereguiluz
Copy link
Member

@stof sure! I wasn't exactly referring to OutputInterface. Let's create something new which allows us to create something concise and beautiful.

@linaori
Copy link
Contributor

linaori commented Sep 25, 2014

@javiereguiluz What about the ability to create a wrapper around the OutputInterface that has it, without the need of a helper:

$output = new OutputDecorator($outputInterface);

// the content is title-cased automatically
$output->title("Lorem ipsum dolor sit amet");

// the content is auto wrapped to the right length
$output->info('Duis aute irure dolor in reprehenderit in voluptate velit esse ... ');

// the [OK] prefix and the padding spaces are automatically added
$output->success('Lorem ipsum dolor sit amet, consectetur adipisicing elit');

edit: this decorator would of course replace the helper

@javiereguiluz
Copy link
Member

@kbond thanks a lot for your quick response. I guess you imagine my answer, so I will be pretty sincere: I don't like that API. In fact, as a developer I would like to never use something like that :(

What do you think we could do to reduce its verbosity? If this is something that we cannot solve with the existing Console component classes, we could create something new specially crafted for this. What do you think?

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

I like the OutputDecorator idea.

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

We can debate using Formatter classes, but I think the API should be the same whether we use them or not.

@hhamon
Copy link
Contributor

hhamon commented Sep 25, 2014

I like the OutputDecorator solution too. Maybe having a better name like PrettyOutput / FormattedOutput can be convenient.

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

Here is the code updated using an OutputDecorator:

protected function execute(InputInterface $input, OutputInterface $output)
{
    $output = new OutputDecorator($output);

    $output->title('Lorem Ipsum Dolor Sit Amet');
    $output->text(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat'
    ));
    $output->writeln('');

    // TODO table

    $output->caution('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.');
    $output->subtitle('Consectetur Adipisicing Elit Sed Do Eiusmod');
    $output->listing(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod, tempor incididunt ut labore et dolore magna aliqua.',
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.',
        'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
    ));

    // TODO questions

    $output->note(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. (second paragraph)'
    ));
    $output->success('Lorem ipsum dolor sit amet, consectetur adipisicing elit');
    $output->error('Duis aute irure dolor in reprehenderit in voluptate velit esse.');
    $output->warning('Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.');
}

@javiereguiluz
Copy link
Member

@kbond superb! I'm starting to like it. Some proposals:

Instead of this:

$output->listElement(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod',
        'tempor incididunt ut labore et dolore magna aliqua.'
    ));
    $output->listElement(array(
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut',
        'aliquip ex ea commodo.'
    ));
    $output->listElement(array(
        'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt',
        'mollit anim id est laborum.'
    ));

What about this:

$output->list(array(
    'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod ...',
    'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ...',
    'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt ...',
));

Instead of this:

$output->caution(array(
    'Lorem ipsum dolor sit amet, consectetur adipisicing elit,',
    'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
    'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.'
));

If you want to output a caution:

$output->caution('Lorem ipsum dolor sit amet, consectetur adipisicing elit ...');

This would output as:

 ! [CAUTION] Lorem ipsum ...
 ! ...
 ! ...

If you want to show two or more separated paragraphs inside the caution:

$output->caution(array(
    'Lorem ipsum dolor sit amet, consectetur adipisicing elit ...',
    'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris ...'
));

This would output as:

 ! [CAUTION] Lorem ipsum ...
 ! ...
 !    <-- BLANK LINE HERE to separate paragraphs
 ! Ut enim ad ...
 ! ...

@kbond
Copy link
Member Author

kbond commented Sep 25, 2014

@javiereguiluz list is a reserved keyword..

So I should add the logic to split the lines if they are too long?

@linaori
Copy link
Contributor

linaori commented Sep 25, 2014

@kbond @javiereguiluz What about

$output->listing(array('Lorem ipsum dolor...'))`

@pokap
Copy link

pokap commented Oct 2, 2014

@nicolas-grekas old!

@jderusse
Copy link
Member

jderusse commented Oct 2, 2014

@kbond
Copy link
Member Author

kbond commented Oct 2, 2014

I have added table, ask, confirm and choice helpers and updated the PR description to show the code and output.

Few notes/issues:

  1. I copied a bunch of code from the QuestionHelper to the decorator - seemed like the best way but am open to alternative suggestions... I added some extension points to the QuestionHelper and created a StandardQuestionHelper subclass
  2. No askHidden - would require a lot of extra code in the decorator... I don't think we need to support this as it is not commonly used in the real-world (AFAIK).
  3. No autocomplete
  4. table doesn't match the style guide exactly
  5. The style guide will have to be updated for the choice question.
  6. Not sure what to do for the ProgressBar

@kbond
Copy link
Member Author

kbond commented Oct 2, 2014

I was able to make the table helper match as close to the style guide as possible.

->setCellHeaderFormat('%s')
;

Table::setStyleDefinition('symfony-style-guide', $styleGuideTableStyle);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I add this in Table::initStyles?

@kbond
Copy link
Member Author

kbond commented Oct 3, 2014

I have done some refactoring to remove the FormatterInterface and added some screenshots to the PR description.

@linaori
Copy link
Contributor

linaori commented Oct 3, 2014

Looking good! 👍

*/
class SymfonyStyle extends OutputStyle
{
const MAX_LENGTH = 120;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor comment, ignore it at will: what about renaming this constant to MAX_LINE_LENGTH?

@cryptiklemur
Copy link
Contributor

Looking awesome :)

is this going to make it into 2.6?

@kbond
Copy link
Member Author

kbond commented Oct 14, 2014

@javiereguiluz, Fabien mentioned last week at SymfonyLive that we might be able to sneak this into 2.6 if we can finalize it in time...

@sstok
Copy link
Contributor

sstok commented Mar 23, 2015

Whats the status of this?

@cryptiklemur
Copy link
Contributor

:( I hope this isnt dead.

@javiereguiluz
Copy link
Member

@kbond do you think you'll have time to rebase and finish this PR this week? If not, I totally understand, but we're in a hurry because this week ends the development period for Symfony 2.7 and it's our last chance to make it happen for 2.x branch. Thanks.

@kbond
Copy link
Member Author

kbond commented Mar 25, 2015

Yes, I can work on this. Should it be rebased to the 2.7 branch then? Do I have to open a new PR?

@kbond
Copy link
Member Author

kbond commented Mar 25, 2015

Closed in favor of #14057

@kbond kbond closed this Mar 25, 2015
fabpot added a commit that referenced this pull request Mar 30, 2015
…(kbond)

This PR was squashed before being merged into the 2.7 branch (closes #14057).

Discussion
----------

[RFC][Console] Added console style guide helpers (v2)

*(Rebased to 2.7)*

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #12014, #12035, symfony/symfony-docs#4265
| License       | MIT
| Doc PR        | todo

## Proposed API

### Code

```php
// Symfony command
protected function execute(InputInterface $input, OutputInterface $output)
{
    $output = new SymfonyStyle($output);

    $output->title('Lorem Ipsum Dolor Sit Amet');
    $output->text(array(
        'Duis aute irure dolor in reprehenderit in voluptate velit esse',
        'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat'
    ));
    $output->ln();

    $output->table(array('Name', 'Method', 'Scheme', 'Host', 'Path'), array(
            array('admin_post_new', 'ANY', 'ANY', 'ANY', '/admin/post/new'),
            array('admin_post_show', 'GET', 'ANY', 'ANY', '/admin/post/{id}'),
            array('admin_post_edit', 'ANY', 'ANY', 'ANY', '/admin/post/{id}/edit'),
            array('admin_post_delete', 'DELETE', 'ANY', 'ANY', '/admin/post/{id}'),
        ));

    $output->caution(array(
            'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.',
            'foo'
        ));
    $output->section('Consectetur Adipisicing Elit Sed Do Eiusmod');
    $output->listing(array(
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod, tempor incididunt ut labore et dolore magna aliqua.',
        'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.',
        'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
    ));

    $customValidator = function ($value) {
        if ($value == 'foo') {
            throw new \Exception('cannot be foo');
        }

        return $value;
    };

    // hidden question
    $output->note($output->askHidden('Hidden question'));

    // choice questions
    $output->note($output->choice('Choice question no default', array('choice1', 'choice2')));
    $output->note($output->choice('Choice question with default', array('choice1', 'choice2'), 'choice1'));

    // confirmation questions
    $output->note($output->confirm('Confirmation with yes default', true) ? 'yes' : 'no');
    $output->note($output->confirm('Confirmation with no default', false) ? 'yes' : 'no');

    // standard questions
    $output->note($output->ask('Question no default'));
    $output->note($output->ask('Question no default and custom validator', null, $customValidator));
    $output->note($output->ask('Question with default', 'default'));
    $output->note($output->ask('Question with default and custom validator', 'default', $customValidator));

    $output->note('Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.');
    $output->success('Lorem ipsum dolor sit amet, consectetur adipisicing elit');
    $output->error('Duis aute irure dolor in reprehenderit in voluptate velit esse.');
    $output->warning('Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.');

    $output->progressStart(100);

    for ($i = 0; $i < 100; $i++) {
        usleep(10000);
        $output->progressAdvance();
    }

    $output->progressFinish();
}
```

### Output

```
$ php app/console command

Lorem Ipsum Dolor Sit Amet
==========================

 // Duis aute irure dolor in reprehenderit in voluptate velit esse
 // cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat

 ------------------- -------- -------- ------ -----------------------
  Name                Method   Scheme   Host   Path
 ------------------- -------- -------- ------ -----------------------
  admin_post_new      ANY      ANY      ANY    /admin/post/new
  admin_post_show     GET      ANY      ANY    /admin/post/{id}
  admin_post_edit     ANY      ANY      ANY    /admin/post/{id}/edit
  admin_post_delete   DELETE   ANY      ANY    /admin/post/{id}
 ------------------- -------- -------- ------ -----------------------

 ! [CAUTION] Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
 ! dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet,
 ! consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
 ! veniam, quis nostrud exercitation ullamco laboris.
 !
 ! foo

Consectetur Adipisicing Elit Sed Do Eiusmod
-------------------------------------------

 * Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod, tempor incididunt ut labore et dolore magna aliqua.

 * Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.

 * Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Hidden question:
 > <f><o><o><enter>

 ! [NOTE] foo

 Choice question no default:
  [0] choice1
  [1] choice2
 > <enter>

 [ERROR] Value "" is invalid

 Choice question no default:
  [0] choice1
  [1] choice2
 > 0<enter>

 ! [NOTE] choice1

 Choice question with default [choice1]:
  [0] choice1
  [1] choice2
 > 1<enter>

 ! [NOTE] choice2

 Confirmation with yes default (yes/no) [yes]:
 > <enter>

 ! [NOTE] yes

 Confirmation with no default (yes/no) [no]:
 > <enter>

 ! [NOTE] no

 Question no default:
 > <enter>

 [ERROR] A value is required.

 Question no default:
 > foo<enter>

 ! [NOTE] foo

 Question no default and custom validator:
 > foo<enter>

 [ERROR] cannot be foo

 Question no default and custom validator:
 > <enter>

 [ERROR] A value is required.

 Question no default and custom validator:
 > foo<enter>

 [ERROR] cannot be foo

 Question no default and custom validator:
 > bar<enter>

 ! [NOTE] bar

 Question with default [default]:
 > <enter>

 ! [NOTE] default

 Question with default and custom validator [default]:
 > <enter>

 ! [NOTE] default

 ! [NOTE] Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
 ! Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
 ! fugiat nulla pariatur. Excepteur sint occaecat cupidatat. Duis aute irure dolor in reprehenderit in voluptate velit
 ! esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat.

 [OK] Lorem ipsum dolor sit amet, consectetur adipisicing elit

 [ERROR] Duis aute irure dolor in reprehenderit in voluptate velit esse.

 [WARNING] Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.

 100/100 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

```

### Screenshots

![screen1](https://cloud.githubusercontent.com/assets/127811/4507077/53bc009c-4b09-11e4-937c-44fe7fe30dc0.png)

![screen2](https://cloud.githubusercontent.com/assets/127811/4507078/53bf982e-4b09-11e4-8b5a-8c44c20ae4d9.png)

![screen](https://cloud.githubusercontent.com/assets/127811/6848451/b2e64848-d3a3-11e4-9916-43bd377684ca.png)

Commits
-------

96b4210 [RFC][Console] Added console style guide helpers (v2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.