.. index::
single: Console Helpers; Progress Bar
Progress Bar
============
When executing longer-running commands, it may be helpful to show progress
information, which updates as your command runs:
.. image:: /_images/components/console/progressbar.gif
To display progress details, use the
:class:`Symfony\\Component\\Console\\Helper\\ProgressBar`, pass it a total
number of units, and advance the progress as the command executes::
use Symfony\Component\Console\Helper\ProgressBar;
// creates a new progress bar (50 units)
$progressBar = new ProgressBar($output, 50);
// starts and displays the progress bar
$progressBar->start();
$i = 0;
while ($i++ < 50) {
// ... do some work
// advances the progress bar 1 unit
$progressBar->advance();
// you can also advance the progress bar by more than 1 unit
// $progressBar->advance(3);
}
// ensures that the progress bar is at 100%
$progressBar->finish();
.. tip::
You can also regress the progress bar (i.e. step backwards) by calling
``$progress->advance()`` with a negative value. For example, if you call
``$progress->advance(-2)`` then it will regress the progress bar 2 steps.
Instead of advancing the bar by a number of steps (with the
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::advance` method),
you can also set the current progress by calling the
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::setProgress` method.
.. tip::
If your platform doesn't support ANSI codes, updates to the progress
bar are added as new lines. To prevent the output from being flooded,
use the :method:`Symfony\\Component\\Console\\Helper\\ProgressBar::minSecondsBetweenRedraws`
method to limit the number of redraws and the
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::setRedrawFrequency` method
to redraw every N iterations. By default, redraw frequency is
**100ms** or **10%** of your ``max``.
If you don't know the exact number of steps in advance, set it to a reasonable
value and then call the ``setMaxSteps()`` method to update it as needed::
// start with a 50 units progressbar
$progressBar = new ProgressBar($output, 50);
// a complex task has just been created: increase the progressbar to 200 units
$progressBar->setMaxSteps(200);
Another solution is to omit the steps argument when creating the
:class:`Symfony\\Component\\Console\\Helper\\ProgressBar` instance::
$progressBar = new ProgressBar($output);
The progress will then be displayed as a throbber:
.. code-block:: text
# no max steps (displays it like a throbber)
0 [>---------------------------]
5 [----->----------------------]
5 [============================]
# max steps defined
0/3 [>---------------------------] 0%
1/3 [=========>------------------] 33%
3/3 [============================] 100%
Whenever your task is finished, don't forget to call
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::finish` to ensure
that the progress bar display is refreshed with a 100% completion.
.. note::
If you want to output something while the progress bar is running,
call :method:`Symfony\\Component\\Console\\Helper\\ProgressBar::clear` first.
After you're done, call
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::display`
to show the progress bar again.
If the progress information is stored in an iterable variable (such as an array
or a PHP generator) you can use the
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::iterate` method,
which starts, advances and finishes the progress bar automatically::
use Symfony\Component\Console\Helper\ProgressBar;
$progressBar = new ProgressBar($output);
// $iterable can be array
$iterable = [1, 2];
foreach ($progressBar->iterate($iterable) as $value) {
// ... do some work
}
// or a generator
function iterable() { yield 1; yield 2; ... };
foreach ($progressBar->iterate(iterable()) as $value) {
// ... do some work
}
The previous code will output:
.. code-block:: text
0/2 [>---------------------------] 0%
1/2 [==============>-------------] 50%
2/2 [============================] 100%
Customizing the Progress Bar
----------------------------
Built-in Formats
~~~~~~~~~~~~~~~~
By default, the information rendered on a progress bar depends on the current
level of verbosity of the ``OutputInterface`` instance:
.. code-block:: text
# OutputInterface::VERBOSITY_NORMAL (CLI with no verbosity flag)
0/3 [>---------------------------] 0%
1/3 [=========>------------------] 33%
3/3 [============================] 100%
# OutputInterface::VERBOSITY_VERBOSE (-v)
0/3 [>---------------------------] 0% 1 sec
1/3 [=========>------------------] 33% 1 sec
3/3 [============================] 100% 1 sec
# OutputInterface::VERBOSITY_VERY_VERBOSE (-vv)
0/3 [>---------------------------] 0% 1 sec/1 sec
1/3 [=========>------------------] 33% 1 sec/1 sec
3/3 [============================] 100% 1 sec/1 sec
# OutputInterface::VERBOSITY_DEBUG (-vvv)
0/3 [>---------------------------] 0% 1 sec/1 sec 1.0 MB
1/3 [=========>------------------] 33% 1 sec/1 sec 1.0 MB
3/3 [============================] 100% 1 sec/1 sec 1.0 MB
.. note::
If you call a command with the quiet flag (``-q``), the progress bar won't
be displayed.
Instead of relying on the verbosity mode of the current command, you can also
force a format via ``setFormat()``::
$progressBar->setFormat('verbose');
The built-in formats are the following:
* ``normal``
* ``verbose``
* ``very_verbose``
* ``debug``
If you don't set the number of steps for your progress bar, use the ``_nomax``
variants:
* ``normal_nomax``
* ``verbose_nomax``
* ``very_verbose_nomax``
* ``debug_nomax``
Custom Formats
~~~~~~~~~~~~~~
Instead of using the built-in formats, you can also set your own::
$progressBar->setFormat('%bar%');
This sets the format to only display the progress bar itself:
.. code-block:: text
>---------------------------
=========>------------------
============================
A progress bar format is a string that contains specific placeholders (a name
enclosed with the ``%`` character); the placeholders are replaced based on the
current progress of the bar. Here is a list of the built-in placeholders:
* ``current``: The current step;
* ``max``: The maximum number of steps (or 0 if no max is defined);
* ``bar``: The bar itself;
* ``percent``: The percentage of completion (not available if no max is defined);
* ``elapsed``: The time elapsed since the start of the progress bar;
* ``remaining``: The remaining time to complete the task (not available if no max is defined);
* ``estimated``: The estimated time to complete the task (not available if no max is defined);
* ``memory``: The current memory usage;
* ``message``: used to display arbitrary messages in the progress bar (as explained later).
For instance, here is how you could set the format to be the same as the
``debug`` one::
$progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%');
Notice the ``:6s`` part added to some placeholders? That's how you can tweak
the appearance of the bar (formatting and alignment). The part after the colon
(``:``) is used to set the ``sprintf`` format of the string.
Instead of setting the format for a given instance of a progress bar, you can
also define global formats::
ProgressBar::setFormatDefinition('minimal', 'Progress: %percent%%');
$progressBar = new ProgressBar($output, 3);
$progressBar->setFormat('minimal');
This code defines a new ``minimal`` format that you can then use for your
progress bars:
.. code-block:: text
Progress: 0%
Progress: 33%
Progress: 100%
.. tip::
It is almost always better to redefine built-in formats instead of creating
new ones as that allows the display to automatically vary based on the
verbosity flag of the command.
When defining a new style that contains placeholders that are only available
when the maximum number of steps is known, you should create a ``_nomax``
variant::
ProgressBar::setFormatDefinition('minimal', '%percent%% %remaining%');
ProgressBar::setFormatDefinition('minimal_nomax', '%percent%%');
$progressBar = new ProgressBar($output);
$progressBar->setFormat('minimal');
When displaying the progress bar, the format will automatically be set to
``minimal_nomax`` if the bar does not have a maximum number of steps like in
the example above.
.. tip::
A format can contain any valid ANSI codes and can also use the
Symfony-specific way to set colors::
ProgressBar::setFormatDefinition(
'minimal',
'%percent%\033[32m%\033[0m %remaining%>'
);
.. note::
A format can span more than one line; that's very useful when you want to
display more contextual information alongside the progress bar (see the
example at the beginning of this article).
Bar Settings
~~~~~~~~~~~~
Among the placeholders, ``bar`` is a bit special as all the characters used
to display it can be customized::
// the finished part of the bar
$progressBar->setBarCharacter('=');
// the unfinished part of the bar
$progressBar->setEmptyBarCharacter(' ');
// the progress character
$progressBar->setProgressCharacter('|');
// the bar width
$progressBar->setBarWidth(50);
.. caution::
For performance reasons, Symfony redraws screen every 100ms. If this is too
fast or to slow for your application, use the methods
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::minSecondsBetweenRedraws` and
:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::maxSecondsBetweenRedraws`::
$progressBar = new ProgressBar($output, 50000);
$progressBar->start();
// this redraws the screen every 100 iterations, but sets additional limits:
// don't redraw slower than 200ms (0.2) or faster than 100ms (0.1)
$progressBar->setRedrawFrequency(100);
$progressBar->maxSecondsBetweenRedraws(0.2);
$progressBar->minSecondsBetweenRedraws(0.1);
$i = 0;
while ($i++ < 50000) {
// ... do some work
$progressBar->advance();
}
Custom Placeholders
~~~~~~~~~~~~~~~~~~~
If you want to display some information that depends on the progress bar
display that are not available in the list of built-in placeholders, you can
create your own. Let's see how you can create a ``remaining_steps`` placeholder
that displays the number of remaining steps::
ProgressBar::setPlaceholderFormatterDefinition(
'remaining_steps',
function (ProgressBar $progressBar, OutputInterface $output) {
return $progressBar->getMaxSteps() - $progressBar->getProgress();
}
);
Custom Messages
~~~~~~~~~~~~~~~
Progress bars define a placeholder called ``message`` to display arbitrary
messages. However, none of the built-in formats include that placeholder, so
before displaying these messages, you must define your own custom format::
ProgressBar::setFormatDefinition('custom', ' %current%/%max% -- %message%');
$progressBar = new ProgressBar($output, 100);
$progressBar->setFormat('custom');
Now, use the ``setMessage()`` method to set the value of the ``%message%``
placeholder before displaying the progress bar::
// ...
$progressBar->setMessage('Start');
$progressBar->start();
// 0/100 -- Start
$progressBar->advance();
$progressBar->setMessage('Task is in progress...');
// 1/100 -- Task is in progress...
Messages can be combined with custom placeholders too. In this example, the
progress bar uses the ``%message%`` and ``%filename%`` placeholders::
ProgressBar::setFormatDefinition('custom', ' %current%/%max% -- %message% (%filename%)');
$progressBar = new ProgressBar($output, 100);
$progressBar->setFormat('custom');
The ``setMessage()`` method accepts a second optional argument to set the value
of the custom placeholders::
// ...
// $files = ['client-001/invoices.xml', '...'];
foreach ($files as $filename) {
$progressBar->setMessage('Importing invoices...');
$progressBar->setMessage($filename, 'filename');
$progressBar->advance();
// 2/100 -- Importing invoices... (client-001/invoices.xml)
}
.. _console-multiple-progress-bars:
Displaying Multiple Progress Bars
---------------------------------
When using :ref:`Console output sections ` it's
possible to display multiple progress bars at the same time and change their
progress independently::
$section1 = $output->section();
$section2 = $output->section();
$progress1 = new ProgressBar($section1);
$progress2 = new ProgressBar($section2);
$progress1->start(100);
$progress2->start(100);
$i = 0;
while (++$i < 100) {
$progress1->advance();
if ($i % 2 === 0) {
$progress2->advance(4);
}
usleep(50000);
}
After a couple of iterations, the output in the terminal will look like this:
.. code-block:: text
34/100 [=========>------------------] 34%
68/100 [===================>--------] 68%