[РЕШЕНО] Вопрос для академиков
        Сразу оговорюсь, никакого сарказма, на мой взгляд задача действительно должна быть известна тем кто получил академическое образование по специальности программирование. Собственно задача.
Дан массив
[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));            
                Спасибо всем участвующим. Будем считать вопрос решённым.            
                    
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.