Обновление коснулось возможности отправлять повторные циклические запросы на сервер и выполнять один и тот же код несколько раз — до тех пор, пока все, что вам нужно не будет обработано.
Вот небольшая демонстрация того, как это новшество можно использовать:
Включить этот функционал очень просто. Нужно определить переменную $_SESSION['Console']['completed'] и присвоить ей значение false — тогда консоль будет выполнять скрипт до тех пор, пока значение этой переменной не станет равной true.
Вот код, который выполнялся в видео. Здесь происходит пошаговая обработка ресурсов, причем за один шаг обрабатывается только один ресурс. Такой код поможет вам обработать неограниченное число объектов даже на слабом сервере — нужно только время.
<?php $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:
<?php // Сколько ресурсов обрабатывать за раз $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";
Единственный нюанс в том, что код можно продолжать редактировать по ходу выполнения скрипта. Но я еще не определился — баг это или фича)
Илья, спасибо за пулл-реквест! Полезная штука :)
Вот только думаю надо немного механизм изменить. Вот получается, что есть $_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); И действовать это будетолько на текущий шаг. И так в каждом последующем шаге.