Как мне использовать StreamedResponse для отображения представления шаблона в Symfony2

#php #symfony #buffer

#php #symfony #буфер

Вопрос:

Я пытаюсь использовать StreamedResponse для вывода прогресса на мою индексную страницу в Symfony2.

Этот приведенный ниже код показывает мой прогресс в вызовах API по мере их возникновения, но у меня возникают проблемы с отображением потоковой информации в реальном представлении. Прямо сейчас он просто выводит обычный текст в верхней части страницы, а затем отображает представление, когда все завершено.

Я не хочу возвращать конечный массив и закрывать функцию, пока все не будет загружено, но, похоже, я не могу получить обычный шаблон twig для отображения во время вывода прогресса.

Я пытался использовать render, но, похоже, ничто не выводит этот файл просмотра на экран, если я не вернусь.

  public function indexAction($countryCode)
    {

    //anywhere from five to fifteen api calls are going to take place
    foreach ($Widgets as $Widget) {

        $response = new StreamedResponse();

        $curlerUrl = $Widget->getApiUrl()
            . '?action=returnWidgets'
            . 'amp;data=' . urlencode(serialize(array(
                'countryCode' => $countryCode
            )));

        $requestStartTime = microtime(true);
        $curler = $this->get('curler')->curlAUrl($curlerUrl);
        $curlResult = json_decode($curler['body'], true);


        if(isset($curlResult['data'])){
           //do some processing on the data
        }

        $response->setCallback(function() use ($Widget, $executionTime) {
            flush();
            sleep(1);
            var_dump($Widget->getName());
            var_dump($executionTime);
            flush();
        });

        $response->send();
    } 
    //rest of indexAction with a return statement

    return array(
      //all the vars my template will need       
    );
}
  

Кроме того, еще одна важная деталь заключается в том, что я пытаюсь отобразить все в twig, и, похоже, с этим связаны некоторые интересные проблемы.

Комментарии:

1. Являются ли эти 15 запросов последовательными?

2. @Rhono, да, они последовательные. Прямо сейчас страница не отображается, пока все они не будут завершены, поэтому я пытаюсь показывать прогресс по мере завершения каждого вызова.

Ответ №1:

Насколько я понимаю, у вас есть только один шанс вывести что-то в браузер с сервера (PHP / Twig), а затем JavaScript должен внести какие-либо дальнейшие изменения (например, обновить индикатор выполнения).

Я бы рекомендовал использовать multi-cURL для асинхронного выполнения всех 15 запросов. Это эффективно делает общее время запроса равным самому медленному запросу, поэтому вы можете обслуживать свою страницу намного быстрее и, возможно, устранить необходимость в индикаторе выполнения.

 // Create the multiple cURL handle
$mh = curl_multi_init();
$handles = array();
$responses = array();

// Create and add the cURL handles to the $mh
foreach($widgets as $widget) {
    $ch = $curler->getHandle($widget->getURL()); // Code that returns a cURL handle
    $handles[] = $ch;
    curl_multi_add_handle($mh, $ch);
}

// Execute the requests
do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh);
} while ($running > 0);

// Get the request content
foreach($handles as $handle) {
    $responses[] = curl_multi_getcontent($handle);

    // Close the handles
    curl_close($handle);
}
curl_multi_close();

// Do something with the responses
// ...
  

В идеале это был бы метод вашего Curler сервиса.

 public function processHandles(array $widgets)
{
    // most of the above

    return $responses;
}
  

Ответ №2:

Вы можете реализовать всю логику в setCallback методе, поэтому рассмотрите этот код:

 public function indexAction($countryCode)
{

    $Widgets = [];

    $response = new StreamedResponse();

    $curlerService = $this->get('curler');

    $response->setCallback(function() use ($Widgets, $curlerService, $countryCode) {

        foreach ($Widgets as $Widget) {

            $curlerUrl = $Widget->getApiUrl()
                . '?action=returnWidgets'
                . 'amp;data=' . urlencode(serialize(array(
                    'countryCode' => $countryCode
                )));

            $requestStartTime = microtime(true);
            $curler = $curlerService->curlAUrl($curlerUrl);
            $curlResult = json_decode($curler['body'], true);


            if(isset($curlResult['data'])){
                //do some processing on the data
            }
            flush();
            sleep(1);
            var_dump($Widget->getName());
            var_dump( (microtime(true) - $requestStartTime) );
            flush();

        }

    });

    // Directly return the streamed response object
    return $response;

}
  

Дальнейшее чтение этой и этой статьи.

Надеюсь, это поможет

Комментарии:

1. привет @absentx вы взглянули на этот ответ? о чем вы думаете?