Skip to content

Commit 130fb5a

Browse files
authored
feat: better path sorting for openapi UIs (#6583)
* feat: better path sorting for openapi UIs * fix: cs fixer * fix: move the paths sorting logic to the normalizer * fix: cs fixer * fix: refactoring for readability * fix: missing the tags for patch
1 parent 9aadc2c commit 130fb5a

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

src/OpenApi/Model/Paths.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ final class Paths
2020
public function addPath(string $path, PathItem $pathItem): void
2121
{
2222
$this->paths[$path] = $pathItem;
23-
24-
ksort($this->paths);
2523
}
2624

2725
public function getPath(string $path): ?PathItem

src/OpenApi/Serializer/OpenApiNormalizer.php

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function __construct(private readonly NormalizerInterface $decorated)
3939
*/
4040
public function normalize(mixed $object, ?string $format = null, array $context = []): array
4141
{
42-
$pathsCallback = static fn ($decoratedObject): array => $decoratedObject instanceof Paths ? $decoratedObject->getPaths() : [];
42+
$pathsCallback = $this->getPathsCallBack();
4343
$context[AbstractObjectNormalizer::PRESERVE_EMPTY_OBJECTS] = true;
4444
$context[AbstractObjectNormalizer::SKIP_NULL_VALUES] = true;
4545
$context[AbstractNormalizer::CALLBACKS] = [
@@ -95,4 +95,46 @@ public function hasCacheableSupportsMethod(): bool
9595

9696
return true;
9797
}
98+
99+
private function getPathsCallBack(): \Closure
100+
{
101+
return static function ($decoratedObject): array {
102+
if ($decoratedObject instanceof Paths) {
103+
$paths = $decoratedObject->getPaths();
104+
105+
// sort paths by tags, then by path for each tag
106+
uksort($paths, function ($keyA, $keyB) use ($paths) {
107+
$a = $paths[$keyA];
108+
$b = $paths[$keyB];
109+
110+
$tagsA = [
111+
...($a->getGet()?->getTags() ?? []),
112+
...($a->getPost()?->getTags() ?? []),
113+
...($a->getPatch()?->getTags() ?? []),
114+
...($a->getPut()?->getTags() ?? []),
115+
...($a->getDelete()?->getTags() ?? []),
116+
];
117+
sort($tagsA);
118+
119+
$tagsB = [
120+
...($b->getGet()?->getTags() ?? []),
121+
...($b->getPost()?->getTags() ?? []),
122+
...($b->getPatch()?->getTags() ?? []),
123+
...($b->getPut()?->getTags() ?? []),
124+
...($b->getDelete()?->getTags() ?? []),
125+
];
126+
sort($tagsB);
127+
128+
return match (true) {
129+
current($tagsA) === current($tagsB) => $keyA <=> $keyB,
130+
default => current($tagsA) <=> current($tagsB),
131+
};
132+
});
133+
134+
return $paths;
135+
}
136+
137+
return [];
138+
};
139+
}
98140
}

0 commit comments

Comments
 (0)