Bug #94549
closedFlexform section change order when deleting item
0%
Description
I've discoverd an odd behaviour with FlexForms in combination with sections. When a section contains at least 17 Items and (After a save) a item is removed and then saved then the order is changed of the items.
I tried to find the root of this behaviour and ended in the DataHandler
The asort
cause the isse but I don't know why. I made some independent tests with the data which gets passed to the method and noticed something.
$data = [
"60ed404104921816320239" => "",
"60ed524b3b735029561451" => "",
"60ed56d915a2d143366883" => "",
"60ed550b0146a452956314" => "",
"60ed523e70373667109521" => "",
"60ed5241903ef623057117" => "",
"60ed5243d6b64443066657" => "",
"60ed5246a244d957906702" => "",
"60ed5248d9115418847870" => "",
"60ed404526917612536689" => "",
"60ed52531e488403102629" => "",
"60ed525043157609282528" => "",
"60ed52551e75e407845160" => "",
"60ed525714df1794924549" => "",
"60ed52591c447113268801" => "",
"60ed525ad7160719857266" => "DELETE",
];
asort($data);
print_r($data);
//Output
Array
(
[60ed404104921816320239] =>
[60ed524b3b735029561451] =>
[60ed56d915a2d143366883] =>
[60ed550b0146a452956314] =>
[60ed523e70373667109521] =>
[60ed5241903ef623057117] =>
[60ed5243d6b64443066657] =>
[60ed5246a244d957906702] =>
[60ed5248d9115418847870] =>
[60ed404526917612536689] =>
[60ed52531e488403102629] =>
[60ed525043157609282528] =>
[60ed52551e75e407845160] =>
[60ed525714df1794924549] =>
[60ed52591c447113268801] =>
[60ed525ad7160719857266] => DELETE
)
The Order is correct, now lets try the same with one item more:
$data2 = [
"60ed404104921816320239" => "",
"60ed524b3b735029561451" => "",
"60ed56d915a2d143366883" => "",
"60ed550b0146a452956314" => "",
"60ed523e70373667109521" => "",
"60ed5241903ef623057117" => "",
"60ed5243d6b64443066657" => "",
"60ed5246a244d957906702" => "",
"60ed5248d9115418847870" => "",
"60ed404526917612536689" => "",
"60ed52531e488403102629" => "",
"60ed525043157609282528" => "",
"60ed52551e75e407845160" => "",
"60ed525714df1794924549" => "",
"60ed52591c447113268801" => "",
"60ed57dcde329615532849" => "",
"60ed57e02d30b476661246" => "DELETE",
];
asort($data2);
print_r($data2);
//Output
Array
(
[60ed404104921816320239] =>
[60ed404526917612536689] =>
[60ed57dcde329615532849] =>
[60ed52591c447113268801] =>
[60ed525714df1794924549] =>
[60ed52551e75e407845160] =>
[60ed525043157609282528] =>
[60ed52531e488403102629] =>
[60ed5248d9115418847870] =>
[60ed524b3b735029561451] =>
[60ed5246a244d957906702] =>
[60ed5243d6b64443066657] =>
[60ed5241903ef623057117] =>
[60ed523e70373667109521] =>
[60ed550b0146a452956314] =>
[60ed56d915a2d143366883] =>
[60ed57e02d30b476661246] => DELETE
)
You notice that many items are not in the correct order as the input.
Wo why did this happen? Is the asort
event required?
Updated by Jonas Eberle over 3 years ago
PHP asort() is has not been a stable sorting algorithm (Note: on https://www.php.net/manual/en/function.asort.php).
It is implemented in PHP 8.0+ https://github.com/php/php-src/pull/5236 (https://wiki.php.net/rfc/stable_sorting). I haven't found a polyfill but could be solved with uasort().
Updated by Paul Kamma over 3 years ago
Ok that's intresting.
I found this library
https://github.com/vanderlee/PHP-stable-sort-functions
The asort
with this works but I bet that someone have a better solution then using an external library.
Updated by Robert Wolle over 2 years ago
- Tags changed from flexform asort to flexform asort section order save
In general it has to be addressed for PHP 7.4 and the function asort needs to be replaced.
I added a mehtod asort in the DataHandler-Class:
public function asort(array &$array, $sort_flags = SORT_REGULAR){
$index = 0;
foreach ($array as &$item) {
$item = array($index++, $item);
}
$result = uasort($array, function($a, $b) use($sort_flags) {
if ($a[1] == $b[1]) {
return $a[0] - $b[0];
}
$set = array(-1 => $a[1], 1 => $b[1]);
asort($set, $sort_flags);
reset($set);
return key($set);
});
foreach ($array as &$item) {
$item = $item[1];
}
return $result;
}
and replaced
asort($actionCMDs[$key]);
with
$this->asort($actionCMDs[$key]);
in the method _ACTION_FLEX_FORMdata.
Updated by Christian Kuhn about 1 year ago
Hey.
I'm pretty confident we can close here:
- There was a rewrite of DataHandler->_ACTION_FLEX_FORMdata() with #99952 for v12, which may or may not have fixed the issue.
- More importantly: v12 requires PHP ^8.1. asort() has been made stable with PHP 8.0, it no longer mixes the order when the value is identical.
- We will no longer fix this issue in v11, since it's not 'critical' or security related. If you really need this in v11 projects, we'd recommend a DataHandler patch for the affected project.
Updated by Christian Kuhn about 1 year ago
- Related to Task #99952: Avoid GU::_GP() in DataHandler added
Updated by Christian Kuhn about 1 year ago
Note Jonas: Thanks for the 'stable' information. This helped a lot to understand what is going on.