1313final class OpenAPI extends Validated
1414{
1515 /**
16+ * @param array<int, Server> $servers
1617 * Optional, may be left empty.
1718 * If empty or unspecified, the array will contain the default Server.
1819 * The default Server has "url" === "/" and no "variables"
19- * @var array<int, Server>
20- */
21- public readonly array $ servers ;
22-
23- /**
24- * REQUIRED
20+ *
21+ * @param array<string,PathItem> $paths
22+ * REQUIRED:
2523 * It may be empty due to ACL constraints
2624 * The PathItem's relative endpoint key mapped to the PathItem
27- * @var array<string,PathItem>
2825 */
29- public readonly array $ paths ;
26+ private function __construct (
27+ Identifier $ identifier ,
28+ public readonly array $ servers ,
29+ public readonly array $ paths
30+ ) {
31+ parent ::__construct ($ identifier );
3032
31- public function __construct (Partial \OpenAPI $ openAPI )
33+ $ this ->reviewServers ($ this ->servers );
34+ $ this ->reviewPaths ($ this ->paths );
35+ }
36+
37+ public function withoutServers (): OpenAPI
3238 {
33- if (!isset ($ openAPI ->title ) || !isset ($ openAPI ->version )) {
34- throw InvalidOpenAPI::missingInfo ();
35- }
39+ return new OpenAPI (
40+ $ this ->getIdentifier (),
41+ [new Server ($ this ->getIdentifier (), new Partial \Server ('/ ' ))],
42+ array_map (fn ($ p ) => $ p ->withoutServers (), $ this ->paths ),
43+ );
44+ }
3645
37- parent ::__construct (new Identifier ("$ openAPI ->title ( $ openAPI ->version ) " ));
46+ public static function fromPartial (Partial \OpenAPI $ openAPI ): self
47+ {
48+ $ identifier = new Identifier (sprintf (
49+ '%s(%s) ' ,
50+ $ openAPI ->title ?? throw InvalidOpenAPI::missingInfo (),
51+ $ openAPI ->version ?? throw InvalidOpenAPI::missingInfo (),
52+ ));
3853
39- if (!isset ($ openAPI ->openAPI )) {
40- throw InvalidOpenAPI::missingOpenAPIVersion ($ this ->getIdentifier ());
41- }
54+ $ openAPI ->openAPI ??
55+ throw InvalidOpenAPI::missingOpenAPIVersion ($ identifier );
4256
43- $ this ->servers = $ this ->validateServers (
44- $ this ->getIdentifier (),
45- $ openAPI ->servers
46- );
57+ $ servers = self ::validateServers ($ identifier , $ openAPI ->servers );
58+ $ paths = self ::validatePaths ($ identifier , $ servers , $ openAPI ->paths );
4759
48- $ this ->paths = $ this ->validatePaths (
49- $ this ->getIdentifier (),
50- $ openAPI ->paths ,
51- );
60+ return new OpenAPI ($ identifier , $ servers , $ paths );
5261 }
5362
5463 /**
5564 * @param Partial\Server[] $servers
5665 * @return array<int,Server>
5766 */
58- private function validateServers (
67+ private static function validateServers (
5968 Identifier $ identifier ,
6069 array $ servers
6170 ): array {
6271 if (empty ($ servers )) {
6372 return [new Server ($ identifier , new Partial \Server ('/ ' ))];
6473 }
6574
66- $ result = array_values (array_map (
75+ return array_values (array_map (
6776 fn ($ s ) => new Server ($ identifier , $ s ),
6877 $ servers
6978 ));
79+ }
7080
71- $ uniqueURLS = array_unique (array_map (fn ($ s ) => $ s ->url , $ result ));
72- if (count ($ result ) !== count ($ uniqueURLS )) {
81+ /**
82+ * @param Server[] $servers
83+ */
84+ private function reviewServers (array $ servers ): void
85+ {
86+ $ uniqueURLS = array_unique (array_map (fn ($ s ) => $ s ->url , $ servers ));
87+ if (count ($ servers ) !== count ($ uniqueURLS )) {
7388 $ this ->addWarning (
7489 'Server URLs are not unique ' ,
7590 Warning::IDENTICAL_SERVER_URLS
7691 );
7792 }
78-
79- return $ result ;
8093 }
8194
82- /**
95+ /**
96+ * @param Server[] $servers
8397 * @param null|Partial\PathItem[] $pathItems
8498 * @return array<string,PathItem>
8599 */
86- private function validatePaths (
100+ private static function validatePaths (
87101 Identifier $ identifier ,
102+ array $ servers ,
88103 ?array $ pathItems
89104 ): array {
90105 if (is_null ($ pathItems )) {
91106 throw InvalidOpenAPI::missingPaths ($ identifier );
92107 }
93108
94- if (empty ($ pathItems )) {
95- $ this ->addWarning ('No Paths in OpenAPI ' , Warning::EMPTY_PATHS );
96- }
97-
98109 $ result = [];
99110
100111 foreach ($ pathItems as $ pathItem ) {
@@ -115,27 +126,37 @@ private function validatePaths(
115126 );
116127 }
117128
118- $ result [$ pathItem ->path ] = new PathItem (
129+ $ result [$ pathItem ->path ] = PathItem:: fromPartial (
119130 $ identifier ->append ($ pathItem ->path ),
120- $ this -> servers ,
131+ $ servers ,
121132 $ pathItem
122133 );
123134 }
124135
125- $ this -> checkForEquivalentPathTemplates ($ result );
126- $ this -> checkForDuplicatedOperationIds ($ result );
136+ self :: checkForEquivalentPathTemplates ($ result );
137+ self :: checkForDuplicatedOperationIds ($ result );
127138
128139 return $ result ;
129140 }
130141
142+ /**
143+ * @param PathItem[] $paths
144+ */
145+ private function reviewPaths (array $ paths ): void
146+ {
147+ if (empty ($ paths )) {
148+ $ this ->addWarning ('No Paths in OpenAPI ' , Warning::EMPTY_PATHS );
149+ }
150+ }
151+
131152 /**
132153 * @param array<string,PathItem> $pathItems
133154 */
134- private function checkForEquivalentPathTemplates (array $ pathItems ): void
155+ private static function checkForEquivalentPathTemplates (array $ pathItems ): void
135156 {
136157 $ regexToIdentifier = [];
137158 foreach ($ pathItems as $ path => $ pathItem ) {
138- $ regex = $ this -> getPathRegex ($ path );
159+ $ regex = self :: getPathRegex ($ path );
139160
140161 if (isset ($ regexToIdentifier [$ regex ])) {
141162 throw InvalidOpenAPI::equivalentTemplates (
@@ -151,7 +172,7 @@ private function checkForEquivalentPathTemplates(array $pathItems): void
151172 /**
152173 * @param PathItem[] $paths
153174 */
154- private function checkForDuplicatedOperationIds (array $ paths ): void
175+ private static function checkForDuplicatedOperationIds (array $ paths ): void
155176 {
156177 $ checked = [];
157178
@@ -174,7 +195,7 @@ private function checkForDuplicatedOperationIds(array $paths): void
174195 }
175196 }
176197
177- private function getPathRegex (string $ path ): string
198+ private static function getPathRegex (string $ path ): string
178199 {
179200 $ pattern = preg_replace ('#{[^/]+}# ' , '{([^/]+)} ' , $ path );
180201
0 commit comments