diff --git a/Classes/Definition/ElementDefinition.php b/Classes/Definition/ElementDefinition.php index f90bb3fd..e28e73b3 100644 --- a/Classes/Definition/ElementDefinition.php +++ b/Classes/Definition/ElementDefinition.php @@ -56,7 +56,7 @@ public static function createFromArray(array $elementArray, string $table): Elem $elementDefinition->descriptions = $elementArray['descriptions'] ?? []; $elementDefinition->options = $elementArray['options'] ?? []; $elementDefinition->hidden = !empty($elementArray['hidden']); - $elementDefinition->sorting = $elementArray['sorting'] ?? 0; + $elementDefinition->sorting = (int)($elementArray['sorting'] ?? 0); return $elementDefinition; } diff --git a/Classes/Definition/ElementDefinitionCollection.php b/Classes/Definition/ElementDefinitionCollection.php index 312b8eb5..f0b91d62 100644 --- a/Classes/Definition/ElementDefinitionCollection.php +++ b/Classes/Definition/ElementDefinitionCollection.php @@ -85,12 +85,37 @@ public function count(): int return count($this->definitions); } - protected function sort($definitions): array + private function sort($definitions): array { - usort($definitions, static function ($a, $b) { - return $a->sorting <=> $b->sorting; - }); + if (PHP_VERSION_ID < 80000) { + $this->stable_usort($definitions, static function ($a, $b) { + return $a->sorting <=> $b->sorting; + }); + } else { + usort($definitions, static function ($a, $b) { + return $a->sorting <=> $b->sorting; + }); + } return $definitions; } + + /** + * Taken from https://wiki.php.net/rfc/stable_sorting + */ + private function stable_usort(array &$array, callable $compare): void + { + $arrayAndPos = []; + $pos = 0; + foreach ($array as $value) { + $arrayAndPos[] = [$value, $pos++]; + } + usort($arrayAndPos, static function($a, $b) use($compare) { + return $compare($a[0], $b[0]) ?: $a[1] <=> $b[1]; + }); + $array = []; + foreach ($arrayAndPos as $elem) { + $array[] = $elem[0]; + } + } } diff --git a/Tests/Unit/Definition/ElementDefinitionCollectionTest.php b/Tests/Unit/Definition/ElementDefinitionCollectionTest.php new file mode 100644 index 00000000..884d9bdb --- /dev/null +++ b/Tests/Unit/Definition/ElementDefinitionCollectionTest.php @@ -0,0 +1,211 @@ + [ + 'json' => [ + 'element1' => [ + 'key' => 'element1', + 'label' => 'Element1' + ], + 'element2' => [ + 'key' => 'element2', + 'label' => 'Element2' + ], + 'element3' => [ + 'key' => 'element3', + 'label' => 'Element3' + ], + ], + 'expected' => [ + [ + 'key' => 'element1', + 'label' => 'Element1', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + [ + 'key' => 'element2', + 'label' => 'Element2', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + [ + 'key' => 'element3', + 'label' => 'Element3', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + ] + ]; + + yield 'Sorting of elements is preserved with sorting set' => [ + 'json' => [ + 'element1' => [ + 'key' => 'element1', + 'label' => 'Element1', + 'sorting' => '0', + ], + 'element2' => [ + 'key' => 'element2', + 'label' => 'Element2', + 'sorting' => '0', + ], + 'element3' => [ + 'key' => 'element3', + 'label' => 'Element3', + 'sorting' => '0', + ], + ], + 'expected' => [ + [ + 'key' => 'element1', + 'label' => 'Element1', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + [ + 'key' => 'element2', + 'label' => 'Element2', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + [ + 'key' => 'element3', + 'label' => 'Element3', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + ] + ]; + + yield 'Sorting of elements is preserved with real sorting set' => [ + 'json' => [ + 'element1' => [ + 'key' => 'element1', + 'label' => 'Element1', + 'sorting' => '2', + ], + 'element2' => [ + 'key' => 'element2', + 'label' => 'Element2', + 'sorting' => '1', + ], + 'element3' => [ + 'key' => 'element3', + 'label' => 'Element3', + 'sorting' => '0', + ], + ], + 'expected' => [ + [ + 'key' => 'element3', + 'label' => 'Element3', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 0, + ], + [ + 'key' => 'element2', + 'label' => 'Element2', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 1, + ], + [ + 'key' => 'element1', + 'label' => 'Element1', + 'description' => '', + 'shortLabel' => '', + 'color' => '', + 'icon' => '', + 'columns' => [], + 'labels' => [], + 'descriptions' => [], + 'sorting' => 2, + ], + ] + ]; + } + + /** + * @dataProvider elementsAreSortedBySortingDataProvider + * @test + */ + public function elementsAreSortedBySorting(array $json, array $expected): void + { + $elements = []; + foreach (ElementDefinitionCollection::createFromArray($json, 'tt_content') as $element) { + $elements[] = $element->toArray(); + } + self::assertEquals($expected, $elements); + } +}