如何使用symfony2 compoments OutputInterface和Table帮助器缩进写入操作?

I have an OutputInterface and I use it to write a bunch of tables onto them via the Table helper. The information has nested context, so I want the output to be indented by 4 spaces.

I thought that something like this should be possible:

 new Table($output);
 $output->writeln('0. run');
 $someTable->render();
 $output->increaseIndentLevel(); // pseudocode
 $output->writeln('1. run');
 $someTable->render();

to create the expected output:

0. run
+---------------+-----------------------+------------------+
| ISBN          | Title                 | Author           |
+---------------+-----------------------+------------------+
| 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |
| 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
+---------------+-----------------------+------------------+
     1. run
     +---------------+-----------------------+------------------+
     | ISBN          | Title                 | Author           |
     +---------------+-----------------------+------------------+
     | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |
     | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
     | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
     +---------------+-----------------------+------------------+

I searched for ways to implement this. I noticed that the OutputInterface provides a OutputFormatterStyle, yet this seems to only be able to change the colors of the text and some options can be set that have nothing to do with prepending or appending content to a write operation.

I could extend an OutputInterface, e.g. ConsoleOutput, yet I also would like to have the ability to add this functionality to any OutputInterfaces (e.g. BufferedOutput) as well, without having to create a manual version of each one.

And my last try was to inject a my own OutputFormatter to the OutputInterface:

<?php
namespace Hive\App;

use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyleInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * IndentedOutputFormatter
 **/
class IndentedOutputFormatter extends OutputFormatter
{
    const INDENT_AMOUNT = 4;

    private $indentLevel = 0;

    /**
     * Formats a message according to the given styles.
     * @param string $message The message to style
     * @return string The styled message
     * @api
     */
    public function format($message)
    {
        $message = parent::format($message);
        if ($this->indentLevel === 0) {
            return $message;
        }

        $amount = self::INDENT_AMOUNT * $this->indentLevel;
        $prependBy = str_repeat(' ', $amount);
        $message = $prependBy . $message;

        return $message;
    }

    /**
     *
     */
    public function increaseLevel()
    {
        $this->indentLevel = $this->indentLevel + 1;
    }

    /**
     *
     */
    public function decreaseLevel()
    {
        $this->indentLevel = $this->indentLevel - 1;
    }
}

and using it like this from a command:

/**
 * @param InputInterface  $input
 * @param OutputInterface $output
 * @return int
 */
protected function execute(InputInterface $input, OutputInterface $output)
{
    $headers = [
        'ISBN',
        'Title',
        'Author',
    ];

    $rows = [
        [
            '99921-58-10-7',
            'Divine Comedy',
            'Dante Alighieri',

        ],
        [
            '9971-5-0210-0',
            'A Tale of Two Cities',
            'Charles Dickens',

        ],
        [
            '960-425-059-0',
            'The Lord of the Rings',
            'J. R. R. Tolkien',
        ],
    ];


    $formatter = new IndentedOutputFormatter();
    $output->setFormatter($formatter);
    $table = new Table($output);
    $table->setHeaders($headers);
    $table->setRows($rows);

    foreach (range(0, 3) as $currentRun) {
        $output->writeln("$currentRun. run");
        $formatter->increaseLevel();
        $table->render();
    }

    return 0;
}

Yet this yields in the problem that not only the table is rendered via indentation, but also its content fields:

