问题
TL;DR
I would like to send data to update live in a view, such as a progress bar showing the status of an action. What is the best way to do that in laravel 4?
The Setup
I'm working on a Laravel 4 based project where each user can redeem a serial key.
I've made an admin backend where I can easily paste in a list of keys, or upload a file of them.
Let's say $key_string
is the string of newline-seperated keys that I've uploaded, and want to parse out to then upload the contained key strings from - here is the simplified code that adds the keys:
$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) )
);
}
Since the sets of keys I upload number in the thousands, this can sometimes take a good 30 seconds, during which time the admin panel naturally doesn't show anything.
Now, I don't mind it taking this time. I don't need to optimize the upload to use one query, etc, but I would like to have some actual feedback so I know how far the upload has gone.
The Question
When I upload keys, I would like to be able to update a progress bar or counter in my view every few seconds or percent ticks (using the current $index
)
Is there an easy way to handle this painlessly, preferably integrated in Laravel 4? I'm assuming this would involve ajax, but can someone point me in the right direction?
回答1:
With PHP there are really two options without going to Web Sockets or Push-Pull setups. This isn't really a Laravel thing it's more of an AJAX loop that requests JSON "thing".
Short polling
Olark uses this methodology for their chat script.
setInterval(function() {
$.getJSON("/path", function(data) {
// update the view with your fresh data
});
}, 5000);
Long polling
Javascript
var eventName = function() {
$.getJSON("/path", function(data) {
// update the view with your fresh data
if (data.progress < 100)
eventName();
});
};
Controller Logic
I use this when I have users upload a CSV and are waiting for it to finish uploading and be processed.
// 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,
));
I made a screencast on this using Laravel 3 but Long Polling is PHP relevant not Laravel. https://www.youtube.com/watch?v=LDgJF77jELo
Examples
- https://gist.github.com/clouddueling/5239153
- https://gist.github.com/clouddueling/6296036
回答2:
You could put it in Session and get it from another link.
$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');
});
回答3:
Whether you code using Laravel or Core PHP, you should give Server sent events a try. It is easily doable using SSE.
It basically includes two parts:-
1. Javascript API (Client side) - You will have to subscribe to an event stream, create an EventSource object and pass it the URL of your stream like this:-
if (!!window.EventSource) {
var source = new EventSource('stream.php');
} else {
// Result to xhr polling :(
}
Then setting up a handler for the message event. You can optionally listen for open and error:-
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 (Server side ) - You will have to send Content-Type: text/event-stream
header and then push the response as and when processed, in predefined format like this:-
<?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()));
This all snippets is borrowed from aforementioned link and a thorough study is recommended for crystal clear understanding.
Cheers
来源:https://stackoverflow.com/questions/18344343/update-live-data-like-progress-bar-in-view-with-laravel-4