[2.2][Console] Add ProgressHelper
merged branch leek/feature/progress-helper (PR #3501)

This PR was squashed before being merged into the master branch (closes #3501).

Commits
-------

4f3ded7 Actually this is worse
72a1c65 * Coding standards fixes * Changed `started` to `startTime` * Other fixes/edits
8249928 * Weeks/months/years is probably unrealistic * Set some sensible padding defaults * Use isset() instead of is_array()
37b62bf Fixing bug for elapsed time between 1 and 2 seconds
8fe4568 Special formatting for when there is no maximum set
75f532f Minor docblock updates
e436e1a Adding ProgressHelper for Console Component

Discussion
----------

[2.2][Console] Add ProgressHelper

[![Build Status](https://secure.travis-ci.org/leek/symfony.png?branch=feature/progress-helper)](http://travis-ci.org/leek/symfony)

Bug fix: no
Feature addition: yes
Backwards compatibility break: no
Symfony2 tests pass: Yes
Fixes the following tickets: -
Todo:
- Add unit tests
- Add documentation

--

I find myself needing some sort of progress indicator in most of my Console applications.
If this is something that could possibly be apart of Symfony, that would be great.

**Example:**
![Progress Example](http://i.imgur.com/a0wGQ.gif)

---------------------------------------------------------------------------

by jmikola at 2012-03-05T03:08:24Z

Do you have an example of this being used within a console command?

I'd be curious what the performance overhead is. My earliest console commands (nearly 2 years ago) would print status during each iteration (for a database migration) and I found the impact noticeable. After some time, I revised it to only print each X iterations, which often matched up with the batch size inserts/updates.

But for the last year, I've been using [declare(ticks=X)](http://php.net/manual/en/control-structures.declare.php) and have been quite happy with the results. By tuning the tick interrupt, the performance overhead is very small. It's especially helpful when dealing with processing code that is difficult to interrupt with a manual call to update the progress display, as PHP takes care of invoking the tick handler for me. I've thought about making such a console component helper for it, but I think the implementation is too invasive to abstract into a helper.

Here's an example of it being used in OrnicarMessageBundle's [MongoDBMigrateMetadataCommand](https://github.com/ornicar/OrnicarMessageBundle/blob/master/Command/MongoDBMigrateMetadataCommand.php).

---------------------------------------------------------------------------

by leek at 2012-03-05T04:05:29Z

@jmikola: Here is a simple example:

```php
<?php
// ...
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $progress = $this->getHelperSet()->get('progress');
        $progress->start($output, 50);

        $i = 0;
        while ($i++ < 50) {
            usleep(mt_rand(20000, 200000));
            $progress->advance();
        }

        $progress->finish();
    }
```

The performance overhead shouldn't be much more than a standard `$output->write()` call. When used with a loop doing 1000's of iterations, you can set the `redrawFreq` option to something more appropriate to control how often the progress indicator is redrawn to the console.

---------------------------------------------------------------------------

by leek at 2012-03-10T10:05:32Z

Added some minor updates along with an example GIF of 2 of the progress bars (see edited PR).

---------------------------------------------------------------------------

by jmikola at 2012-03-10T15:22:29Z

Why does `1 sec` flash over to `1 secs` before `2 secs` is rendered?

---------------------------------------------------------------------------

by henrikbjorn at 2012-03-10T15:26:08Z

:+1:

---------------------------------------------------------------------------

by leek at 2012-03-10T16:07:08Z

@jmikola: Thanks! I didn't even notice that. Fixed.

---------------------------------------------------------------------------

by drak at 2012-03-11T09:04:58Z

What an amazing PR.  I feel like I just have to write some code that uses this feature just because it's there!

---------------------------------------------------------------------------

by henrikbjorn at 2012-03-11T09:55:50Z

This is needed a lot, we have a bunch of import scripts where this is useful.

@fabpot what are your thoughts on this?

---------------------------------------------------------------------------

by francoispluchino at 2012-03-14T12:34:38Z

:+1:

---------------------------------------------------------------------------

by vicb at 2012-03-14T13:00:42Z

could you please order the properties & methods by visibility according to the Sf2 CS.

---------------------------------------------------------------------------

by leek at 2012-03-14T19:08:52Z

No problem - I'll make the requested changes tonight.

---------------------------------------------------------------------------

by stof at 2012-04-03T22:48:45Z

@fabpot ping

---------------------------------------------------------------------------

by stloyd at 2012-04-14T09:46:31Z

@fabpot Any hope to get this in 2.1 ?

---------------------------------------------------------------------------

by mvriel at 2012-05-15T19:28:34Z

:+1:

Tried it out by manually including it in my project and works like a charm

---------------------------------------------------------------------------

by blaugueux at 2012-05-23T18:46:15Z

Up ! It will be great to have this feature in the next release.

@fabpot ping

---------------------------------------------------------------------------

by guilhermeblanco at 2012-05-28T22:58:35Z

@fabpot tried on my app and everything works fine.
Any plans to merge this one into 2.1?

---------------------------------------------------------------------------

by damonjones at 2012-05-29T02:31:39Z

+1
This would be a very nice feature to have in 2.1.

---------------------------------------------------------------------------

by fabpot at 2012-05-29T06:18:57Z

This is scheduled for 2.2.

---------------------------------------------------------------------------

by Burgov at 2012-08-16T13:04:34Z

I have a service which downloads a file using wget though the console component, and reads the progress from stderr. Rather than advancing in steps, i'd like to be able to set the current progress. Something like this method might be a nice addition:

```php
    public function setCurrent($value, $redraw = false)
    {
        $this->advance($value - $this->current, $redraw);
    }
```
[Console] converted options to proper setters in ProgressHelper
[Console] added some basic tests for the ProgressHelper class