In this example, we are going to call console command from controller and display the response as output arrives rather than displaying whole output in one go. For that we will be using StreamedResponse class of symfony and create our own streaming output class.


SayHelloCommand


namespace Football\FrontendBundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SayHelloCommand extends Command
{
protected function configure()
{
$this
->setName('say:hello')
->addOption('name', null, InputOption::VALUE_REQUIRED)
->addOption('iteration', null, InputOption::VALUE_REQUIRED);
}

protected function execute(InputInterface $input, OutputInterface $output)
{
for ($i = 1; $i <= $input->getOption('iteration'); $i++) {
$output->writeln(sprintf('%d: Hello %s', $i, $input->getOption('name')));

sleep(1);
}
}
}

services:
football_frontend.command.say_hello:
class: Football\FrontendBundle\Command\SayHelloCommand
tags:
- { name: console.command }

Test output in terminal.


football$ bin/console say:hello --name=Inanzzz --iteration=5
1: Hello Inanzzz
2: Hello Inanzzz
3: Hello Inanzzz
4: Hello Inanzzz
5: Hello Inanzzz

DefaultController


namespace Football\FrontendBundle\Controller;

use Football\FrontendBundle\Command\SayHelloCommand;
use Football\FrontendBundle\Service\StreamedOutput;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
* @Route("", service="football_frontend.controller.default")
*/
class DefaultController
{
private $sayHelloCommand;

public function __construct(
SayHelloCommand $sayHelloCommand
) {
$this->sayHelloCommand = $sayHelloCommand;
}

/**
* @Method({"GET"})
* @Route("")
*
* @return Response
*/
public function streamAction()
{
$response = new StreamedResponse(function() {
$input = new ArrayInput([
'--name' => 'Inanzzz',
'--iteration' => 5,
]);
$input->setInteractive(false);

$output = new StreamedOutput(fopen('php://stdout', 'w'));

$this->sayHelloCommand->run($input, $output);
});

return $response;
}
}

services:
football_frontend.controller.default:
class: Football\FrontendBundle\Controller\DefaultController
arguments:
- '@football_frontend.command.say_hello'

StreamedOutput class


namespace Football\FrontendBundle\Service;

use RuntimeException;
use Symfony\Component\Console\Output\StreamOutput;

class StreamedOutput extends StreamOutput
{
protected function doWrite($message, $newline)
{
if (
false === @fwrite($this->getStream(), $message) ||
(
$newline &&
(false === @fwrite($this->getStream(), PHP_EOL))
)
) {
throw new RuntimeException('Unable to write output.');
}

echo $message;

ob_flush();
flush();
}
}

Test


If you go to your home page, you'll response displayed on the page every second one by one.


1: Hello Inanzzz2: Hello Inanzzz3: Hello Inanzzz4: Hello Inanzzz5: Hello Inanzzz