0. run
    +-------------------+---------------------------+----------------------+
    |     ISBN              |     Title                     |     Author               |    
    +-------------------+---------------------------+----------------------+
    |     99921-58-10-7     |     Divine Comedy             |     Dante Alighieri      |    
    |     9971-5-0210-0     |     A Tale of Two Cities      |     Charles Dickens      |    
    |     960-425-059-0     |     The Lord of the Rings     |     J. R. R. Tolkien     |    
    +-------------------+---------------------------+----------------------+
    1. run
        +-----------------------+-------------------------------+--------------------------+
        |         ISBN                  |         Title                         |         Author                   |        
        +-----------------------+-------------------------------+--------------------------+
        |         99921-58-10-7         |         Divine Comedy                 |         Dante Alighieri          |        
        |         9971-5-0210-0         |         A Tale of Two Cities          |         Charles Dickens          |        
        |         960-425-059-0         |         The Lord of the Rings         |         J. R. R. Tolkien         |        
        +-----------------------+-------------------------------+--------------------------+
        2. run
            +---------------------------+-----------------------------------+------------------------------+
            |             ISBN                      |             Title                             |             Author                       |            
            +---------------------------+-----------------------------------+------------------------------+
            |             99921-58-10-7             |             Divine Comedy                     |             Dante Alighieri              |            
            |             9971-5-0210-0             |             A Tale of Two Cities              |             Charles Dickens              |            
            |             960-425-059-0             |             The Lord of the Rings             |             J. R. R. Tolkien             |            
            +---------------------------+-----------------------------------+------------------------------+
            3. run
                +-------------------------------+---------------------------------------+----------------------------------+
                |                 ISBN                          |                 Title                                 |                 Author                           |                
                +-------------------------------+---------------------------------------+----------------------------------+
                |                 99921-58-10-7                 |                 Divine Comedy                         |                 Dante Alighieri                  |                
                |                 9971-5-0210-0                 |                 A Tale of Two Cities                  |                 Charles Dickens                  |                
                |                 960-425-059-0                 |                 The Lord of the Rings                 |                 J. R. R. Tolkien                 |                
                +-------------------------------+---------------------------------------+----------------------------------+

How can I get indentation to work using the symfony2 components of and OutputInterface and a Table helper?

This does the job

Output decorator

use Symfony\Component\Console\Output\Output;

class IndentedOutput extends Output
{
    const INDENT_AMOUNT = 4;

    private $output;
    private $indentLevel = 0;
    private $resetLine = false;

    public function setOutput(OutputInterface $output)
    {
        $this->output = $output;
    }

    public function increaseLevel()
    {
        $this->indentLevel += 1;
    }

    public function decreaseLevel()
    {
        $this->indentLevel -= 1;
    }

    public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
    {
        $prependBy = str_repeat(' ', self::INDENT_AMOUNT * $this->indentLevel);

        if ($newline) {
            $this->resetLine = true;
            $messages = $prependBy.$messages;
        }

        if ($this->resetLine && !$newline) {
            $messages = $prependBy.$messages;
            $this->resetLine = false;
        }

        $this->output->write($messages, $newline, $type);
    }

    public function doWrite($message, $newline)
    {
        $this->output->doWrite($message, $newline);
    }
}

Test

use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\BufferedOutput;

$headers = [
    'ISBN',
    'Title',
    'Author',
];

$rows = [[
    '99921-58-10-7',
    'Divine Comedy',
    'Dante Alighieri',

],[
    '9971-5-0210-0',
    'A Tale of Two Cities',
    'Charles Dickens',

],[
    '960-425-059-0',
    'The Lord of the Rings',
    'J. R. R. Tolkien',
]];

$app = new Application();
$app
    ->register('foo')
    ->setCode(function(InputInterface $input, OutputInterface $output) use ($headers, $rows) {

        $buffered = new BufferedOutput;
        $indented = new IndentedOutput;
        $indented->setOutput($buffered);

        $table = new Table($indented);
        $table->setHeaders($headers);
        $table->setRows($rows);

        foreach (range(0, 3) as $currentRun) {
            $indented->writeln("$currentRun. run");
            $table->render();
            $indented->increaseLevel();
        }

        $indented->decreaseLevel();
        $indented->decreaseLevel();
        $indented->decreaseLevel();
        $indented->decreaseLevel();
        $indented->write('hello world');

        $output->write($buffered->fetch());
    });
$app->run();

Output:

0. run
+---------------+-----------------------+------------------+
| ISBN          | Title                 | Author           |
+---------------+-----------------------+------------------+
| 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |
| 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |
| 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |
+---------------+-----------------------+------------------+
    1. run
    +---------------+-----------------------+------------------+
    | ISBN          | Title                 | Author           |    
    +---------------+-----------------------+------------------+
    | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |    
    | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |    
    | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |    
    +---------------+-----------------------+------------------+
        2. run
        +---------------+-----------------------+------------------+
        | ISBN          | Title                 | Author           |        
        +---------------+-----------------------+------------------+
        | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |        
        | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |        
        | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |        
        +---------------+-----------------------+------------------+
            3. run
            +---------------+-----------------------+------------------+
            | ISBN          | Title                 | Author           |            
            +---------------+-----------------------+------------------+
            | 99921-58-10-7 | Divine Comedy         | Dante Alighieri  |            
            | 9971-5-0210-0 | A Tale of Two Cities  | Charles Dickens  |            
            | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien |            
            +---------------+-----------------------+------------------+
hello world