@@ -131,14 +131,12 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
131
131
}
132
132
133
133
$ openapiOperation = $ operation ->getOpenapi ();
134
- $ hasOpenapi = null !== $ openapiOperation && !\is_bool ($ openapiOperation );
135
134
136
135
// Operation ignored from OpenApi
137
136
if ($ operation instanceof HttpOperation && false === $ openapiOperation ) {
138
137
continue ;
139
138
}
140
139
141
- $ uriVariables = $ operation ->getUriVariables ();
142
140
$ resourceClass = $ operation ->getClass () ?? $ resource ->getClass ();
143
141
$ routeName = $ operation ->getRouteName () ?? $ operation ->getName ();
144
142
@@ -159,17 +157,69 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
159
157
continue ;
160
158
}
161
159
160
+ if (!\is_object ($ openapiOperation )) {
161
+ $ openapiOperation = new Model \Operation ();
162
+ }
163
+
164
+ // Complete with defaults
165
+ $ openapiOperation = new Model \Operation (
166
+ operationId: null !== $ openapiOperation ->getOperationId () ? $ openapiOperation ->getOperationId () : $ this ->normalizeOperationName ($ operationName ),
167
+ tags: null !== $ openapiOperation ->getTags () ? $ openapiOperation ->getTags () : [$ operation ->getShortName () ?: $ resourceShortName ],
168
+ responses: null !== $ openapiOperation ->getResponses () ? $ openapiOperation ->getResponses () : [],
169
+ summary: null !== $ openapiOperation ->getSummary () ? $ openapiOperation ->getSummary () : $ this ->getPathDescription ($ resourceShortName , $ method , $ operation instanceof CollectionOperationInterface),
170
+ description: null !== $ openapiOperation ->getDescription () ? $ openapiOperation ->getDescription () : $ this ->getPathDescription ($ resourceShortName , $ method , $ operation instanceof CollectionOperationInterface),
171
+ externalDocs: $ openapiOperation ->getExternalDocs (),
172
+ parameters: null !== $ openapiOperation ->getParameters () ? $ openapiOperation ->getParameters () : [],
173
+ requestBody: $ openapiOperation ->getRequestBody (),
174
+ callbacks: $ openapiOperation ->getCallbacks (),
175
+ deprecated: null !== $ openapiOperation ->getDeprecated () ? $ openapiOperation ->getDeprecated () : (bool ) $ operation ->getDeprecationReason (),
176
+ security: null !== $ openapiOperation ->getSecurity () ? $ openapiOperation ->getSecurity () : null ,
177
+ servers: null !== $ openapiOperation ->getServers () ? $ openapiOperation ->getServers () : null ,
178
+ extensionProperties: $ openapiOperation ->getExtensionProperties (),
179
+ );
180
+
162
181
[$ requestMimeTypes , $ responseMimeTypes ] = $ this ->getMimeTypes ($ operation );
163
182
164
- $ operationId = $ hasOpenapi && $ openapiOperation ->getOperationId () ? $ openapiOperation ->getOperationId () : $ this ->normalizeOperationName ($ operationName );
165
183
// TODO Remove in 4.0
166
- if ($ operation ->getOpenapiContext ()['operationId ' ] ?? false ) {
184
+ foreach (['operationId ' , 'tags ' , 'summary ' , 'description ' , 'security ' , 'servers ' ] as $ key ) {
185
+ if (null !== ($ operation ->getOpenapiContext ()[$ key ] ?? null )) {
186
+ trigger_deprecation (
187
+ 'api-platform/core ' ,
188
+ '3.1 ' ,
189
+ 'The "openapiContext" option is deprecated, use "openapi" instead. '
190
+ );
191
+ $ openapiOperation = $ openapiOperation ->{'with ' .ucfirst ($ key )}($ operation ->getOpenapiContext ()[$ key ]);
192
+ }
193
+ }
194
+
195
+ // TODO Remove in 4.0
196
+ if (null !== ($ operation ->getOpenapiContext ()['externalDocs ' ] ?? null )) {
197
+ trigger_deprecation (
198
+ 'api-platform/core ' ,
199
+ '3.1 ' ,
200
+ 'The "openapiContext" option is deprecated, use "openapi" instead. '
201
+ );
202
+ $ openapiOperation = $ openapiOperation ->withExternalDocs (new ExternalDocumentation ($ operation ->getOpenapiContext ()['externalDocs ' ]['description ' ] ?? null , $ operation ->getOpenapiContext ()['externalDocs ' ]['url ' ]));
203
+ }
204
+
205
+ // TODO Remove in 4.0
206
+ if (null !== ($ operation ->getOpenapiContext ()['callbacks ' ] ?? null )) {
167
207
trigger_deprecation (
168
208
'api-platform/core ' ,
169
209
'3.1 ' ,
170
210
'The "openapiContext" option is deprecated, use "openapi" instead. '
171
211
);
172
- $ operationId = $ operation ->getOpenapiContext ()['operationId ' ];
212
+ $ openapiOperation = $ openapiOperation ->withCallbacks (new \ArrayObject ($ operation ->getOpenapiContext ()['callbacks ' ]));
213
+ }
214
+
215
+ // TODO Remove in 4.0
216
+ if (null !== ($ operation ->getOpenapiContext ()['deprecated ' ] ?? null )) {
217
+ trigger_deprecation (
218
+ 'api-platform/core ' ,
219
+ '3.1 ' ,
220
+ 'The "openapiContext" option is deprecated, use "openapi" instead. '
221
+ );
222
+ $ openapiOperation = $ openapiOperation ->withDeprecated ((bool ) $ operation ->getOpenapiContext ()['deprecated ' ]);
173
223
}
174
224
175
225
if ($ path ) {
@@ -190,9 +240,6 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
190
240
$ this ->appendSchemaDefinitions ($ schemas , $ operationOutputSchema ->getDefinitions ());
191
241
}
192
242
193
- $ parameters = $ hasOpenapi ? $ openapiOperation ->getParameters () : [];
194
- $ responses = [];
195
-
196
243
// TODO Remove in 4.0
197
244
if ($ operation ->getOpenapiContext ()['parameters ' ] ?? false ) {
198
245
trigger_deprecation (
@@ -204,29 +251,30 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
204
251
foreach ($ operation ->getOpenapiContext ()['parameters ' ] as $ parameter ) {
205
252
$ parameters [] = new Parameter ($ parameter ['name ' ], $ parameter ['in ' ], $ parameter ['description ' ] ?? '' , $ parameter ['required ' ] ?? false , $ parameter ['deprecated ' ] ?? false , $ parameter ['allowEmptyValue ' ] ?? false , $ parameter ['schema ' ] ?? [], $ parameter ['style ' ] ?? null , $ parameter ['explode ' ] ?? false , $ parameter ['allowReserved ' ] ?? false , $ parameter ['example ' ] ?? null , isset ($ parameter ['examples ' ]) ? new \ArrayObject ($ parameter ['examples ' ]) : null , isset ($ parameter ['content ' ]) ? new \ArrayObject ($ parameter ['content ' ]) : null );
206
253
}
254
+ $ openapiOperation = $ openapiOperation ->withParameters ($ parameters );
207
255
}
208
256
209
257
// Set up parameters
210
- foreach ($ uriVariables ?? [] as $ parameterName => $ uriVariable ) {
258
+ foreach ($ operation -> getUriVariables () ?? [] as $ parameterName => $ uriVariable ) {
211
259
if ($ uriVariable ->getExpandedValue () ?? false ) {
212
260
continue ;
213
261
}
214
262
215
263
$ parameter = new Parameter ($ parameterName , 'path ' , (new \ReflectionClass ($ uriVariable ->getFromClass ()))->getShortName ().' identifier ' , true , false , false , ['type ' => 'string ' ]);
216
- if ($ this ->hasParameter ($ parameter , $ parameters )) {
264
+ if ($ this ->hasParameter ($ openapiOperation , $ parameter )) {
217
265
continue ;
218
266
}
219
267
220
- $ parameters [] = $ parameter ;
268
+ $ openapiOperation = $ openapiOperation -> withParameter ( $ parameter) ;
221
269
}
222
270
223
271
if ($ operation instanceof CollectionOperationInterface && HttpOperation::METHOD_POST !== $ method ) {
224
272
foreach (array_merge ($ this ->getPaginationParameters ($ operation ), $ this ->getFiltersParameters ($ operation )) as $ parameter ) {
225
- if ($ this ->hasParameter ($ parameter , $ parameters )) {
273
+ if ($ this ->hasParameter ($ openapiOperation , $ parameter )) {
226
274
continue ;
227
275
}
228
276
229
- $ parameters [] = $ parameter ;
277
+ $ openapiOperation = $ openapiOperation -> withParameter ( $ parameter) ;
230
278
}
231
279
}
232
280
@@ -235,66 +283,59 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
235
283
case HttpOperation::METHOD_GET :
236
284
$ successStatus = (string ) $ operation ->getStatus () ?: 200 ;
237
285
$ responseContent = $ this ->buildContent ($ responseMimeTypes , $ operationOutputSchemas );
238
- $ responses [ $ successStatus ] = new Response (sprintf ('%s %s ' , $ resourceShortName , $ operation instanceof CollectionOperationInterface ? 'collection ' : 'resource ' ), $ responseContent );
286
+ $ openapiOperation = $ openapiOperation -> withResponse ( $ successStatus , new Response (sprintf ('%s %s ' , $ resourceShortName , $ operation instanceof CollectionOperationInterface ? 'collection ' : 'resource ' ), $ responseContent) );
239
287
break ;
240
288
case HttpOperation::METHOD_POST :
241
289
$ responseLinks = $ this ->getLinks ($ resourceMetadataCollection , $ operation );
242
290
$ responseContent = $ this ->buildContent ($ responseMimeTypes , $ operationOutputSchemas );
243
291
$ successStatus = (string ) $ operation ->getStatus () ?: 201 ;
244
- $ responses [ $ successStatus ] = new Response (sprintf ('%s resource created ' , $ resourceShortName ), $ responseContent , null , $ responseLinks );
245
- $ responses [ ' 400 ' ] = new Response ('Invalid input ' );
246
- $ responses [ ' 422 ' ] = new Response ('Unprocessable entity ' );
292
+ $ openapiOperation = $ openapiOperation -> withResponse ( $ successStatus , new Response (sprintf ('%s resource created ' , $ resourceShortName ), $ responseContent , null , $ responseLinks) );
293
+ $ openapiOperation = $ openapiOperation -> withResponse ( 400 , new Response ('Invalid input ' ) );
294
+ $ openapiOperation = $ openapiOperation -> withResponse ( 422 , new Response ('Unprocessable entity ' ) );
247
295
break ;
248
296
case HttpOperation::METHOD_PATCH :
249
297
case HttpOperation::METHOD_PUT :
250
298
$ responseLinks = $ this ->getLinks ($ resourceMetadataCollection , $ operation );
251
299
$ successStatus = (string ) $ operation ->getStatus () ?: 200 ;
252
300
$ responseContent = $ this ->buildContent ($ responseMimeTypes , $ operationOutputSchemas );
253
- $ responses [ $ successStatus ] = new Response (sprintf ('%s resource updated ' , $ resourceShortName ), $ responseContent , null , $ responseLinks );
254
- $ responses [ ' 400 ' ] = new Response ('Invalid input ' );
255
- $ responses [ ' 422 ' ] = new Response ('Unprocessable entity ' );
301
+ $ openapiOperation = $ openapiOperation -> withResponse ( $ successStatus , new Response (sprintf ('%s resource updated ' , $ resourceShortName ), $ responseContent , null , $ responseLinks) );
302
+ $ openapiOperation = $ openapiOperation -> withResponse ( 400 , new Response ('Invalid input ' ) );
303
+ $ openapiOperation = $ openapiOperation -> withResponse ( 422 , new Response ('Unprocessable entity ' ) );
256
304
break ;
257
305
case HttpOperation::METHOD_DELETE :
258
306
$ successStatus = (string ) $ operation ->getStatus () ?: 204 ;
259
- $ responses [ $ successStatus ] = new Response (sprintf ('%s resource deleted ' , $ resourceShortName ));
307
+ $ openapiOperation = $ openapiOperation -> withResponse ( $ successStatus , new Response (sprintf ('%s resource deleted ' , $ resourceShortName) ));
260
308
break ;
261
309
}
262
310
263
311
if (!$ operation instanceof CollectionOperationInterface && HttpOperation::METHOD_POST !== $ operation ->getMethod ()) {
264
- $ responses [ ' 404 ' ] = new Response ('Resource not found ' );
312
+ $ openapiOperation = $ openapiOperation -> withResponse ( 404 , new Response ('Resource not found ' ) );
265
313
}
266
314
267
- if (!$ responses ) {
268
- $ responses [ 'default ' ] = new Response ('Unexpected error ' );
315
+ if (!$ openapiOperation -> getResponses () ) {
316
+ $ openapiOperation = $ openapiOperation -> withResponse ( 'default ' , new Response ('Unexpected error ' ) );
269
317
}
270
318
271
- if ($ hasOpenapi && ($ contextResponses = $ openapiOperation ->getResponses () ?: false )) {
272
- foreach ($ contextResponses as $ statusCode => $ contextResponse ) {
273
- $ responses [$ statusCode ] = $ contextResponse ;
274
- }
275
- } elseif ($ contextResponses = $ operation ->getOpenapiContext ()['responses ' ] ?? false ) {
319
+ if ($ contextResponses = $ operation ->getOpenapiContext ()['responses ' ] ?? false ) {
276
320
// TODO Remove this "elseif" in 4.0
277
321
trigger_deprecation (
278
322
'api-platform/core ' ,
279
323
'3.1 ' ,
280
324
'The "openapiContext" option is deprecated, use "openapi" instead. '
281
325
);
282
326
foreach ($ contextResponses as $ statusCode => $ contextResponse ) {
283
- $ responses [ $ statusCode ] = new Response ($ contextResponse ['description ' ] ?? '' , isset ($ contextResponse ['content ' ]) ? new \ArrayObject ($ contextResponse ['content ' ]) : null , isset ($ contextResponse ['headers ' ]) ? new \ArrayObject ($ contextResponse ['headers ' ]) : null , isset ($ contextResponse ['links ' ]) ? new \ArrayObject ($ contextResponse ['links ' ]) : null );
327
+ $ openapiOperation = $ openapiOperation -> withResponse ( $ statusCode , new Response ($ contextResponse ['description ' ] ?? '' , isset ($ contextResponse ['content ' ]) ? new \ArrayObject ($ contextResponse ['content ' ]) : null , isset ($ contextResponse ['headers ' ]) ? new \ArrayObject ($ contextResponse ['headers ' ]) : null , isset ($ contextResponse ['links ' ]) ? new \ArrayObject ($ contextResponse ['links ' ]) : null ) );
284
328
}
285
329
}
286
330
287
- $ requestBody = null ;
288
- if ($ hasOpenapi && ($ contextRequestBody = $ openapiOperation ->getRequestBody () ?: false )) {
289
- $ requestBody = $ contextRequestBody ;
290
- } elseif ($ contextRequestBody = $ operation ->getOpenapiContext ()['requestBody ' ] ?? false ) {
331
+ if ($ contextRequestBody = $ operation ->getOpenapiContext ()['requestBody ' ] ?? false ) {
291
332
// TODO Remove this "elseif" in 4.0
292
333
trigger_deprecation (
293
334
'api-platform/core ' ,
294
335
'3.1 ' ,
295
336
'The "openapiContext" option is deprecated, use "openapi" instead. '
296
337
);
297
- $ requestBody = new RequestBody ($ contextRequestBody ['description ' ] ?? '' , new \ArrayObject ($ contextRequestBody ['content ' ]), $ contextRequestBody ['required ' ] ?? false );
338
+ $ openapiOperation = $ openapiOperation -> withRequestBody ( new RequestBody ($ contextRequestBody ['description ' ] ?? '' , new \ArrayObject ($ contextRequestBody ['content ' ]), $ contextRequestBody ['required ' ] ?? false ) );
298
339
} elseif (\in_array ($ method , [HttpOperation::METHOD_PATCH , HttpOperation::METHOD_PUT , HttpOperation::METHOD_POST ], true )) {
299
340
$ operationInputSchemas = [];
300
341
foreach ($ requestMimeTypes as $ operationFormat ) {
@@ -303,16 +344,9 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
303
344
$ this ->appendSchemaDefinitions ($ schemas , $ operationInputSchema ->getDefinitions ());
304
345
}
305
346
306
- $ requestBody = new RequestBody (sprintf ('The %s %s resource ' , HttpOperation::METHOD_POST === $ method ? 'new ' : 'updated ' , $ resourceShortName ), $ this ->buildContent ($ requestMimeTypes , $ operationInputSchemas ), true );
347
+ $ openapiOperation = $ openapiOperation -> withRequestBody ( new RequestBody (sprintf ('The %s %s resource ' , HttpOperation::METHOD_POST === $ method ? 'new ' : 'updated ' , $ resourceShortName ), $ this ->buildContent ($ requestMimeTypes , $ operationInputSchemas ), true ) );
307
348
}
308
349
309
- $ openapiOperation = ($ hasOpenapi ? $ openapiOperation : new Model \Operation ())
310
- // Defaults
311
- ->withTags ($ hasOpenapi && $ openapiOperation ->getTags () ? $ openapiOperation ->getTags () : [$ operation ->getShortName () ?: $ resourceShortName ])
312
- ->withSummary ($ hasOpenapi && $ openapiOperation ->getSummary () ? $ openapiOperation ->getSummary () : $ this ->getPathDescription ($ resourceShortName , $ method , $ operation instanceof CollectionOperationInterface))
313
- ->withDescription ($ hasOpenapi && $ openapiOperation ->getDescription () ? $ openapiOperation ->getDescription () : $ this ->getPathDescription ($ resourceShortName , $ method , $ operation instanceof CollectionOperationInterface))
314
- ->withDeprecated ($ hasOpenapi && $ openapiOperation ->getDeprecated () ? $ openapiOperation ->getDeprecated () : (bool ) $ operation ->getDeprecationReason ());
315
-
316
350
// TODO Remove in 4.0
317
351
if (null !== $ operation ->getOpenapiContext () && \count ($ operation ->getOpenapiContext ())) {
318
352
trigger_deprecation (
@@ -338,14 +372,7 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
338
372
}
339
373
}
340
374
341
- $ pathItem = $ pathItem ->{'with ' .ucfirst ($ method )}($ openapiOperation
342
- ->withOperationId ($ operationId )
343
- ->withResponses ($ responses )
344
- ->withParameters ($ parameters )
345
- ->withRequestBody ($ requestBody )
346
- );
347
-
348
- $ paths ->addPath ($ path , $ pathItem );
375
+ $ paths ->addPath ($ path , $ pathItem ->{'with ' .ucfirst ($ method )}($ openapiOperation ));
349
376
}
350
377
}
351
378
@@ -620,12 +647,9 @@ private function appendSchemaDefinitions(\ArrayObject $schemas, \ArrayObject $de
620
647
}
621
648
}
622
649
623
- /**
624
- * @param Model\Parameter[] $parameters
625
- */
626
- private function hasParameter (Parameter $ parameter , array $ parameters ): bool
650
+ private function hasParameter (Model \Operation $ operation , Parameter $ parameter ): bool
627
651
{
628
- foreach ($ parameters as $ existingParameter ) {
652
+ foreach ($ operation -> getParameters () as $ existingParameter ) {
629
653
if ($ existingParameter ->getName () === $ parameter ->getName () && $ existingParameter ->getIn () === $ parameter ->getIn ()) {
630
654
return true ;
631
655
}
0 commit comments