[Console 2.0.4-beta] Циклические запросы в консоли MODX

Сегодня вышла новая версия дополнение Console для MODX.

Обновление коснулось возможности отправлять повторные циклические запросы на сервер и выполнять один и тот же код несколько раз — до тех пор, пока все, что вам нужно не будет обработано.

Вот небольшая демонстрация того, как это новшество можно использовать:

Включить этот функционал очень просто. Нужно определить переменную $_SESSION['Console']['completed'] и присвоить ей значение false — тогда консоль будет выполнять скрипт до тех пор, пока значение этой переменной не станет равной true.

Вот код, который выполнялся в видео. Здесь происходит пошаговая обработка ресурсов, причем за один шаг обрабатывается только один ресурс. Такой код поможет вам обработать неограниченное число объектов даже на слабом сервере — нужно только время.

$q = $modx->newQuery('modResource', array('published' => 0));
$q->limit(1);
if ($resources = $modx->getCollection('modResource', $q)) {
    foreach ($resources as $resource) {
        print "Публикую ресурс <b>".$resource->get('pagetitle')."</b>";
        $resource->set('published', 1);
        $resource->save();
    }
    // Говорим консольке, что обработка еще не завершена
    $_SESSION['Console']['completed'] = false;
} else {
    // Останавливаем обработку
    $_SESSION['Console']['completed'] = true;
    print "Готово";
}

А вот пример посложнее — уже с использованием offset:

// Сколько ресурсов обрабатывать за раз
$step = 1;
// Если процесс уже остановлен, сбрасываем OFFSET
if (!isset($_SESSION['Console']['completed'])) {
    $_SESSION['console_offset'] = 0;
}
$offset = isset($_SESSION['console_offset']) && $_SESSION['console_offset'] ? $_SESSION['console_offset'] : 0;
// Формируем запрос
$q = $modx->newQuery('modResource');
$total = $modx->getCount('modResource', $q);
// Пропускаем все уже обработанные объекты
$q->limit($step, $offset);
$resources = $modx->getCollection('modResource', $q);
// Обработка
foreach ($resources as $resource) {
    print "<p>Processing resource <b>".$resource->get('pagetitle')."</b></p>";
    sleep(0.5);
}
// Меняем offset
$_SESSION['console_offset'] = $offset + $step;
if ($_SESSION['console_offset'] >= $total) {
  $sucsess = 100;
  $_SESSION['Console']['completed'] = true;
} else {
  $sucsess = round($_SESSION['console_offset'] / $total, 2) * 100;
  $_SESSION['Console']['completed'] = false;
}
for ($i=0; $i<=100; $i++) {
    if ($i <= $sucsess) {
        print '=';
    } else {
        print '_';
    }
}
print "\n";
print $sucsess.'% ('.$_SESSION['console_offset'].')'."\n\n";

Единственный нюанс в том, что код можно продолжать редактировать по ходу выполнения скрипта. Но я еще не определился — баг это или фича)

Comments

Илья, спасибо за пулл-реквест! Полезная штука :) Вот только думаю надо немного механизм изменить. Вот получается, что есть $_SESSION['Console']['completed'] === false, то скрипт опять выполняется в цикле. А вот рассмотрим такой пользовательский сценарий:

  1. Запускаем циклический скрипт, устанавливающий $_SESSION['Console']['completed'] = false;
  2. Этот скрипт при выполнении разваливается или еще по какой причине не доходит до того, чтобы установить $_SESSION['Console']['completed'] = true.
  3. Запускаем новый скрипт на выполнение, не циклический. Он все равно начнет отрабатываться бесконечно, потому как $_SESSION['Console']['completed'] === false, и true он не устанавливает.

Правильней не $_SESSION['Console']['completed'] === false проверять, а $this->getProperty('progress') == true. То есть в процессе выполнения ты смотришь, если надо повторно выполнить скрипт, то устанавливаешь $this->setProperty('progress', true); И действовать это будет только на текущий шаг. И так в каждом последующем шаге.