Skip to content

[5.1][Console][WIP] Laravel Console Style #8338

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 1 commit into from
Closed

[5.1][Console][WIP] Laravel Console Style #8338

wants to merge 1 commit into from

Conversation

barryvdh
Copy link
Contributor

@barryvdh barryvdh commented Apr 8, 2015

In Symfony 2.7, Style Guide helpers are added (see symfony/symfony#14057 and symfony/symfony@96b4210 )

This adds a StyleInterface with a few common helpers, similar to the helpers that Laravel currently adds.

Perhaps it would be a good idea to make a Laravel Style, that perhaps extends the Symfony one. The existing helper functions could be redirected to the Style ouput, new methods can also be directed to the style helper or be available as $style for example.

The OutputStyle also implements the OutputInterface, so the Output could be changed to the OutputStyle.

Pros:

  • Easier to use
  • Prettier ouput
  • Uniformity between commands
  • Leverage Symfony helpers/code
  • Interoperability with Symfony

Cons:

  • Some helpers have different signatures, so might give confusion.

Example:

    public function run(InputInterface $input, OutputInterface $output)
    {
        $this->input = $input;
        $this->output = new LaravelStyle($input, $output);
        return parent::run($input, $output);
    }

    public function ask($question, $default = null)
    {
        return $this->output ->ask($question, $default);
    }

Table with current/symfony helpers:

Symfony StyleInterface Laravel Command
title($message) n/a
section($message) n/a
listing(array $elements) n/a
text($message) line($string)
success($message) info($string)
error($message) error($string)
warning($message) (warning in ConfirmableTrait)
note($message) comment($string)
caution($message) n/a
n/a question($string)
table(array $headers, array $rows) table(array $headers, array $rows, $style = 'default')
ask($question, $default = null, $validator = null) ask($question, $default = null)
askHidden($question, $validator = null) secret($question, $fallback = true)
n/a askWithCompletion($question, array $choices, $default = null)
confirm($question, $default = true) confirm($question, $default = false)
choice($question, array $choices, $default = null) choice($question, array $choices, $default = null, $attempts = null, $multiple = null)
newLine($count = 1) n/a
progressStart($max = 0) n/a
progressAdvance($step = 1) n/a
progressFinish() n/a

As this is for 5.1 (because only in Symfony 2.7), we could change the signatures perhaps, if it's worth the BC break. Otherwise keep the existing method signatures and make the style available for new helpers.

This PR is a Work in Progress. It replaces #8306
This shows how it could work, but it should be decided which style we want to follow. The old Laravel style is a bit more 'compact' then Symfony, which has more newlines etc and more verbose errors/notes. See symfony/symfony#14057 for screenshots.

Todo

  • Replace OutputInterface with LaravelStyle
  • Use askQuestion to reduce code in Command
  • Move table from Command to LaravelStyle
  • Move comment/info etc to LaravelStyle
  • Decide on preferable default format for questions, tables, blocks, errors etc in LaravelStyle.

private $progressBar;
private $lineLength;

/**
Copy link
Member

Choose a reason for hiding this comment

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

oops :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah copied from Symfony, but this is WIP so please comment on CS after it's finished.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed all that, removed a lot too ;)

@GrahamCampbell
Copy link
Member

Looking pretty nice so far. :)

@barryvdh
Copy link
Contributor Author

barryvdh commented Apr 8, 2015

But should we move to 'Symfony style' questions and error/success blocks, or keep the current style (1 line errors, answers directly after questions)

@GrahamCampbell
Copy link
Member

But should we move to 'Symfony style' questions and error/success blocks, or keep the current style (1 line errors, answers directly after questions)

Not sure. Could you show us a comparison please?

@barryvdh
Copy link
Contributor Author

barryvdh commented Apr 8, 2015

Above: Laravel 5.0, Below: Symfony style

Laravel questions:

Symfony questions:

I think especially the questions could benefit from the new styles.
The notes etc I'm not so sure, depends on the use case.

@GrahamCampbell
Copy link
Member

I quite like the symfony questions. Ping @taylorotwell.

@barryvdh
Copy link
Contributor Author

barryvdh commented Apr 8, 2015

I've added the Laravel style messages, includings warnings.

SymfonyStyle:

LaravelStyle:

Also mapped info -> success, comment -> note, error -> error, line -> writeln
The warnings (from the ConfirmableTrait) could be moved to the Output.

@barryvdh
Copy link
Contributor Author

barryvdh commented Apr 9, 2015

I made the borderedBlock method more flexible (padding + border character), allowed an array of lines and added wordwrapping for lines that are too long, while keeping the border:

laravel-wordwrap

@barryvdh
Copy link
Contributor Author

I've tweaked the code a bit and fixed the CS, so I guess this is ready for review.

@GrahamCampbell
Copy link
Member

The todo list is incomplete?

@@ -29,7 +29,7 @@ class Command extends \Symfony\Component\Console\Command\Command {
/**
* The output interface implementation.
*
* @var \Symfony\Component\Console\Output\OutputInterface
* @var LaravelStyle
Copy link
Member

Choose a reason for hiding this comment

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

Please use the FQCN in here.

protected function borderedBlock($messages, $style = null, $borderChar = '*', $paddingSize = 3)
{
$messages = (array) $messages;
$lines = array();
Copy link
Member

Choose a reason for hiding this comment

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

please use short array syntax on new code

@barryvdh
Copy link
Contributor Author

Regarding the todo list:

Deciding the layout is up to you guys, I just made the example with proposed layout. So if you're okay with that, I'll check it off.

About the tables, I can't use the style layout as it doesn't have a $style property in the interface. So either we remove the style property (which can be considered a BC break) or just keep the current method.

private $lineLength;

/**
* Create a new LaravelStyle instance.
Copy link
Member

Choose a reason for hiding this comment

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

Create a new Laravel style instance. please

@barryvdh
Copy link
Contributor Author

Here is the difference between the default and symfony-style-guide:
tables

So we could change the style back to default if you want (or create a custom style).

If we want to keep the $style property on the command method, we just have to duplicate it I guess.

@GrahamCampbell
Copy link
Member

I think default is ok. I'll ask Taylor...

@barryvdh
Copy link
Contributor Author

I added the default table style to the LaravelStyle, the same as in the default in the command class itself. Symfony adds a newline directly after, but left that out to keep it in line with current behavior.

@barryvdh
Copy link
Contributor Author

Current output is a lot more compact then Symfony, which adds more new lines and spacing in front of lines. But I'll leave that up to Taylor to decide. Below the output from the example from the Symfony issue, so you can see the difference:

$output = $this->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->newLine();

$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();

laravelstyle-1
laravelstyle-2
laravelstyle-3

@taylorotwell
Copy link
Member

Personally I would rather just use whatever Symfony ships with as it is less for us to maintain going forward.

@barryvdh
Copy link
Contributor Author

So shall I submit a PR to use the Symfony styles as the default output and use that to simplify the questions etc?

@taylorotwell
Copy link
Member

Sure, we can. Is that a lot of code? Whatever is the least custom code for
us to maintain going forward.

On Thu, Apr 23, 2015 at 1:29 PM, Barry vd. Heuvel notifications@github.com
wrote:

So shall I submit a PR to use the Symfony styles as the default output and
use that to simplify the questions etc?


Reply to this email directly or view it on GitHub
#8338 (comment).

@barryvdh
Copy link
Contributor Author

That would be pretty much the same changes to the Command class as in this PR, but then using the Symfony style class instead of a new Laravel Style class.

@taylorotwell
Copy link
Member

So what if we just don't change anything. The console component has no
styling now unless you implement some extra interface? There is no default
styling?

On Thu, Apr 23, 2015 at 2:07 PM, Barry vd. Heuvel notifications@github.com
wrote:

That would be pretty much the same changes to the Command class as in this
PR, but then using the Symfony style class instead of a new Laravel Style
class.


Reply to this email directly or view it on GitHub
#8338 (comment).

@barryvdh
Copy link
Contributor Author

What do you mean?
The Console component currently doesn't have any styling, except the <question> and <comment> tag indeed.

The SymfonyStyle adds styling for commonly used things, similar to our current helper methods (see table in opening post). So we can use that to make our questions prettier and reduce logic.
We can also use the notice/success methods from the Style class, instead of our <comment>Text</comment> styling.

@barryvdh
Copy link
Contributor Author

The styling in this original PR adds the same (very basic) styling to the interface, using the same style as the current styling. It pretty basic, except perhaps the orderBlock method.
The SymfonyStyle is just a bit more verbose and more new lines. See the screenshots above.

@barryvdh
Copy link
Contributor Author

Submitted a simplified PR in #8537

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants