Skip to content

Commit 806fa54

Browse files
jbonorclaude
andcommitted
Fix: field drag-and-drop reorder throws "Unknown field" RuntimeException
The REDIPS drag-and-drop library sends 1-based DOM row indices as old_order/new_order, but reorder.php treated them as database ranking values. When rankings have gaps (from deletions or prior reorders), DOM indices diverge from stored rankings, causing the query `WHERE ranking = old_order` to find no matching field. Refactor reorder.php to accept positional indices: retrieve all fields ordered by ranking ASC, map them to 1-based positions matching REDIPS row indices, reorder via array manipulation, and persist with normalized contiguous rankings. This also auto-repairs ranking gaps on every reorder operation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fab59ee commit 806fa54

1 file changed

Lines changed: 30 additions & 41 deletions

File tree

ajax/reorder.php

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
* -------------------------------------------------------------------------
2929
*/
3030

31-
use Glpi\DBAL\QueryExpression;
32-
3331
Session::checkLoginUser();
3432

3533
if (
@@ -49,59 +47,50 @@
4947
/** @var DBmysql $DB */
5048
global $DB;
5149

52-
// Retrieve id of field to update
53-
$field_iterator = $DB->request(
50+
// Retrieve all fields for this container ordered by ranking.
51+
// Row indices from the JS drag-and-drop library (REDIPS) start at 1 (row 0 is
52+
// the table header), so they map to 1-based ordinal positions, not to the raw
53+
// ranking values stored in DB (which may contain gaps).
54+
$all_fields_iterator = $DB->request(
5455
[
5556
'SELECT' => 'id',
5657
'FROM' => $table,
5758
'WHERE' => [
5859
'plugin_fields_containers_id' => $container_id,
59-
'ranking' => $old_order,
6060
],
61+
'ORDER' => 'ranking ASC',
6162
],
6263
);
6364

64-
if (0 === $field_iterator->count()) {
65-
// Unknown field
65+
// Build an ordered list of field IDs (1-indexed to match row indices).
66+
$fields = [];
67+
$position = 1;
68+
foreach ($all_fields_iterator as $row) {
69+
$fields[$position] = $row['id'];
70+
$position++;
71+
}
72+
73+
if (!array_key_exists($old_order, $fields)) {
74+
// Unknown field at given position
6675
throw new RuntimeException('Unknown field', 404);
6776
}
6877

69-
$field_id = $field_iterator->current()['id'];
78+
// Remove the dragged field from its old position and re-insert at the new one.
79+
$field_id = $fields[$old_order];
80+
unset($fields[$old_order]);
81+
$fields = array_values($fields); // re-index to 0-based
7082

71-
// Move all elements to their new ranking
72-
if ($old_order < $new_order) {
83+
// Convert new_order (1-based row index) to 0-based insertion index.
84+
$insert_index = $new_order - 1;
85+
array_splice($fields, $insert_index, 0, [$field_id]);
86+
87+
// Persist the new ordering with contiguous rankings starting at 1.
88+
$ranking = 1;
89+
foreach ($fields as $id) {
7390
$DB->update(
7491
$table,
75-
[
76-
'ranking' => new QueryExpression($DB->quoteName('ranking') . ' - 1'),
77-
],
78-
[
79-
'plugin_fields_containers_id' => $container_id,
80-
['ranking' => ['>', $old_order]],
81-
['ranking' => ['<=', $new_order]],
82-
],
83-
);
84-
} else {
85-
$DB->update(
86-
$table,
87-
[
88-
'ranking' => new QueryExpression($DB->quoteName('ranking') . ' + 1'),
89-
],
90-
[
91-
'plugin_fields_containers_id' => $container_id,
92-
['ranking' => ['<', $old_order]],
93-
['ranking' => ['>=', $new_order]],
94-
],
92+
['ranking' => $ranking],
93+
['id' => $id],
9594
);
95+
$ranking++;
9696
}
97-
98-
// Update current element
99-
$DB->update(
100-
$table,
101-
[
102-
'ranking' => $new_order,
103-
],
104-
[
105-
'id' => $field_id,
106-
],
107-
);

0 commit comments

Comments
 (0)