Yii have a CJuiProgressBar, but it is static. If we want a dynamic progress bar to show the percentage or status, we have to do more things. I make it successfully and am glad to share it with you.
There are 6 files changed or added (to get zip file or any question,mail me by hehbhehb#163.com)
- 1 Component(or model) file
ProgressBar.php
class ProgressBar { private $key; private $running; private $total; private $done; public function __construct($key) { $this->key = $key; } public function start($total) { $this->running = 1; $this->done = 0; $this->total = $total; $this->put(); } public function stop() { $this->running = 0; $this->put(); } public function inc($step=1) { $this->done += $step; $this->put(); } public function put() { $ret = Yii::app()->cache->set($this->key, array('running'=>$this->running, 'total'=>$this->total, 'done'=>$this->done)); } public static function get($key) { $test = 1; //$test = 0; if ($test) { $data = Yii::app()->cache->get($key); if($data === false) { $data = array('running'=>1, 'total'=>119, 'done'=>0); } $data['done'] = $data['done'] + 10; if ($data['done'] > 119) { $data['running'] = 0; } Yii::app()->cache->set($key, $data, 1*60); return $data; } $data = Yii::app()->cache->get($key); if($data === false) { $data = array('running' =>1, 'total'=>100, 'done'=>0); } return $data; } }
- 2 Controller files
MyController.php
class MyController extends Controller { public function actions() { return array( 'GetProgressBarData'=>array( 'class'=>'ActionGetProgressBarData', ), ); } public function actionBatchHandle() { ... if(isset($_POST)) { $post = $_POST; $id = uniqid(); $filename = Yii::app()->getRuntimePath().DIRECTORY_SEPARATOR."{$id}"; file_put_contents($filename, json_encode($post)); $command = 'php ' . Yii::app()->getBasePath().DIRECTORY_SEPARATOR.'yiic.php ' . "cli BatchHandle --id=$id > /dev/null 2>&1 &"; exec($command); } $this->render('form',array('model'=>$model)); } }
ActionGetProgressBarData.php, which is also placed under /controllers directory
class ActionGetProgressBarData extends CAction { public function run($key) { $response = ProgressBar::get($key); echo json_encode($response); } }
- 2 View files
form.php
<div class="form"> <?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'form_id', )); ... <div class="row buttons"> <?php echo CHtml::submitButton('Batch Process', array('name'=>'Batch')); <?php echo CHtml::hiddenField('progress_key', uniqid(), array('id'=>'progress_key')); </div> <?php $this->endWidget(); </div> <?php $js_code=<<<EOD jQuery('#form_id input[type=submit]').on('click', function() { $('#progress_key').val(uniqid()); open_progress_bar(); return true; }); EOD; Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.'form_id', $js_code); <?php $this->widget('zii.widgets.jui.CJuiButton',array('name'=>'just_for_include_jqeuryui_css','htmlOptions'=>array('style'=>'display:none;'))); $this->renderPartial('VProgressBar'); // include the progress bar here, should we wrap it into a CJuiWidget?
VProgressBar.php
<script type="text/javascript"> function open_progress_bar() { my_title = 'Processing, please wait...'; $('#modalDivProgress').dialog({ autoOpen: true, width: 800, height:150, modal: true, title: my_title }); $("#progressbar").progressbar({value: 0}); show_progress(); } function show_progress() { var url = '<?php echo Yii::app()->controller->createUrl("GetProgressBarData"); ?>'; var progress_key = $('#progress_key').val(); $.getJSON(url + "&key=" + progress_key, function(data) { var done = parseInt(data.done); var total = parseInt(data.total); var percentage = Math.floor(100 * done / total); if (percentage > 100) percentage = 100; $("#progressbar").progressbar( "value", percentage); var percentage_txt = percentage + "%" + " [" + done + "/" + total + "]"; $("#percentage").text(percentage_txt); if (percentage == 100) { alert('Done'); $("#progressbar").progressbar( "destroy"); $("#modalDivProgress").dialog("close"); } else { setTimeout("show_progress()", 5000); } }); } function uniqid (prefix, more_entropy) { // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + revised by: Kankrelune (http://www.webfaktory.info/) // % note 1: Uses an internal counter (in php_js global) to avoid collision // * example 1: uniqid(); // * returns 1: 'a30285b160c14' // * example 2: uniqid('foo'); // * returns 2: 'fooa30285b1cd361' // * example 3: uniqid('bar', true); // * returns 3: 'bara20285b23dfd1.31879087' if (typeof prefix === 'undefined') { prefix = ""; } var retId; var formatSeed = function (seed, reqWidth) { seed = parseInt(seed, 10).toString(16); // to hex str if (reqWidth < seed.length) { // so long we split return seed.slice(seed.length - reqWidth); } if (reqWidth > seed.length) { // so short we pad return Array(1 + (reqWidth - seed.length)).join('0') + seed; } return seed; }; // BEGIN REDUNDANT if (!this.php_js) { this.php_js = {}; } // END REDUNDANT if (!this.php_js.uniqidSeed) { // init seed with big random int this.php_js.uniqidSeed = Math.floor(Math.random() * 0x75bcd15); } this.php_js.uniqidSeed++; retId = prefix; // start with prefix, add current milliseconds hex string retId += formatSeed(parseInt(new Date().getTime() / 1000, 10), 8); retId += formatSeed(this.php_js.uniqidSeed, 5); // add seed hex string if (more_entropy) { // for more entropy we add a float lower to 10 retId += (Math.random() * 10).toFixed(8).toString(); } return retId; } </script> <div id="modalDivProgress" style="margin: 20px auto;"> <div id="progressbar" style="width:780px;"></div> <div id="percentage" style="margin-top: -22px;margin-left:310px;"></div> </div>
- 1 Command file CliCommand.php
class CliCommand extends CConsoleCommand { public function actionBatchHandle($id) { set_time_limit(0); $filename = Yii::app()->getRuntimePath().DIRECTORY_SEPARATOR."{$id}"; $post = file_get_contents($filename); $post = json_decode($post, true); //$criteria = getCriteria($post); ... $total = Yii::app()->db->getCommandBuilder()->createCountCommand('table_name', $criteria)->queryScalar(); $progress = new ProgressBar($post['progress_key']); $progress->start($total); $dataReader = Yii::app()->db->getCommandBuilder()->createFindCommand('table_name', $criteria)->query(); while(($row=$dataReader->read())!==false) { // process one record ... $progress->inc(); } $progress->stop(); unlink($filename); } }