使用Laravel 4更新视图中的实时数据(如进度条)


Update live data (like progress bar) in view with Laravel 4

TL;DR

我想发送数据以实时更新视图,例如进度显示操作状态的栏。在laravel 4中,最好的方法是什么?


设置

我正在做一个基于Laravel 4的项目,每个用户都可以兑换一个串行密钥。

我做了一个管理后台,在那里我可以很容易地粘贴密钥列表,或者上传它们的文件。

假设$key_string是我上传的换行键字符串,我想解析出来,然后从中上传包含的键字符串-这是添加键的简化代码:

$key_string = rtrim($key_string);
$key_string = str_replace("'n'r", "'n", $key_string);
$keys = explode( "'n", $key_string);
foreach($keys as $index => $key) {
    Key::create(
        array( "serial" => trim($key) )
    );
}

由于我上传的密钥集有数千个,这有时可能需要30秒的时间,在此期间,管理面板自然不会显示任何内容。

现在,我不介意花这个时间。我不需要优化上传来使用一个查询等,但我想得到一些实际的反馈,这样我就知道上传已经进行了多远。


问题

当我上传密钥时,我希望能够每隔几秒钟或百分比更新一次视图中的进度条或计数器(使用当前的$index

有没有一种简单的方法可以无痛地处理这个问题,最好集成在Laravel 4中?我假设这将涉及ajax,但有人能为我指明正确的方向吗?

使用PHP,实际上有两个选项不需要使用Web套接字或Push-Pull设置。这并不是一个真正的Laravel,它更像是一个请求JSON"东西"的AJAX循环。

短轮询

Olark在他们的聊天脚本中使用了这种方法。

setInterval(function() {
    $.getJSON("/path", function(data) {
        // update the view with your fresh data
    });
}, 5000);

长轮询

Javascript

var eventName = function() {
    $.getJSON("/path", function(data) {
        // update the view with your fresh data
        if (data.progress < 100)
            eventName();
    });
};

控制器逻辑

当我让用户上传CSV并等待它完成上传和处理时,我会使用它。

// in your controller
$check = true;
while ($check) {
    // search database
    // compare values
    if ($newDataWasFound)
        $check = false;
    $progressFromAbove = 90;
}
return Response::json(array(
    'newData' => $array,
    'progress' => $progressFromAbove,
));

我用Laravel 3做了一个屏幕截图,但Long Polling与PHP无关,而不是Laravel。https://www.youtube.com/watch?v=LDgJF77jELo

示例

  • https://gist.github.com/clouddueling/5239153
  • https://gist.github.com/clouddueling/6296036

您可以将它放在Session中,然后从另一个链接获取它。

$key_string = rtrim($key_string);
$key_string = str_replace("'n'r", "'n", $key_string);
$keys = explode( "'n", $key_string);
$count = 0;
foreach($keys as $key) {
  Key::create(
      array( "serial" => trim($key) )
  );
  $count++;
  if($count % 5== 0) Session::put('count',$count);
}

//route.php
Route::get('/count', function()
{
   if( Session::has('count'))
        return Session::get('count');
});

无论您使用Laravel还是Core PHP进行编码,都应该尝试一下服务器发送的事件。使用SSE很容易实现。

它基本上包括两个部分:-

1.Javascript API(客户端)-您必须订阅一个事件流,创建一个EventSource对象并向其传递流的URL,如下所示:-

if (!!window.EventSource) {
  var source = new EventSource('stream.php');
} else {
  // Result to xhr polling :(
}

然后为消息事件设置一个处理程序。您可以选择监听打开和错误:-

source.addEventListener('message', function(e) {
  console.log(e.data);
}, false);
source.addEventListener('open', function(e) {
  // Connection was opened.
}, false);
source.addEventListener('error', function(e) {
  if (e.readyState == EventSource.CLOSED) {
    // Connection was closed.
  }
}, false);

2.PHP(服务器端)-您必须发送Content-Type: text/event-stream标头,然后在处理时推送响应,格式如下:-

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
/**
 * Constructs the SSE data format and flushes that data to the client.
 *
 * @param string $id Timestamp/id of this connection.
 * @param string $msg Line of text that should be transmitted.
 */
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));

这所有的片段都是从前面提到的链接中借来的,建议进行彻底的研究以获得清晰的理解。

干杯