Completed
Branch master (e1d486)
by Pieter
02:44
created

OpenApiSpecGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
c 0
b 0
f 0
nc 1
nop 9
dl 0
loc 20
rs 9.9666

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace W2w\Lib\Apie\OpenApiSchema;
4
5
use erasys\OpenApi\Spec\v3 as OASv3;
6
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
7
use W2w\Lib\Apie\Core\ApiResourceMetadataFactory;
8
use W2w\Lib\Apie\Core\ClassResourceConverter;
9
use W2w\Lib\Apie\Core\IdentifierExtractor;
10
use W2w\Lib\Apie\Core\PluginContainer;
11
use W2w\Lib\Apie\Core\Resources\ApiResourcesInterface;
12
use W2w\Lib\Apie\Interfaces\SearchFilterProviderInterface;
13
use W2w\Lib\Apie\OpenApiSchema\SubActions\SubAction;
14
use W2w\Lib\Apie\OpenApiSchema\SubActions\SubActionContainer;
15
16
/**
17
 * Class that generated an OpenAPI spec from a list of API resources.
18
 */
19
class OpenApiSpecGenerator
20
{
21
    private $apiResources;
22
23
    private $converter;
24
25
    private $info;
26
27
    private $schemaGenerator;
28
29
    private $apiResourceMetadataFactory;
30
31
    private $identifierExtractor;
32
33
    private $baseUrl;
34
35
    private $subActionContainer;
36
37
    private $addSpecsHook;
38
39
    public function __construct(
40
        ApiResourcesInterface $apiResources,
41
        ClassResourceConverter $converter,
42
        OASv3\Info $info,
43
        SchemaGenerator $schemaGenerator,
44
        ApiResourceMetadataFactory $apiResourceMetadataFactory,
45
        IdentifierExtractor $identifierExtractor,
46
        string $baseUrl,
47
        SubActionContainer $subActionContainer,
48
        ?callable $addSpecsHook = null
49
    ) {
50
        $this->apiResources = $apiResources;
51
        $this->converter = $converter;
52
        $this->info = $info;
53
        $this->schemaGenerator = $schemaGenerator;
54
        $this->apiResourceMetadataFactory = $apiResourceMetadataFactory;
55
        $this->identifierExtractor = $identifierExtractor;
56
        $this->baseUrl = $baseUrl;
57
        $this->subActionContainer = $subActionContainer;
58
        $this->addSpecsHook = $addSpecsHook;
59
    }
60
61
    private function getIdentifierKey(string $className): ?string
62
    {
63
        $context = $this->apiResourceMetadataFactory->getMetadata($className)->getContext();
64
        return $this->identifierExtractor->getIdentifierKeyOfClass($className, $context);
65
    }
66
67
    /**
68
     * Gets an OpenAPI spec document.
69
     *
70
     * @return OASv3\Document
71
     */
72
    public function getOpenApiSpec(): OASv3\Document
73
    {
74
        $paths = [];
75
        foreach ($this->apiResources->getApiResources() as $apiResourceClass) {
76
            $path = $this->converter->normalize($apiResourceClass);
77
            $identifierName = $this->getIdentifierKey($apiResourceClass);
78
            $paths['/' . $path] = $this->convertAllToPathItem($apiResourceClass, $path);
79
            if ($identifierName) {
80
                $paths['/' . $path . '/{' . $identifierName . '}'] = $this->convertToPathItem($apiResourceClass, $path, $identifierName);
81
                foreach ($this->subActionContainer->getSubActionsForResourceClass($apiResourceClass) as $key => $subAction) {
82
                    $paths['/' . $path . '/{' . $identifierName . '}/' . $key] = $this->convertSubActionToPathItem($subAction, $path, $identifierName);
83
                }
84
            }
85
        }
86
87
        $stringSchema = new OASv3\Schema(['type' => 'string']);
88
        $stringOrIntSchema = new OASv3\Schema(['oneOf' => [$stringSchema, new OASv3\Schema(['type' => 'integer'])]]);
89
        $stringArraySchema = new OASv3\Schema(['type' => 'array', 'items' => $stringSchema]);
90
91
        $errorSchema = new OASv3\Reference('#/components/schemas/Error');
92
93
        $validationErrorSchema = new OASv3\Schema([
94
            'type'       => 'object',
95
            'properties' => [
96
                'type'    => $stringSchema,
97
                'message' => $stringSchema,
98
                'code'    => $stringOrIntSchema,
99
                'trace'   => $stringSchema,
100
                'errors'  => new OASv3\Schema([
101
                    'type'       => 'object',
102
                    'additionalProperties' => $stringArraySchema
103
                ]),
104
            ],
105
            'xml' => new OASv3\Xml(['name' => 'response']),
106
        ]);
107
108
        $doc = new OASv3\Document(
109
            $this->info,
110
            $paths,
111
            '3.0.1',
112
            [
113
                'servers' => [
114
                    new OASv3\Server($this->baseUrl),
115
                ],
116
                'components' => new OASv3\Components([
117
                    'schemas' => [
118
                        'Error' => new OASv3\Schema([
119
                            'type'       => 'object',
120
                            'properties' => [
121
                                'type'    => $stringSchema,
122
                                'message' => $stringSchema,
123
                                'code'    => $stringOrIntSchema,
124
                                'trace'   => $stringSchema,
125
                            ],
126
                            'xml' => new OASv3\Xml(['name' => 'response']),
127
                        ]),
128
                    ],
129
                    'headers' => [
130
                        'x-ratelimit-limit' => new Oasv3\Header(
131
                            'Request limit per hour',
132
                            [
133
                                'example' => 100,
134
                                'schema'  => new OASv3\Schema([
135
                                    'type' => 'integer',
136
                                ]),
137
                            ]
138
                        ),
139
                        'x-ratelimit-remaining' => new Oasv3\Header(
140
                            'Request limit per hour',
141
                            [
142
                                'example' => 94,
143
                                'schema'  => new OASv3\Schema([
144
                                    'type' => 'integer',
145
                                ]),
146
                            ]
147
                        ),
148
                    ],
149
                    'responses' => [
150
                        'InvalidFormat' => new OASv3\Response(
151
                            'The body input could not be parsed',
152
                            [
153
                                'application/json' => new OASv3\MediaType(
154
                                    [
155
                                        'schema' => $errorSchema,
156
                                    ]
157
                                ),
158
                                'application/xml' => new OASv3\MediaType(
159
                                    [
160
                                        'schema' => $errorSchema,
161
                                    ]
162
                                ),
163
                            ]
164
                        ),
165
                        'ValidationError' => new OASv3\Response(
166
                            'The body input was in a proper format, but the input values were not valid',
167
                            [
168
                                'application/json' => new OASv3\MediaType(
169
                                    [
170
                                        'schema' => $validationErrorSchema,
171
                                    ]
172
                                ),
173
                                'application/xml' => new OASv3\MediaType(
174
                                    [
175
                                        'schema' => $validationErrorSchema,
176
                                    ]
177
                                ),
178
                            ]
179
                        ),
180
                        'TooManyRequests' => new OASv3\Response(
181
                            'Too many requests per seconds were sent',
182
                            [
183
                                'application/json' => new OASv3\MediaType(
184
                                    [
185
                                        'schema' => $errorSchema,
186
                                    ]
187
                                ),
188
                                'application/xml' => new OASv3\MediaType(
189
                                    [
190
                                        'schema' => $errorSchema,
191
                                    ]
192
                                ),
193
                            ]
194
                        ),
195
                        'MaintenanceMode' => new OASv3\Response(
196
                            'App is in maintenance mode',
197
                            [
198
                                'application/json' => new OASv3\MediaType(
199
                                    [
200
                                        'schema' => $errorSchema,
201
                                    ]
202
                                ),
203
                                'application/xml' => new OASv3\MediaType(
204
                                    [
205
                                        'schema' => $errorSchema,
206
                                    ]
207
                                ),
208
                            ]
209
                        ),
210
                        'NotFound' => new OASv3\Response(
211
                            'Response when resource could not be found',
212
                            [
213
                                'application/json' => new OASv3\MediaType(
214
                                    [
215
                                        'schema' => $errorSchema,
216
                                    ]
217
                                ),
218
                                'application/xml' => new OASv3\MediaType(
219
                                    [
220
                                        'schema' => $errorSchema,
221
                                    ]
222
                                ),
223
                            ]
224
                        ),
225
                        'NotAuthorized' => new OASv3\Response(
226
                            'You have no permission to do this call',
227
                            [
228
                                'application/json' => new OASv3\MediaType(
229
                                    [
230
                                        'schema' => $errorSchema,
231
                                    ]
232
                                ),
233
                                'application/xml' => new OASv3\MediaType(
234
                                    [
235
                                        'schema' => $errorSchema,
236
                                    ]
237
                                ),
238
                            ]
239
                        ),
240
                        'InternalError' => new OASv3\Response(
241
                            'An internal error occured',
242
                            [
243
                                'application/json' => new OASv3\MediaType(
244
                                    [
245
                                        'schema' => $errorSchema,
246
                                    ]
247
                                ),
248
                                'application/xml' => new OASv3\MediaType(
249
                                    [
250
                                        'schema' => $errorSchema,
251
                                    ]
252
                                ),
253
                            ]
254
                        ),
255
                        'ServerDependencyError' => new OASv3\Response(
256
                            'The server required an external response which threw an error',
257
                            [
258
                                'application/json' => new OASv3\MediaType(
259
                                    [
260
                                        'schema' => $errorSchema,
261
                                    ]
262
                                ),
263
                                'application/xml' => new OASv3\MediaType(
264
                                    [
265
                                        'schema' => $errorSchema,
266
                                    ]
267
                                ),
268
                            ]
269
                        ),
270
                    ],
271
                ]),
272
            ]
273
        );
274
        if (is_callable($this->addSpecsHook)) {
275
            $res = call_user_func($this->addSpecsHook, $doc);
276
            if ($res instanceof OASv3\Document) {
277
                return $res;
278
            }
279
        }
280
281
        return $doc;
282
    }
283
284
    /**
285
     * Returns the default HTTP headers we generated for every REST api call.
286
     *
287
     * @return array
288
     */
289
    private function getDefaultHeaders(): array
290
    {
291
        return [
292
            'x-ratelimit-limit'     => new OASv3\Reference('#/components/headers/x-ratelimit-limit'),
293
            'x-ratelimit-remaining' => new OASv3\Reference('#/components/headers/x-ratelimit-remaining'),
294
        ];
295
    }
296
297
    private function convertSubActionToRequestBody(SubAction $subAction): ?OASv3\RequestBody
298
    {
299
        $properties = [];
300
        foreach ($subAction->getArguments() as $fieldName => $type) {
301
            //TODO typehint string etc.
302
            if ($type === null || !$type->getClassName()) {
303
                $properties[$fieldName] = new OASv3\Schema([
304
                    'type' => 'object',
305
                    'additionalProperties' => true,
306
                ]);
307
                continue;
308
            }
309
            $properties[$fieldName] = $this->schemaGenerator->createSchema($type->getClassName(), 'post', ['write', 'post']);
310
        }
311
        $jsonSchema = new OASv3\Schema([
312
            'type' => 'object',
313
            'properties' => $properties,
314
        ]);
315
        $xmlSchema = unserialize(serialize($jsonSchema));
316
        $xmlSchema->xml = new OASv3\Xml(['name' => 'item']);
317
318
        return new OASv3\RequestBody(
319
            [
320
                'application/json' => new OASv3\MediaType(
321
                    [
322
                        'schema' => $jsonSchema,
323
                    ]
324
                ),
325
                'application/xml' => new OASv3\MediaType(
326
                    [
327
                        'schema' => $xmlSchema,
328
                    ]
329
                ),
330
            ],
331
            'the resource as JSON to persist',
332
            true
333
        );
334
    }
335
336
    /**
337
     * Returns the content OpenAPI spec for a resource class and a certain operation.
338
     *
339
     * @param string $apiResourceClass
340
     * @param string $operation
341
     * @return OASv3\MediaType[]
342
     */
343
    private function convertToContent(string $apiResourceClass, string $operation): array
344
    {
345
        $readWrite = $this->determineReadWrite($operation);
346
        $jsonSchema = $this->schemaGenerator->createSchema($apiResourceClass, $operation, [$operation, $readWrite]);
347
        $xmlSchema = unserialize(serialize($jsonSchema));
348
        $xmlSchema->xml = new OASv3\Xml(['name' => 'item']);
349
350
        return [
351
            'application/json' => new OASv3\MediaType(
352
                [
353
                    'schema' => $jsonSchema,
354
                ]
355
            ),
356
            'application/xml' => new OASv3\MediaType(
357
                [
358
                    'schema' => $xmlSchema,
359
                ]
360
            ),
361
        ];
362
    }
363
364
    /**
365
     * Returns the content OpenAPI spec for a resource class when it returns an array of resources.
366
     *
367
     * @param string $apiResourceClass
368
     * @param string $operation
369
     * @return OASv3\MediaType[]
370
     */
371
    private function convertToContentArray(string $apiResourceClass, string $operation): array
372
    {
373
        $readWrite = $this->determineReadWrite($operation);
374
        $jsonSchema = $this->schemaGenerator->createSchema($apiResourceClass, $operation, [$operation, $readWrite]);
375
        $xmlSchema = $this->schemaGenerator->createSchema($apiResourceClass, $operation, [$operation, $readWrite]);
376
        $xmlSchema->xml = new OASv3\Xml(['name' => 'item']);
377
378
        return [
379
            'application/json' => new OASv3\MediaType(
380
                [
381
                    'schema' => new OASv3\Schema([
382
                        'type'  => 'array',
383
                        'items' => $jsonSchema,
384
                    ]),
385
                ]
386
            ),
387
            'application/xml' => new OASv3\MediaType(
388
                [
389
                    'schema' => new OASv3\Schema([
390
                        'type'  => 'array',
391
                        'items' => $xmlSchema,
392
                        'xml'   => new OASv3\Xml(['name' => 'response']),
393
                    ]),
394
                ]
395
            ),
396
        ];
397
    }
398
399
    /**
400
     * Determine if the operation is a read or a write.
401
     *
402
     * @param string $operation
403
     * @return string
404
     */
405
    private function determineReadWrite(string $operation): string
406
    {
407
        if ($operation === 'post' || $operation === 'put') {
408
            return 'write';
409
        }
410
411
        return 'read';
412
    }
413
414
    /**
415
     * Sluggify resource name for the operation id.
416
     *
417
     * @param string $resourceName
418
     * @return string|string[]|\Symfony\Component\Serializer\NameConverter\string|null
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Serializer\NameConverter\string was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
419
     */
420
    private function sluggify(string $resourceName)
421
    {
422
        return (new CamelCaseToSnakeCaseNameConverter(null, false))->denormalize($resourceName);
423
    }
424
425
    /**
426
     * Returns all paths of an api resource without an id in the url.
427
     *
428
     * @param string $apiResourceClass
429
     * @param string $resourceName
430
     * @return OASv3\PathItem
431
     */
432
    private function convertAllToPathItem(string $apiResourceClass, string $resourceName): OASv3\PathItem
433
    {
434
        $paths = [];
435
436
        if ($this->allowed($apiResourceClass, 'all')) {
437
            $paths['get'] = new OASv3\Operation(
438
                [
439
                    '200' => new OASv3\Response(
440
                        'Retrieves all instances of ' . $resourceName,
441
                        $this->convertToContentArray($apiResourceClass, 'get'),
442
                        $this->getDefaultHeaders()
443
                    ),
444
                    '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
445
                    '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
446
                    '500' => new OASv3\Reference('#/components/responses/InternalError'),
447
                    '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
448
                    '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
449
                ],
450
                'resourceGetAll' . $this->sluggify($resourceName),
451
                'get/search all instances of ' . $resourceName,
452
                [
453
                    'tags'       => [$resourceName],
454
                    'parameters' => [
455
                        new OASv3\Parameter('page', 'query', 'pagination index counting from 0', ['schema' => new OASv3\Schema(['type' => 'integer', 'minimum' => 0])]),
456
                        new OASv3\Parameter('limit', 'query', 'number of results', ['schema' => new OASv3\Schema(['type' => 'integer', 'minimum' => 1])]),
457
                    ],
458
                ]
459
            );
460
            $metadata = $this->apiResourceMetadataFactory->getMetadata($apiResourceClass);
461
            $retriever = $metadata->hasResourceRetriever() ? $metadata->getResourceRetriever() : null;
462
            if ($retriever instanceof SearchFilterProviderInterface) {
463
                foreach ($retriever->getSearchFilter($metadata)->getAllPrimitiveSearchFilter() as $name => $filter) {
464
                    $schema = $filter->getSchemaForFilter();
465
                    $paths['get']->parameters[] = new OASv3\Parameter(
466
                        $name,
467
                        'query',
468
                        'search filter ' . $name,
469
                        ['schema' => $schema]
470
                    );
471
                }
472
            }
473
        }
474
475
        if ($this->allowed($apiResourceClass, 'post')) {
476
            $paths['post'] = new OASv3\Operation(
477
                [
478
                    '200' => new OASv3\Response(
479
                        'Creates a new instance of ' . $resourceName,
480
                        $this->convertToContent($apiResourceClass, 'get'),
481
                        $this->getDefaultHeaders()
482
                    ),
483
                    '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
484
                    '415' => new OASv3\Reference('#/components/responses/InvalidFormat'),
485
                    '422' => new OASv3\Reference('#/components/responses/ValidationError'),
486
                    '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
487
                    '500' => new OASv3\Reference('#/components/responses/InternalError'),
488
                    '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
489
                    '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
490
                ],
491
                'resourcePostSingle' . $this->sluggify($resourceName),
492
                'create a new single instance of ' . $resourceName,
493
                [
494
                    'tags'        => [$resourceName],
495
                    'requestBody' => new OASv3\RequestBody(
496
                        $this->convertToContent($apiResourceClass, 'post'),
497
                        'the resource as JSON to persist',
498
                        true
499
                    ),
500
                ]
501
            );
502
        }
503
504
        return new OASv3\PathItem($paths);
505
    }
506
507
    /**
508
     * Creates PathItem for sub actions.
509
     *
510
     * @param SubAction $subAction
511
     * @param string $resourceName
512
     * @param string $identifierName
513
     * @return OASv3\PathItem
514
     */
515
    private function convertSubActionToPathItem(SubAction $subAction, string $resourceName, string $identifierName): OASv3\PathItem
516
    {
517
        $paths = [
518
            'parameters' => [
519
                new OASv3\Parameter($identifierName, 'path', 'the id of the resource', ['required' => true, 'schema' => new OASv3\Schema(['type' => 'string'])]),
520
            ],
521
        ];
522
        $paths['post'] = new OASv3\Operation(
523
            [
524
                '200' => new OASv3\Response(
525
                    'Retrieves return value of ' . $subAction->getName(),
526
                    $subAction->getReturnTypehint()->getClassName() ? $this->convertToContent($subAction->getReturnTypehint()->getClassName(), 'get') : null,
527
                    $this->getDefaultHeaders()
528
                ),
529
                '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
530
                '404' => new OASv3\Reference('#/components/responses/NotFound'),
531
                '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
532
                '500' => new OASv3\Reference('#/components/responses/InternalError'),
533
                '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
534
                '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
535
            ],
536
            'resourcePostSubAction' . $this->sluggify($resourceName . '_' . $subAction->getName()),
537
            null,
538
            [
539
                'tags' => [$resourceName],
540
                'requestBody' => $this->convertSubActionToRequestBody($subAction),
541
            ]
542
        );
543
        return new OASv3\PathItem($paths);
544
    }
545
546
    /**
547
     * Returns all paths of an api resource with an id in the url.
548
     * @param string $apiResourceClass
549
     * @param string $resourceName
550
     * @return OASv3\PathItem
551
     */
552
    private function convertToPathItem(string $apiResourceClass, string $resourceName, string $identifierName): OASv3\PathItem
553
    {
554
        $paths = [
555
            'parameters' => [
556
                new OASv3\Parameter($identifierName, 'path', 'the id of the resource', ['required' => true, 'schema' => new OASv3\Schema(['type' => 'string'])]),
557
            ],
558
        ];
559
        if ($this->allowed($apiResourceClass, 'get')) {
560
            $paths['get'] = new OASv3\Operation(
561
                [
562
                    '200' => new OASv3\Response(
563
                        'Retrieves a single instance of ' . $resourceName,
564
                        $this->convertToContent($apiResourceClass, 'get'),
565
                        $this->getDefaultHeaders()
566
                    ),
567
                    '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
568
                    '404' => new OASv3\Reference('#/components/responses/NotFound'),
569
                    '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
570
                    '500' => new OASv3\Reference('#/components/responses/InternalError'),
571
                    '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
572
                    '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
573
                ],
574
                'resourceGetSingle' . $this->sluggify($resourceName),
575
                'retrieve a single instance of ' . $resourceName,
576
                [
577
                    'tags' => [$resourceName],
578
                ]
579
            );
580
        }
581
        if ($this->allowed($apiResourceClass, 'delete')) {
582
            $paths['delete'] = new OASv3\Operation(
583
                [
584
                    '204' => new OASv3\Response(
585
                        'Deletes a single instance of ' . $resourceName,
586
                        null,
587
                        $this->getDefaultHeaders()
588
                    ),
589
                    '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
590
                    '404' => new OASv3\Reference('#/components/responses/NotFound'),
591
                    '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
592
                    '500' => new OASv3\Reference('#/components/responses/InternalError'),
593
                    '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
594
                    '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
595
                ],
596
                'resourceDeleteSingle' . $this->sluggify($resourceName),
597
                'delete a single instance of ' . $resourceName,
598
                [
599
                    'tags' => [$resourceName],
600
                ]
601
            );
602
        }
603
        if ($this->allowed($apiResourceClass, 'put')) {
604
            $paths['put'] = new OASv3\Operation(
605
                [
606
                    '200' => new OASv3\Response(
607
                        'Retrieves and update a single instance of ' . $resourceName,
608
                        $this->convertToContent($apiResourceClass, 'get'),
609
                        $this->getDefaultHeaders()
610
                    ),
611
                    '401' => new OASv3\Reference('#/components/responses/NotAuthorized'),
612
                    '404' => new OASv3\Reference('#/components/responses/NotFound'),
613
                    '415' => new OASv3\Reference('#/components/responses/InvalidFormat'),
614
                    '422' => new OASv3\Reference('#/components/responses/ValidationError'),
615
                    '429' => new OASv3\Reference('#/components/responses/TooManyRequests'),
616
                    '500' => new OASv3\Reference('#/components/responses/InternalError'),
617
                    '502' => new OASv3\Reference('#/components/responses/ServerDependencyError'),
618
                    '503' => new OASv3\Reference('#/components/responses/MaintenanceMode'),
619
                ],
620
                'resourcePutSingle' . $this->sluggify($resourceName),
621
                'modify a single instance of ' . $resourceName,
622
                [
623
                    'tags'        => [$resourceName],
624
                    'requestBody' => new OASv3\RequestBody(
625
                        $this->convertToContent($apiResourceClass, 'put'),
626
                        'the resource as JSON to persist',
627
                        true
628
                    ),
629
                ]
630
            );
631
        }
632
633
        return new OASv3\PathItem($paths);
634
    }
635
636
    /**
637
     * Returns if a specific REST API call is an allowed method.
638
     *
639
     * @param string $apiResourceClass
640
     * @param string $operation
641
     * @return bool
642
     */
643
    private function allowed(string $apiResourceClass, string $operation): bool
644
    {
645
        $metadata = $this->apiResourceMetadataFactory->getMetadata($apiResourceClass);
646
        switch ($operation) {
647
            case 'all':
648
                return $metadata->allowGetAll();
649
            case 'get':
650
                return $metadata->allowGet();
651
            case 'post':
652
                return $metadata->allowPost();
653
            case 'put':
654
                return $metadata->allowPut();
655
            case 'delete':
656
                return $metadata->allowDelete();
657
        }
658
        // @codeCoverageIgnoreStart
659
        return false;
660
        // @codeCoverageIgnoreEnd
661
    }
662
}
663