Срабатывание плагина, если tv изменился
Приветствую.
Подскажите, есть ли возможность проверить, изменилось ли значение tv-параметра ресурса и (если изменилось) выполнить плагин по onDocFormSave (например)?
Ситуация: для раздела есть поле скидка. При его изменении — изменяется цена товаров данного подраздела.
Нужно запустить плагин (выполнить изменение цен) только тогда, когда значение скидки изменилось (чтобы не нагружать сервак просто так).
Подскажите, есть ли возможность проверить, изменилось ли значение tv-параметра ресурса и (если изменилось) выполнить плагин по onDocFormSave (например)?
Ситуация: для раздела есть поле скидка. При его изменении — изменяется цена товаров данного подраздела.
Нужно запустить плагин (выполнить изменение цен) только тогда, когда значение скидки изменилось (чтобы не нагружать сервак просто так).
Комментарии: 20
Сразу в голову пришло запихнуть куда-нибудь массив вида $sales[$resource_id] = $sale в виде json и проверять новое значение TV с ним.
Или для этих же целей можно использовать:
как то так…
Или для этих же целей можно использовать:
$prop = $modx->fromJSON($resource->get('properties'));
$old_sale = empty($prop['old_sale']) ? 0 : $prop['old_sale'];
... тут сравниваем скидку с $old_sale
...
$prop['old_sale'] = $resource->getTVValue('sale');
$resource->set('properties', $modx->toJSON($prop')))
$resource->save();
как то так…
А где менеджер меняет значение, в админке или на сайте?
В админке.
switch ($modx->event->name) {
case 'OnDocFormPrerender':
$_SESSION['before'] = $resource->getTVValue('adres'); // адрес при загрузке
break;
case 'OnDocFormSave':
$after = $resource->getTVValue('adres'); // адрес при сохранении
if($after == $_SESSION['before']){
$modx->event->output('равны');
}else{
$modx->event->output('не равны');
}
break;
}
Можно и так. Только
Вот чуть измененный вариант
$modx->event->output('равны');
в этом событии не сработает.Вот чуть измененный вариант
switch ($modx->event->name) {
case 'OnDocFormRender':
$_SESSION['discount'] = $resource->getTVValue('discount');
break;
case 'OnDocFormSave':
$new_discount = $resource->getTVValue('discount');
if($new_discount != $_SESSION['discount']){
$modx->runSnippet('RecalcPrice',array('discount'=>$new_discount,'parent'=>$resource->id ));
}
unset($_SESSION['discount']);
break;
}
В сниппете RecalcPrice меняешь цены согласно новой скидке для ресурсов из раздела, указанном в параметре parent.
Спасибо)
А еще подскажи пжлста, как в сниппете RecalcPrice получить пришедшие переменные?
Раньше не доводилось вызывать runSnippet
А еще подскажи пжлста, как в сниппете RecalcPrice получить пришедшие переменные?
Раньше не доводилось вызывать runSnippet
Как к обычным переменным $discount, $parent.
И есть еще массив всех переменных сниппета $scriptProperties. Можно через него $scriptProperties['discount'] и т.п.
И есть еще массив всех переменных сниппета $scriptProperties. Можно через него $scriptProperties['discount'] и т.п.
Если ТВ меняется в админке (или вообще, через процессор), то нужно ловить событие OnBeforeDocFormSave и сравнивать присланное значение ТВ с имеющимся в документе.
Если они отличаются — выполнять свой код по обновлению цен. Можно прям в этом событии, а можно поставить флаг в сессию, выполнить код в OnDocFormSave (то есть, уже после сохранения новой цены в ТВ) и удалить флаг до следующего раза.
В любом случае, нужно слушать события изменения документа, потому что все сохранения ТВ — там.
Если они отличаются — выполнять свой код по обновлению цен. Можно прям в этом событии, а можно поставить флаг в сессию, выполнить код в OnDocFormSave (то есть, уже после сохранения новой цены в ТВ) и удалить флаг до следующего раза.
В любом случае, нужно слушать события изменения документа, потому что все сохранения ТВ — там.
Ну это все понятно (в теории).
Но вот как получить ТВ по событию OnBeforeDocFormSave (кроме предложенного выше решения)?
Но вот как получить ТВ по событию OnBeforeDocFormSave (кроме предложенного выше решения)?
Все присылаемые значения можно получить из $_POST, все имеющиеся в ресурсе через $resource->get().
ТВ в $_POST, если я не ошибаюсь, получаются как tv_id, то есть:
ТВ в $_POST, если я не ошибаюсь, получаются как tv_id, то есть:
$tv = $_POST['tv_5'];
Но вот как получить ТВ по событию OnBeforeDocFormSave (кроме предложенного выше решения)?
В OnBeforeDocFormSave новые (сохраняемые) значения TV можно получить следующими способами:
1) Из массива $_POST (как указал Василий). Но этот вариант работает только при вызове коннекторов (сохранение ресурса в админке). Если процессор вызывается из собственного кода, то никаких параметров в запросе не будет.
2) Из массива data, который также передаётся плагину (не задокументирован). В этом массиве лежат все новые (сохраняемые) параметры — и стандартные, и ТВ. Ключ стандартного параметра = имени параметра, ключ ТВ = tvID.
В OnBeforeDocFormSave старые (исходные) значения TV можно получить методом getTVValue (извлекает данные непосредственно из БД).
Самый корректный вариант, имхо, — это OnBeforeDocFormSave + массив data + getTVValue.
Спасибо за оживленную дискуссию! :-)
Итак, я попробовал все предложенные варианты. У каждого свои ограничения:
0. При работе с сессиями в любом виде, на странице (в админке), в которой производится изменение скидки, выводится "../www/core/components/shopkeeper/elements/tv/output/".
1. От Сергея modx.pro/help/4600/#comment-33447
OnDocFormRender не выполняется при сохранении значения, только при перезагрузке страницы (вполне логично).
2. От Василия modx.pro/help/4600/#comment-33439
$_POST тоже приходит только при перезагрузке страницы + приходится пользоваться переменной сессии.
3. От Cyrax_02 modx.pro/help/4600/#comment-33448 Не смог добраться до массива data.
В итоге остановился на варианте №1. Указанные ограничения победить пока не удалось.
код:
0. При работе с сессиями в любом виде, на странице (в админке), в которой производится изменение скидки, выводится "../www/core/components/shopkeeper/elements/tv/output/".
1. От Сергея modx.pro/help/4600/#comment-33447
OnDocFormRender не выполняется при сохранении значения, только при перезагрузке страницы (вполне логично).
2. От Василия modx.pro/help/4600/#comment-33439
$_POST тоже приходит только при перезагрузке страницы + приходится пользоваться переменной сессии.
3. От Cyrax_02 modx.pro/help/4600/#comment-33448 Не смог добраться до массива data.
В итоге остановился на варианте №1. Указанные ограничения победить пока не удалось.
код:
<?php
/*
* Action: OnDocFormRender, OnDocFormSave
*/
global $modx;
if ($mode == modSystemEvent::MODE_UPD ) {
$parent = $resource->get('parent');
$isDiscountChanged = 0;
if ($parent == "9") {
$startTime = microtime(true);
$brand = $resource->get('menutitle');
switch ($modx->event->name) {
case 'OnDocFormRender':
$_SESSION['discount_before'] = (float)$resource->getTVValue(13); // скидка при загрузке
$modx->log(modX::LOG_LEVEL_ERROR, '$discount_before: ' . $_SESSION['discount_before']);
break;
case 'OnDocFormSave':
$discount = (float)$resource->getTVValue(13); // скидка при сохранении
$priceCoeff = (float)$resource->getTVValue(14); // коэфф. при сохранении
if($discount != $_SESSION['discount_before']){
$isDiscountChanged = 1;
}
if ($isDiscountChanged) {
{...} // получение выборки из базы
if ( $query -> prepare() && $query -> stmt -> execute() ) {
while ( $queryRow = $query -> stmt -> fetch( PDO::FETCH_ASSOC ) ) {
$thisProject = $modx -> getObject( 'modResource', $queryRow['id'] );
$price = $thisProject -> getTVValue( 1 );
$discountPrice = round((1-$discount/100)*$price);
$thisProject->setTVValue(2, $discountPrice); //внесение цены со скидкой
}
}
unset($_SESSION['discount_before']);
$finishTime = microtime(true);
$timeScript = $finishTime - $startTime;
$modx->log(modX::LOG_LEVEL_ERROR, 'setDiscount checked ' . $i . ' elements');
$modx->log(modX::LOG_LEVEL_ERROR, 'Time wasted: ' . round($timeScript,4) . 'sec');
break;
}
}
}
Дополнение:
По OnDocFormRender значение изменяется, но не обнуляется.
Думаю, с $_POST тоже самое.
По OnDocFormRender значение изменяется, но не обнуляется.
Думаю, с $_POST тоже самое.
3. От Cyrax_02 modx.pro/help/4600/#comment-33448 Не смог добраться до массива data.
В итоге остановился на варианте №1. Указанные ограничения победить пока не удалось.
Навскидку могу предположить, что:
а) ты его «искал» в тот момент, когда у тебя плагин не был подписан на событие OnDocFormSave и (или) OnDocFormRender. Массив $data передаётся только обработчику OnBeforeDocFormSave
б) получить к нему доступ ты пытался в разделе case 'OnDocFormRender' или case 'OnDocFormSave' оператора switch. С массивом $data нужно работать в case 'OnBeforeDocFormSave'
Ещё раз по порядку:
1) Подписываешь плагин на событие OnBeforeDocFormSave
2) В плагине в разделе case 'OnBeforeDocFormSave' пишешь:
$modx->log(modX::LOG_LEVEL_ERROR, print_r($data, true));
3) Загружаешь страницу (именно ту, которая вызывает плагин)4) Смотришь логи modx: там увидишь все НОВЫЕ стандартные и ТВ-параметры, которые содержит массив $data. Также увидишь их ключи (как к ним обращаться).
События OnBefore...FormSave генерируются до физического сохранения новых значений и только в обработчиках этого события можно одновременно получить доступ и к старым значениям полей, и к новым. Именно для этого в OnBefore...FormSave и передаётся массив новых значений $data, которые будут физически сохранены после этого события.
P.S. У варианта OnBeforeDocFormSave + массив data + getTVValue пока не вижу никаких ограничений. Полная свобода.
1. От Сергея modx.pro/help/4600/#comment-33447
OnDocFormRender не выполняется при сохранении значения, только при перезагрузке страницы (вполне логично).
Именно поэтому, если в период между загрузкой страницы ресурса и сохранением ресурса сессия истечёт, то при сохранении ресурса (будет запрошена авторизация) в массиве $_SESSION значение discount_before установлено не будет.
Более того, если другой пользователь (с другой сессией) изменит значение скидки в период между загрузкой страницы ресурса и сохранением ресурса, то в OnDocFormRender будут получены старые значения (имевшие место в момент открытия страницы ресурса). Впрочем, в вашем случае, к проблемам это не приведёт, но во многих других задачах, где требуется обязательно получать актуальные на текущий момент значения, этот факт делает данный способ получения старых (исходных) значений неприменимым.
2. От Василия modx.pro/help/4600/#comment-33439
$_POST тоже приходит только при перезагрузке страницы + приходится пользоваться переменной сессии.
В массиве $_POST данные передаются именно в момент сохранения ресурса (скрипт сохранения вызывает коннектор путём отправки самостоятельного http-запроса к серверу).
Для получения старых (исходных) значений необходимо:
а) в OnBeforeDocFormSave — метод getTVValue()
б) в OnDocFormSave — только через ранее «запомненные» значения (например, через переменные сессии)
В любом случае, как я уже говорил, новых значений в POST-параметрах запроса не будет, если ресурс сохраняется из собственного кода. Кроме того, от версии к версии формат передаваемых в $_POST данных может меняться, поскольку эти данные предназначены исключительно для внутренних нужд modx (для коннекторов).
Cyrax_02 , спасибо за развернутый ответ.
Попробовал ваш метод — действительно, все просто.
Только вот проблема теперь с shopkeeper'ом (тестировал на нескольких сайтах).
Непонятно, почему, но
Отписал разработчику shopkeeper'a. После устранения проблемы буду использовать ваш метод.
Попробовал ваш метод — действительно, все просто.
Только вот проблема теперь с shopkeeper'ом (тестировал на нескольких сайтах).
Непонятно, почему, но
switch ($modx->event->name) {
case 'OnBeforeDocFormSave':
$discount = (float)$resource->getTVValue(13);
$modx->log(modX::LOG_LEVEL_ERROR, '$discount: ' . $discount);
break;
}
выдает ошибку "../www/core/components/shopkeeper/elements/tv/output/".Отписал разработчику shopkeeper'a. После устранения проблемы буду использовать ваш метод.
Текст ошибки?
Подскажите, делаю плагин на событие OnDocFormSave, для выбора товара с таким же алиасом из контекста web.
Для автоматического заполнения опции price_oct_day
Подскажите где косяк?
Для автоматического заполнения опции price_oct_day
<?php
if ($modx->event->name != "OnDocFormSave" || $resource->get('class_key') != 'msProduct' ) return;
$web_uri = $resource->get('alias');
if (empty($resource->get('price_oct_day')))
{
$res = $modx->getObject('msProduct', array('context_key' => 'web', 'alias' => $web_uri));
$tv_auto = $res->get('price_oct_day');
$resource->setTVvalue('price_oct_day', $tv_auto);
}
$resource->save();
Но при сохранении — тв поле price_oct_day не меняется =(Подскажите где косяк?
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.