[РЕШЕНО] Вопрос для академиков
Сразу оговорюсь, никакого сарказма, на мой взгляд задача действительно должна быть известна тем кто получил академическое образование по специальности программирование. Собственно задача.
Дан массив
[246 => 1, 267 =>2, 296 => 3, 308 => 4, 309 => 5]
Его ключи это id ресурсов, а значения отвечают за их сортировку, пусть будет menuidex. Нужно, чтобы при изменении значения например с ключом 308 с 4 на 2 получился массив
[246 => 1, 267 => 3, 296 => 4, 308 => 2, 309 => 5].
Я написал такое рашение
Дан массив
[246 => 1, 267 =>2, 296 => 3, 308 => 4, 309 => 5]
Его ключи это id ресурсов, а значения отвечают за их сортировку, пусть будет menuidex. Нужно, чтобы при изменении значения например с ключом 308 с 4 на 2 получился массив
[246 => 1, 267 => 3, 296 => 4, 308 => 2, 309 => 5].
Я написал такое рашение
<?php
switch ($modx->event->name) {
case 'OnDocFormSave':
$resource->set('publishedon', time());
$resource->save();
if($resource->get('class_key') == 'Ticket'){
$curPosition = $resource->getTVValue('position');
$positions = [];
if($resource->get('parent') == 73){
$resources = $modx->getIterator('modResource', array('class_key' => 'Ticket', 'id:!=' => $id, 'parent' => 73));
}
else{
$resources = $modx->getIterator('modResource', array('class_key' => 'Ticket', 'id:!=' => $id, 'parent:!=' => 73));
}
foreach($resources as $res){
$pos = $res->getTVValue('position');
if($pos){
$positions[$res->get('id')] = $pos;
}
}
if(in_array($curPosition,$positions)){
asort($positions);
foreach($positions as $id => $pos){
if($pos >= $curPosition){
$modx->log(1, print_r($curPosition,1));
$modx->log(1, print_r($pos,1));
$res = $modx->getObject('modResource', $id);
$res->setTVValue('position', $pos + 1);
$res->save();
$curPosition = $pos + 1;
}
}
}
//$modx->log(1, print_r($positions,1));
}
break;
}
Но кажется мне, что в нём что-то не так, но вот что именно не могу понять.
Поблагодарить автора
Отправить деньги
Комментарии: 12
Нам нужно старое значение menuindex и новое.
Если новое меньше старого, то делаем sql запрос, в котором у ресурсов (только с тем же parent конечно) с menuindex от нового до старого делаем menuindex=menuindex+1.
Если старое меньше нового — наоборот.
Вот пример кода из какого-то процессора (там не ресурсы, а свои объекты).
Если новое меньше старого, то делаем sql запрос, в котором у ресурсов (только с тем же parent конечно) с menuindex от нового до старого делаем menuindex=menuindex+1.
Если старое меньше нового — наоборот.
Вот пример кода из какого-то процессора (там не ресурсы, а свои объекты).
if ($source->get('priority') < $target->get('priority')) {
$this->modx->exec("UPDATE ".$tableName."
SET priority = priority - 1 WHERE
priority <= {$target->get('priority')}
AND priority > {$source->get('priority')}
AND priority > 0
");
} else {
$this->modx->exec("UPDATE ".$tableName."
SET priority = priority + 1 WHERE
priority >= {$target->get('priority')}
AND priority < {$source->get('priority')}
");
}
- Вначале вытащил бы в отдельный массив данные нужных ресурсов (ключ-id, значение-menuindex)
- Сохранил бы в отдельные переменные новый menuindex и его id (в плагине он и так доступен)
- И спокойно бы раскурочил массив из п.1 так как нужно — не в пример нагляднее, чем перебирать ресурсы. Есть методы сортировки, array_flip и так далее..
- Полученный в результате «пыток» в п.3 массив должен содержать: ключ — id ресурса, значение — новое значение menuindex, которое соответствует условиям
- Сохраняем menuindex из массива в ресурсы, id которых в ключе
А где взять старое значение? Изменение делает пользователь, сохраняет и только потом срабатывает плагин.
Если плагин повесить на OnBeforeDocFormSave, то можно обойтись без промежуточного TV
В этом случае нужно помнить, что не срабатывает сохранение TV-поля из плагина. Но оно в данном случае нам и не нужно.
<?php
$eventName = $modx->event->name;
switch($eventName) {
case 'OnBeforeDocFormSave':
$menuindex = $modx->getObject('modResource', $id)->get('menuindex');
$new_menuindex = strip_tags($_POST['menuindex']);
$modx->log(1, print_r($menuindex, 1));
$modx->log(1, print_r($new_menuindex, 1));
break;
}
В этом случае нужно помнить, что не срабатывает сохранение TV-поля из плагина. Но оно в данном случае нам и не нужно.
Почему вы считаете, что TV не сохраняется из плагина? У меня не далее как вчера сохранялась. И второй момент, почему вы считаете, что TV не нужно, ведь значение menuidex сохраняемого ресурса меняет не плагин, а пользователь, т.е. в плагин приходит уже новое значение.
>>>У меня не далее как вчера сохранялась.
Серьезно? На событие OnBeforeDocFormSave? skrinshoter.ru/s/290121/E2iWCCxq
>>>т.е. в плагин приходит уже новое значение.
В плагин на событие OnBeforeDocFormSave приходит новые значение, а вы заметили, откуда я извлекаю старое? Пытались мой пример протестить?
Серьезно? На событие OnBeforeDocFormSave? skrinshoter.ru/s/290121/E2iWCCxq
>>>т.е. в плагин приходит уже новое значение.
В плагин на событие OnBeforeDocFormSave приходит новые значение, а вы заметили, откуда я извлекаю старое? Пытались мой пример протестить?
Сорри, слово before не заметил)))
И вообще TV на самая большая проблема в этой задаче, самая большая проблема это я, потому что я не понимаю что не так, в голове и на бумаге логика безупречна, а код работает не правильно.
Если честно, я не сильно вчитывался в код, приведенный в условии. Но я бы в принципе по-другому пути пошел.
Тут всё наглядно, при работе с массивом можно каждый шаг дебажить и тестить. А так с наскока — перебирая ресурсы — мне, к примеру, тяжеловато сообразить
Тут всё наглядно, при работе с массивом можно каждый шаг дебажить и тестить. А так с наскока — перебирая ресурсы — мне, к примеру, тяжеловато сообразить
Ну суть та же, только я хотел обойтись без промежуточного массива. По факту
$resources = $modx->getIterator('msProduct', array('parent' => $resource->get('parent')));
Массив для пункта 1 можно вытащить только перебрав $resources. И да, с массивом работать удобнее, но п.3 это проблема. Давайте псевдокод напишу$oldValue // старое значение позиции текущего ресурса
$newValue // новое значение
$resources // массив со всеми значениями [id => menuindex]
//По идее надо перебрать $resources предварительно сравнив $oldValue и $newValue
if($newValue < $oldValue){
foreach($resources as $r){
//надо прибавить 1 ко всем menuindex которые соответствуют $newValue <= menuindex < $oldValue
}
else{
//надо отнять 1 ото всех menuindex которые соответствуют $newValue > menuindex >= $oldValue
}
}
Но получается что если $newValue < $oldValue, то последнее значение не меняется.
Я переписал код, но он всё равно как-то не так работает
<?php
switch ($modx->event->name) {
case 'OnDocFormSave':
$oldValue = $resource->getTVValue('old_value');
$newValue = $resource->get('menuindex');
$resource->setTVValue('old_value', $newValue);
$resource->save();
$resources = $modx->getIterator('msProduct', array('parent' => $resource->get('parent')));
if($newValue < $oldValue){
foreach($resources as $res){
$menuindex = $res->get('menuindex');
if($menuindex >= $newValue && $menuindex < $oldValue && $res->get('id') != $id){
$res->set('menuindex', $menuindex + 1);
$res->set('old_value', $menuindex + 1);
}
$res->save();
}
}
else{
foreach($resources as $res){
$menuindex = $res->get('menuindex');
if($menuindex > $newValue && $menuindex <= $oldValue && $res->get('id') != $id){
$res->set('menuindex', $menuindex - 1);
$res->set('old_value', $menuindex - 1);
}
$res->save();
}
}
break;
}
Зачем высчитывать все эти расхождения, если можно просто заново проиндексировать массив на основе нового значения?
Я предполагаю, что в этом массиве у тебя собраны сразу все необходимые id:
Если тебе не принципиально, чтобы первый индекс был единицой, то можно еще проще:
Я предполагаю, что в этом массиве у тебя собраны сразу все необходимые id:
<?php
$array = [246 => 1, 267 => 2, 296 => 3, 308 => 4, 309 => 5];
$affectedResource = 308;
$newIndex = 2;
$array[$affectedResource] = $newIndex - 0.5;
asort($array);
$index = 1; // индексирование будет начато с единицы
foreach ($array as $id => &$oldIndex) {
$oldIndex = $index;
$index++;
}
return $array;
Если тебе не принципиально, чтобы первый индекс был единицой, то можно еще проще:
<?php
...
asort($array);
return array_flip(array_keys($array));
Спасибо всем участвующим. Будем считать вопрос решённым.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.