ProgressBar для CakePHP в стиле WinRAR
Я так люблю CakePHP, что часто мучаю его так, как и не догадывались его создатели. Некоторые задачи у меня выполняются по несколько часов так как приходится обрабатывать огромные таблицы. При этом возникают проблемы - Request Time-out, который появляется, если долго ничего не выдавать браузеру. Я раньше выводил точки, потом номер обрабатываемой записи. Для того, чтобы просмотреть, сколько уже сделано, надо было скроллить в самый низ, который постоянно исчезал.
Сегодня мне это наконец надоело и я сделал привычный ProgressBar.
Хочу, чтобы можно было писать
-
for ($i=0; $i<$countCustomers; $i++) {
-
$this->jsProgressBar($i/$countCustomers);
-
-
$this->Customer->process($customers[$i]);
-
}
и мне выводился красивый ProgressBar.

Обратите внимание на "Loading..." сверху. Это показывает, что страница ещё грузится.
А ещё чтобы можно было писать
и под ProgressBar выводилось что-то вроде "Customer 17/83".
А чтобы совсем отбить желание что-то хотеть, так чтобы можно было выводить несколько ProgressBar
-
for ($i=0; $i<$countCustomers; $i++) {
-
-
$orders = $this->Customer->orders($customers[$i]);
-
-
for ($j=0; $j<$countOrders; $j++) {
-
$this->Customer->Order->process($orders[$j]);
-
}
-
}
Примерно так:

Чтобы добиться такой красоты, добавьте функцию в app_controller.php
-
/**
-
* Shows and updates progress bar for long-processing actions
-
*
-
* @param float $ratio 0<ratio<1; 0=0%, 1=100%
-
* @param string $status optional. If you have something to show under progress bar
-
* @param string $name name of the progress bar if you need more than one
-
*/
-
function jsProgressBar($ratio=0, $status=null, $name='default') {
-
-
// common for all progress bars
-
e('
-
<style>
-
div.progressbar {
-
border:1px solid #06d;
-
width: 75%
-
}
-
div.progressbar div {
-
height:1.2em;
-
line-height:1.2em;
-
background-color:#03a;
-
border-right:1px solid #03a;
-
text-align:right; color:#fff;
-
width:0;
-
overflow:hidden;
-
padding-right: 5px
-
}
-
</style>
-
<body>
-
');
-
}
-
-
// init current progress bar if needed
-
e('
-
<div class="progressbar"><div id="progressbar-'.$name.'"></div></div>
-
<div class="statusbar" id="statusbar-'.$name.'"></div>
-
');
-
-
$inited[] = $name;
-
}
-
-
// set current position
-
if ($status===null) {
-
$statusScript = '';
-
} else {
-
$statusScript = 'document.getElementById("statusbar-'.$name.'").innerHTML = "'.$status.'";';
-
}
-
-
e('
-
<script>
-
var progress = document.getElementById("progressbar-'.$name.'");
-
var percent = '.$percents.'+"%";
-
progress.innerHTML = percent;
-
progress.style.width = percent;
-
'.$statusScript.'
-
</script>
-
');
-
}
Идея в том, чтобы выводить скрипт, который будет менять значение и форматирование определённого div.
Кстати, если вывести какой-то текст, то $this->redirect в контроллере уже не будет работать как и все проявления header() вроде $this->Session->setFlash(). Поэтому, если нужен setFlash, то делайте его до jsProgressBar.
А чтобы сделать redirect, я написал ещё одну маленькую приятность.
URL в неё можно передавать в том же формате, как и для обычного $this->redirect, то есть подходит как '/customers/', так и array('action'=>'index'). В конце вместо
-
$this->redirect('/', null, true);
пишите
Спасибо огромное. Добавьте пожалуйста на http://cake-php.ru/wiki/
Полезная вещь! Спасибо.
Вещь оч хорошая, все бы хорошо, кроме одного - трудно представить куда что вставлять для обработки записей из бд. Т.к я как начинающий и только осваиваю cakephp (1 вечер) - не понимаю какие файлы надо создавать, что в них писать и как использовать(модели, view, контроллеры). Делал стандартный пример с блогом - получилось, а вот с процессом вашим пока не очень понимаю, может распишете, на почту, поподробней? Буду благодарен в двойне))))
[...] 2. Проблемы с долгими скриптами Известная ошибка Request timeout возникает, если не передавать никаких данных в браузер долгое время (вроде 30 секунд). Решается тем, что периодически выводится какой-то текст. [...]
Спасибо, полезная и интерестная статья.. Надо будет как-то испробовать, и поиздеваться над кодом маленько)
Я когда-то сталкивалкивался с такой проблемой.. Нужно было крон-скрипт написать, для обработки данных в БД. Когда тестил пользовался браузером. Есть и другое решение..
Например:
set_time_limit(0); // отключаем лимит обработки скрипта
ignore_user_abort(false); // должно ли отсоединение клиента вызывать прерывание выполнения скрипта
ini_set('output_buffering','Off'); // и собственно та нужная нам функция
ini_set('output_buffering','Off') - ею мы говорим, чтобы PHP не буферизовал данные, а сразу выдавал их браузеру. Правда не все хостинги позволяют это.
Да, чуть не забыл, output_buffering = off в php.ini лечит эту проблему
ЗЫ: если где ошибся - поправте =)