【问题标题】:How to call Symfony2 console command within controller and have streamed output?如何在控制器中调用 Symfony2 控制台命令并进行流式输出?
【发布时间】:2016-05-24 19:48:02
【问题描述】:

所以我有一个基本要求:我需要从控制器调用 Symfony2 的自定义控制台命令(该脚本也由 CRON 作业调用,但我希望它可以从网络浏览器调用)。

我跟着this tutorial 让它工作,它是:

<?php

namespace AppBundle\Controller\Admin;

use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class TacheController extends Controller
{
    /**
     * @Route("/admin/taches/facebook", name="admin_tache_facebook")
     *
     * @return Response
     */
    public function facebookAction(Request $request)
    {
        ini_set('max_execution_time', -1);
        $kernel = $this->get('kernel');
        $application = new Application($kernel);
        $application->setAutoExit(false);

        $input = new ArrayInput(array(
            'command' => 'nrv:fetch:facebook',
        ));
        // You can use NullOutput() if you don't need the output
        $output = new BufferedOutput();
        $application->run($input, $output);

        // return the output, don't use if you used NullOutput()
        $content = $output->fetch();

        // return new Response(""), if you used NullOutput()
        return new Response($content);
    }
}

但是,控制台命令的运行时间很长(大约 2 百万),因此页面会在这段时间内挂起,直到显示命令的所有输出。

我的目标是让输出在控制台中显示,就像在使用带有ConsoleBundle 的 Web 控制台时一样。我想到了ob_start()ob_end_flush()的使用,但我不知道如何在这种情况下使用它们。

我正在努力实现的目标是否可能?我怎样才能做到这一点?


解决方案

根据the answer provided by @MichałSznurawa,我必须扩展\Symfony\Component\Console\Output\BufferedOutput 并实现doWrite() 方法。这里是:

<?php

namespace AppBundle\Console;

use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpFoundation\StreamedResponse;

class StreamedOutput extends BufferedOutput
{
    public function doWrite($message, $newline)
    {
        $response = new StreamedResponse();
        $response->setCallback(function() use($message) {
            echo $message;
            flush();
        });

        $response->send();
    }
}

并按以下方式修改控制器:

$output = new StreamedOutput();

结果是页面在命令执行后立即流式传输命令的输出(而不是等待它完成)。

【问题讨论】:

  • 我明白你的意思吗:你是否试图使用 webconsole 从命令行调用一个应该运行命令的控制器?
  • 对不起,如果我不够清楚:我想通过特定的 URL 访问控制器,该 URL 将运行 Symfony2 控制台命令。但是,我希望控制台的输出立即显示给用户,而不是等待命令完成后再一次显示所有内容。
  • @D4V1D 我试过你的例子,它不会一个接一个地打印消息。所有消息都被一次性转储。您介意分享一个简单的工作示例吗?至少可以流式传输HelloWorld。也许在here

标签: php symfony console output command-line-interface


【解决方案1】:

您必须实现自己的输出类并注入它而不是 BufferedOutput。可以扩展抽象类\Symfony\Component\Console\Output\Output或者实现接口vendor/symfony/symfony/src/Symfony/Component/Console/Output/OutputInterface.php:20

您的实现应该是如下所述的流式响应:http://symfony.com/doc/current/components/http_foundation/introduction.html#streaming-a-response,而不是等待命令执行结束并将所有输出一起发回。当然,这只有在您的命令在执行期间打印某些内容时才有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    相关资源
    最近更新 更多