• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 10315659289

09 Aug 2024 07:49AM UTC coverage: 7.841% (-0.006%) from 7.847%
10315659289

push

github

soyuka
style: cs fixes

70 of 529 new or added lines in 176 files covered. (13.23%)

160 existing lines in 58 files now uncovered.

12688 of 161818 relevant lines covered (7.84%)

26.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Metadata/Tests/Extractor/ResourceMetadataCompatibilityTest.php
1
<?php
2

3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <dunglas@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace ApiPlatform\Metadata\Tests\Extractor;
15

16
use ApiPlatform\Metadata\ApiResource;
17
use ApiPlatform\Metadata\Delete;
18
use ApiPlatform\Metadata\Extractor\XmlResourceExtractor;
19
use ApiPlatform\Metadata\Extractor\YamlResourceExtractor;
20
use ApiPlatform\Metadata\Get;
21
use ApiPlatform\Metadata\GetCollection;
22
use ApiPlatform\Metadata\GraphQl\DeleteMutation;
23
use ApiPlatform\Metadata\GraphQl\Mutation;
24
use ApiPlatform\Metadata\GraphQl\Query;
25
use ApiPlatform\Metadata\GraphQl\QueryCollection;
26
use ApiPlatform\Metadata\GraphQl\Subscription;
27
use ApiPlatform\Metadata\HttpOperation;
28
use ApiPlatform\Metadata\Operations;
29
use ApiPlatform\Metadata\Patch;
30
use ApiPlatform\Metadata\Post;
31
use ApiPlatform\Metadata\Put;
32
use ApiPlatform\Metadata\QueryParameter;
33
use ApiPlatform\Metadata\Resource\Factory\ExtractorResourceMetadataCollectionFactory;
34
use ApiPlatform\Metadata\Resource\Factory\OperationDefaultsTrait;
35
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
36
use ApiPlatform\Metadata\Tests\Extractor\Adapter\ResourceAdapterInterface;
37
use ApiPlatform\Metadata\Tests\Extractor\Adapter\XmlResourceAdapter;
38
use ApiPlatform\Metadata\Tests\Extractor\Adapter\YamlResourceAdapter;
39
use ApiPlatform\Metadata\Tests\Fixtures\ApiResource\Comment;
40
use ApiPlatform\Metadata\Util\CamelCaseToSnakeCaseNameConverter;
41
use ApiPlatform\OpenApi\Model\ExternalDocumentation;
42
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
43
use ApiPlatform\OpenApi\Model\RequestBody;
44
use PHPUnit\Framework\AssertionFailedError;
45
use PHPUnit\Framework\TestCase;
46
use Symfony\Component\WebLink\Link;
47

48
/**
49
 * Ensures XML and YAML mappings are fully compatible with ApiResource.
50
 *
51
 * @author Vincent Chalamon <vincentchalamon@gmail.com>
52
 */
53
final class ResourceMetadataCompatibilityTest extends TestCase
54
{
55
    use OperationDefaultsTrait;
56
    private const RESOURCE_CLASS = Comment::class;
57
    private const SHORT_NAME = 'Comment';
58
    private const DEFAULTS = [
59
        'route_prefix' => '/v1',
60
    ];
61
    private const FIXTURES = [
62
        null,
63
        [
64
            'uriTemplate' => '/users/{userId}/comments',
65
            'shortName' => self::SHORT_NAME,
66
            'description' => 'A list of Comments from User',
67
            'routePrefix' => '/api',
68
            'stateless' => true,
69
            'sunset' => '2021-01-01',
70
            'acceptPatch' => 'application/merge-patch+json',
71
            'status' => 200,
72
            'host' => 'example.com',
73
            'condition' => 'request.headers.get(\'User-Agent\') matches \{/firefox/i\'',
74
            'controller' => 'App\Controller\CommentController',
75
            'urlGenerationStrategy' => 1,
76
            'deprecationReason' => 'This resource is deprecated',
77
            'elasticsearch' => true,
78
            'messenger' => true,
79
            'input' => 'App\Dto\CommentInput',
80
            'output' => 'App\Dto\CommentOutut',
81
            'fetchPartial' => true,
82
            'forceEager' => true,
83
            'paginationClientEnabled' => true,
84
            'paginationClientItemsPerPage' => true,
85
            'paginationClientPartial' => true,
86
            'paginationEnabled' => true,
87
            'paginationFetchJoinCollection' => true,
88
            'paginationUseOutputWalkers' => true,
89
            'paginationItemsPerPage' => 42,
90
            'paginationMaximumItemsPerPage' => 200,
91
            'paginationPartial' => true,
92
            'paginationType' => 'page',
93
            'security' => 'is_granted(\'ROLE_USER\')',
94
            'securityMessage' => 'Sorry, you can\'t access this resource.',
95
            'securityPostDenormalize' => 'is_granted(\'ROLE_ADMIN\')',
96
            'securityPostDenormalizeMessage' => 'Sorry, you must an admin to access this resource.',
97
            'securityPostValidation' => 'is_granted(\'ROLE_OWNER\')',
98
            'securityPostValidationMessage' => 'Sorry, you must the owner of this resource to access it.',
99
            'queryParameterValidationEnabled' => true,
100
            'types' => ['someirischema', 'anotheririschema'],
101
            'formats' => [
102
                'json' => null,
103
                'jsonld' => null,
104
                'xls' => 'application/vnd.ms-excel',
105
            ],
106
            'inputFormats' => [
107
                'json' => 'application/merge-patch+json',
108
            ],
109
            'outputFormats' => [
110
                'json' => 'application/merge-patch+json',
111
            ],
112
            'uriVariables' => [
113
                'userId' => [
114
                    'fromClass' => Comment::class,
115
                    'fromProperty' => 'author',
116
                    'compositeIdentifier' => true,
117
                ],
118
            ],
119
            'defaults' => [
120
                'prout' => 'pouet',
121
            ],
122
            'requirements' => [
123
                'id' => '\d+',
124
            ],
125
            'options' => [
126
                'foo' => 'bar',
127
            ],
128
            'schemes' => ['http', 'https'],
129
            'cacheHeaders' => [
130
                'max_age' => 60,
131
                'shared_max_age' => 120,
132
                'vary' => ['Authorization', 'Accept-Language'],
133
            ],
134
            'normalizationContext' => [
135
                'groups' => 'comment:read',
136
            ],
137
            'denormalizationContext' => [
138
                'groups' => ['comment:write', 'comment:custom'],
139
            ],
140
            'collectDenormalizationErrors' => true,
141
            'hydraContext' => [
142
                'foo' => ['bar' => 'baz'],
143
            ],
144
            'openapi' => [
145
                'extensionProperties' => [
146
                    'bar' => 'baz',
147
                ],
148
            ],
149
            'validationContext' => [
150
                'foo' => 'bar',
151
            ],
152
            'filters' => ['comment.custom_filter'],
153
            'order' => ['foo', 'bar'],
154
            'paginationViaCursor' => [
155
                'id' => 'DESC',
156
            ],
157
            'exceptionToStatus' => [
158
                'Symfony\Component\Serializer\Exception\ExceptionInterface' => 400,
159
            ],
160
            'extraProperties' => [
161
                'custom_property' => 'Lorem ipsum dolor sit amet',
162
                'another_custom_property' => [
163
                    'Lorem ipsum' => 'Dolor sit amet',
164
                ],
165
            ],
166
            'mercure' => true,
167
            'stateOptions' => [
168
                'elasticsearchOptions' => [
169
                    'index' => 'foo_index',
170
                    'type' => 'foo_type',
171
                ],
172
            ],
173
            'graphQlOperations' => [
174
                [
175
                    'args' => [
176
                        'foo' => [
177
                            'type' => 'custom',
178
                            'bar' => 'baz',
179
                        ],
180
                    ],
181
                    'extraArgs' => [
182
                        'bar' => [
183
                            'type' => 'custom',
184
                            'baz' => 'qux',
185
                        ],
186
                    ],
187
                    'queryParameterValidationEnabled' => true,
188
                    'shortName' => self::SHORT_NAME,
189
                    'description' => 'Creates a Comment.',
190
                    'class' => Mutation::class,
191
                    'name' => 'create',
192
                    'urlGenerationStrategy' => 0,
193
                    'deprecationReason' => 'I don\'t know',
194
                    'normalizationContext' => [
195
                        'groups' => 'comment:read_collection',
196
                    ],
197
                    'denormalizationContext' => [
198
                        'groups' => ['comment:write'],
199
                    ],
200
                    'validationContext' => [
201
                        'foo' => 'bar',
202
                    ],
203
                    'filters' => ['comment.another_custom_filter'],
204
                    'elasticsearch' => false,
205
                    'mercure' => [
206
                        'private' => true,
207
                    ],
208
                    'messenger' => 'input',
209
                    'input' => 'App\Dto\CreateCommentInput',
210
                    'output' => 'App\Dto\CommentCollectionOutut',
211
                    'order' => ['userId'],
212
                    'fetchPartial' => false,
213
                    'forceEager' => false,
214
                    'paginationClientEnabled' => false,
215
                    'paginationClientItemsPerPage' => false,
216
                    'paginationClientPartial' => false,
217
                    'paginationEnabled' => false,
218
                    'paginationFetchJoinCollection' => false,
219
                    'paginationUseOutputWalkers' => false,
220
                    'paginationItemsPerPage' => 54,
221
                    'paginationMaximumItemsPerPage' => 200,
222
                    'paginationPartial' => false,
223
                    'paginationType' => 'page',
224
                    'security' => 'is_granted(\'IS_AUTHENTICATED_ANONYMOUSLY\')',
225
                    'securityMessage' => 'Sorry, you can\'t access this collection.',
226
                    'securityPostDenormalize' => 'is_granted(\'ROLE_CUSTOM_ADMIN\')',
227
                    'securityPostDenormalizeMessage' => 'Sorry, you must an admin to access this collection.',
228
                    'read' => true,
229
                    'deserialize' => false,
230
                    'validate' => false,
231
                    'write' => false,
232
                    'serialize' => true,
233
                    'priority' => 200,
234
                    'extraProperties' => [
235
                        'custom_property' => 'Lorem ipsum dolor sit amet',
236
                        'another_custom_property' => [
237
                            'Lorem ipsum' => 'Dolor sit amet',
238
                        ],
239
                        'foo' => 'bar',
240
                        'route_prefix' => '/v1', // from defaults
241
                    ],
242
                    'stateOptions' => [
243
                        'elasticsearchOptions' => [
244
                            'index' => 'foo_index',
245
                            'type' => 'foo_type',
246
                        ],
247
                    ],
248
                ],
249
                [
250
                    'class' => Query::class,
251
                    'queryParameterValidationEnabled' => true,
252
                    'extraProperties' => [
253
                        'route_prefix' => '/v1',
254
                        'custom_property' => 'Lorem ipsum dolor sit amet',
255
                        'another_custom_property' => [
256
                            'Lorem ipsum' => 'Dolor sit amet',
257
                        ],
258
                    ],
259
                    'stateOptions' => [
260
                        'elasticsearchOptions' => [
261
                            'index' => 'foo_index',
262
                            'type' => 'foo_type',
263
                        ],
264
                    ],
265
                ],
266
                [
267
                    'class' => QueryCollection::class,
268
                    'queryParameterValidationEnabled' => true,
269
                    'extraProperties' => [
270
                        'route_prefix' => '/v1',
271
                        'custom_property' => 'Lorem ipsum dolor sit amet',
272
                        'another_custom_property' => [
273
                            'Lorem ipsum' => 'Dolor sit amet',
274
                        ],
275
                    ],
276
                    'stateOptions' => [
277
                        'elasticsearchOptions' => [
278
                            'index' => 'foo_index',
279
                            'type' => 'foo_type',
280
                        ],
281
                    ],
282
                ],
283
                [
284
                    'class' => Subscription::class,
285
                    'queryParameterValidationEnabled' => true,
286
                    'extraProperties' => [
287
                        'route_prefix' => '/v1',
288
                        'custom_property' => 'Lorem ipsum dolor sit amet',
289
                        'another_custom_property' => [
290
                            'Lorem ipsum' => 'Dolor sit amet',
291
                        ],
292
                    ],
293
                    'stateOptions' => [
294
                        'elasticsearchOptions' => [
295
                            'index' => 'foo_index',
296
                            'type' => 'foo_type',
297
                        ],
298
                    ],
299
                ],
300
            ],
301
            'operations' => [
302
                [
303
                    'name' => 'custom_operation_name',
304
                    'method' => 'GET',
305
                    'uriTemplate' => '/users/{userId}/comments{._format}',
306
                    'shortName' => self::SHORT_NAME,
307
                    'description' => 'A list of Comments',
308
                    'types' => ['Comment'],
309
                    'formats' => [
310
                        'json' => null,
311
                        'jsonld' => null,
312
                        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
313
                    ],
314
                    'inputFormats' => [
315
                        'jsonld' => 'application/merge-patch+json+ld',
316
                    ],
317
                    'outputFormats' => [
318
                        'jsonld' => 'application/merge-patch+json+ld',
319
                    ],
320
                    'uriVariables' => [
321
                        'userId' => [
322
                            'fromClass' => Comment::class,
323
                            'fromProperty' => 'author',
324
                            'compositeIdentifier' => true,
325
                        ],
326
                    ],
327
                    'routePrefix' => '/foo/api',
328
                    'defaults' => [
329
                        '_bar' => '_foo',
330
                    ],
331
                    'requirements' => [
332
                        'userId' => '\d+',
333
                    ],
334
                    'options' => [
335
                        'bar' => 'baz',
336
                    ],
337
                    'stateless' => false,
338
                    'sunset' => '2021-12-01',
339
                    'acceptPatch' => 'text/example;charset=utf-8',
340
                    'status' => 204,
341
                    'host' => 'api-platform.com',
342
                    'schemes' => ['https'],
343
                    'headers' => ['key' => 'value'],
344
                    'condition' => 'request.headers.has(\'Accept\')',
345
                    'controller' => 'App\Controller\CustomController',
346
                    'class' => GetCollection::class,
347
                    'urlGenerationStrategy' => 0,
348
                    'deprecationReason' => 'I don\'t know',
349
                    'cacheHeaders' => [
350
                        'max_age' => 60,
351
                        'shared_max_age' => 120,
352
                        'vary' => ['Authorization', 'Accept-Language', 'Accept'],
353
                    ],
354
                    'normalizationContext' => [
355
                        'groups' => 'comment:read_collection',
356
                    ],
357
                    'denormalizationContext' => [
358
                        'groups' => ['comment:write'],
359
                    ],
360
                    'hydraContext' => [
361
                        'foo' => ['bar' => 'baz'],
362
                    ],
363
                    'openapi' => [
364
                        'extensionProperties' => [
365
                            'bar' => 'baz',
366
                        ],
367
                    ],
368
                    'validationContext' => [
369
                        'foo' => 'bar',
370
                    ],
371
                    'filters' => ['comment.another_custom_filter'],
372
                    'elasticsearch' => false,
373
                    'mercure' => [
374
                        'private' => true,
375
                    ],
376
                    'messenger' => 'input',
377
                    'input' => 'App\Dto\CreateCommentInput',
378
                    'output' => 'App\Dto\CommentCollectionOutut',
379
                    'order' => ['userId'],
380
                    'fetchPartial' => false,
381
                    'forceEager' => false,
382
                    'paginationClientEnabled' => false,
383
                    'paginationClientItemsPerPage' => false,
384
                    'paginationClientPartial' => false,
385
                    'paginationViaCursor' => [
386
                        'userId' => 'DESC',
387
                    ],
388
                    'paginationEnabled' => false,
389
                    'paginationFetchJoinCollection' => false,
390
                    'paginationUseOutputWalkers' => false,
391
                    'paginationItemsPerPage' => 54,
392
                    'paginationMaximumItemsPerPage' => 200,
393
                    'paginationPartial' => false,
394
                    'paginationType' => 'page',
395
                    'security' => 'is_granted(\'IS_AUTHENTICATED_ANONYMOUSLY\')',
396
                    'securityMessage' => 'Sorry, you can\'t access this collection.',
397
                    'securityPostDenormalize' => 'is_granted(\'ROLE_CUSTOM_ADMIN\')',
398
                    'securityPostDenormalizeMessage' => 'Sorry, you must an admin to access this collection.',
399
                    'exceptionToStatus' => [
400
                        'Symfony\Component\Serializer\Exception\ExceptionInterface' => 404,
401
                    ],
402
                    'queryParameterValidationEnabled' => false,
403
                    'read' => true,
404
                    'deserialize' => false,
405
                    'validate' => false,
406
                    'write' => false,
407
                    'serialize' => true,
408
                    'priority' => 200,
409
                    'extraProperties' => [
410
                        'custom_property' => 'Lorem ipsum dolor sit amet',
411
                        'another_custom_property' => [
412
                            'Lorem ipsum' => 'Dolor sit amet',
413
                        ],
414
                        'foo' => 'bar',
415
                    ],
416
                    'links' => [
417
                        ['rel' => 'http://www.w3.org/ns/json-ld#error', 'href' => 'http://www.w3.org/ns/hydra/error'],
418
                    ],
419
                    'parameters' => [
420
                        'author' => ['key' => 'author', 'required' => true, 'schema' => ['type' => 'string']],
421
                    ],
422
                ],
423
                [
424
                    'uriTemplate' => '/users/{userId}/comments/{commentId}{._format}',
425
                    'class' => Get::class,
426
                    'uriVariables' => [
427
                        'userId' => [
428
                            'fromClass' => Comment::class,
429
                            'fromProperty' => 'author',
430
                            'compositeIdentifier' => true,
431
                        ],
432
                        'commentId' => [Comment::class, 'id'],
433
                    ],
434
                    'links' => [
435
                        ['rel' => 'http://www.w3.org/ns/json-ld#error', 'href' => 'http://www.w3.org/ns/hydra/error'],
436
                    ],
437
                ],
438
            ],
439
        ],
440
    ];
441
    private const BASE = [
442
        'shortName',
443
        'description',
444
        'urlGenerationStrategy',
445
        'deprecationReason',
446
        'elasticsearch',
447
        'messenger',
448
        'mercure',
449
        'input',
450
        'output',
451
        'fetchPartial',
452
        'forceEager',
453
        'paginationClientEnabled',
454
        'paginationClientItemsPerPage',
455
        'paginationClientPartial',
456
        'paginationEnabled',
457
        'paginationFetchJoinCollection',
458
        'paginationUseOutputWalkers',
459
        'paginationItemsPerPage',
460
        'paginationMaximumItemsPerPage',
461
        'paginationPartial',
462
        'paginationType',
463
        'processor',
464
        'provider',
465
        'security',
466
        'securityMessage',
467
        'securityPostDenormalize',
468
        'securityPostDenormalizeMessage',
469
        'securityPostValidation',
470
        'securityPostValidationMessage',
471
        'normalizationContext',
472
        'denormalizationContext',
473
        'collectDenormalizationErrors',
474
        'validationContext',
475
        'filters',
476
        'order',
477
        'extraProperties',
478
    ];
479
    private const EXTENDED_BASE = [
480
        'uriTemplate',
481
        'routePrefix',
482
        'stateless',
483
        'sunset',
484
        'acceptPatch',
485
        'status',
486
        'host',
487
        'condition',
488
        'controller',
489
        'queryParameterValidationEnabled',
490
        'exceptionToStatus',
491
        'types',
492
        'formats',
493
        'inputFormats',
494
        'outputFormats',
495
        'uriVariables',
496
        'defaults',
497
        'requirements',
498
        'options',
499
        'schemes',
500
        'cacheHeaders',
501
        'hydraContext',
502
        'openapi',
503
        'paginationViaCursor',
504
        'stateOptions',
505
        'links',
506
        'rules',
507
        'headers',
508
        'parameters',
509
    ];
510

511
    #[\PHPUnit\Framework\Attributes\DataProvider('getExtractors')]
512
    public function testValidMetadata(string $extractorClass, ResourceAdapterInterface $adapter): void
513
    {
514
        $reflClass = new \ReflectionClass(ApiResource::class);
×
515
        $parameters = $reflClass->getConstructor()->getParameters();
×
516
        $this->defaults = self::DEFAULTS;
×
517
        $this->camelCaseToSnakeCaseNameConverter = new CamelCaseToSnakeCaseNameConverter();
×
518

519
        try {
520
            $extractor = new $extractorClass($adapter(self::RESOURCE_CLASS, $parameters, self::FIXTURES));
×
521
            $factory = new ExtractorResourceMetadataCollectionFactory($extractor, null, self::DEFAULTS, null, true);
×
522
            $collection = $factory->create(self::RESOURCE_CLASS);
×
523
        } catch (\Exception $exception) {
×
524
            throw new AssertionFailedError('Failed asserting that the schema is valid according to '.ApiResource::class, 0, $exception);
×
525
        }
526

527
        $resources = $this->buildApiResources();
×
528
        $this->assertEquals(new ResourceMetadataCollection(self::RESOURCE_CLASS, $resources), $collection);
×
529
    }
530

531
    public static function getExtractors(): array
532
    {
533
        return [
×
534
            [XmlResourceExtractor::class, new XmlResourceAdapter()],
×
535
            [YamlResourceExtractor::class, new YamlResourceAdapter()],
×
536
        ];
×
537
    }
538

539
    /**
540
     * @return ApiResource[]
541
     */
542
    private function buildApiResources(): array
543
    {
544
        $resources = [];
×
545

546
        foreach (self::FIXTURES as $fixtures) {
×
547
            $resource = (new ApiResource())->withClass(self::RESOURCE_CLASS)->withShortName(self::SHORT_NAME);
×
548

549
            if (null === $fixtures) {
×
550
                // Build default operations
551
                $operations = [];
×
552
                foreach ([new Get(), new GetCollection(), new Post(), new Put(), new Patch(), new Delete()] as $operation) {
×
553
                    [$name, $operation] = $this->getOperationWithDefaults($resource, $operation);
×
554
                    $operations[$name] = $operation;
×
555
                }
556

557
                $resource = $resource->withOperations(new Operations($operations));
×
558

559
                // Build default GraphQL operations
560
                $graphQlOperations = [];
×
561
                foreach ([new QueryCollection(), new Query(), (new Mutation())->withName('update'), (new DeleteMutation())->withName('delete'), (new Mutation())->withName('create')] as $graphQlOperation) {
×
562
                    $description = $graphQlOperation instanceof Mutation ? ucfirst("{$graphQlOperation->getName()}s a {$resource->getShortName()}.") : null;
×
563
                    [$name, $operation] = $this->getOperationWithDefaults($resource, $graphQlOperation);
×
564
                    $graphQlOperations[$name] = $operation->withDescription($description);
×
565
                }
566

567
                $resources[] = $resource->withGraphQlOperations($graphQlOperations);
×
568

569
                continue;
×
570
            }
571

572
            foreach ($fixtures as $parameter => $value) {
×
573
                if (method_exists($this, 'with'.ucfirst($parameter))) {
×
574
                    $value = $this->{'with'.ucfirst($parameter)}($value, $fixtures);
×
575
                }
576

577
                if (method_exists($resource, 'with'.ucfirst($parameter))) {
×
578
                    $resource = $resource->{'with'.ucfirst($parameter)}($value, $fixtures);
×
579
                    continue;
×
580
                }
581

NEW
582
                throw new \RuntimeException(\sprintf('Unknown ApiResource parameter "%s".', $parameter));
×
583
            }
584

585
            $resources[] = $resource;
×
586
        }
587

588
        return $resources;
×
589
    }
590

591
    private function withOpenapi(array|bool $values): bool|OpenApiOperation
592
    {
593
        if (\is_bool($values)) {
×
594
            return $values;
×
595
        }
596

597
        $allowedProperties = array_map(fn (\ReflectionProperty $reflProperty): string => $reflProperty->getName(), (new \ReflectionClass(OpenApiOperation::class))->getProperties());
×
598
        foreach ($values as $key => $value) {
×
599
            $values[$key] = match ($key) {
×
600
                'externalDocs' => new ExternalDocumentation(description: $value['description'] ?? '', url: $value['url'] ?? ''),
×
601
                'requestBody' => new RequestBody(description: $value['description'] ?? '', content: isset($value['content']) ? new \ArrayObject($value['content']) : null, required: $value['required'] ?? false),
×
602
                'callbacks' => new \ArrayObject($value),
×
603
                default => $value,
×
604
            };
×
605

606
            if (\in_array($key, $allowedProperties, true)) {
×
607
                continue;
×
608
            }
609

610
            $values['extensionProperties'][$key] = $value;
×
611
            unset($values[$key]);
×
612
        }
613

614
        return new OpenApiOperation(...$values);
×
615
    }
616

617
    private function withUriVariables(array $values): array
618
    {
619
        $uriVariables = [];
×
620
        foreach ($values as $parameterName => $value) {
×
621
            if (\is_string($value)) {
×
622
                $uriVariables[$value] = $value;
×
623
                continue;
×
624
            }
625

626
            if (isset($value['fromClass']) || isset($value[0])) {
×
627
                $uriVariables[$parameterName]['from_class'] = $value['fromClass'] ?? $value[0];
×
628
            }
629
            if (isset($value['fromProperty']) || isset($value[1])) {
×
630
                $uriVariables[$parameterName]['from_property'] = $value['fromProperty'] ?? $value[1];
×
631
            }
632
            if (isset($value['toClass'])) {
×
633
                $uriVariables[$parameterName]['to_class'] = $value['toClass'];
×
634
            }
635
            if (isset($value['toProperty'])) {
×
636
                $uriVariables[$parameterName]['to_property'] = $value['toProperty'];
×
637
            }
638
            if (isset($value['identifiers'])) {
×
639
                $uriVariables[$parameterName]['identifiers'] = $value['identifiers'];
×
640
            }
641
            if (isset($value['compositeIdentifier'])) {
×
642
                $uriVariables[$parameterName]['composite_identifier'] = $value['compositeIdentifier'];
×
643
            }
644
        }
645

646
        return $uriVariables;
×
647
    }
648

649
    private function withOperations(array $values, ?array $fixtures): Operations
650
    {
651
        $operations = [];
×
652
        foreach ($values as $value) {
×
653
            $class = $value['class'] ?? HttpOperation::class;
×
654
            unset($value['class']);
×
655
            $operation = (new $class())->withClass(self::RESOURCE_CLASS);
×
656

657
            foreach (array_merge(self::BASE, self::EXTENDED_BASE) as $parameter) {
×
658
                if ((!\array_key_exists($parameter, $value) || null === $value[$parameter]) && isset($fixtures[$parameter])) {
×
659
                    $value[$parameter] = $fixtures[$parameter];
×
660
                }
661
            }
662

663
            foreach ($value as $parameter => $parameterValue) {
×
664
                if (method_exists($this, 'with'.ucfirst($parameter))) {
×
665
                    $parameterValue = $this->{'with'.ucfirst($parameter)}($parameterValue);
×
666
                }
667

668
                if (method_exists($operation, 'with'.ucfirst($parameter))) {
×
669
                    $operation = $operation->{'with'.ucfirst($parameter)}($parameterValue);
×
670
                    continue;
×
671
                }
672

NEW
673
                throw new \RuntimeException(\sprintf('Unknown Operation parameter "%s".', $parameter));
×
674
            }
675

676
            $operationName = $operation->getName() ?? $this->getDefaultOperationName($operation, self::RESOURCE_CLASS);
×
677
            $operations[$operationName] = $operation;
×
678
        }
679

680
        return new Operations($operations);
×
681
    }
682

683
    private function withGraphQlOperations(array $values, ?array $fixtures): array
684
    {
685
        $operations = [];
×
686
        foreach ($values as $value) {
×
687
            $class = $value['class'];
×
688
            unset($value['class']);
×
689
            $operation = (new $class())->withClass(self::RESOURCE_CLASS);
×
690

691
            foreach (self::BASE as $parameter) {
×
692
                if ((!\array_key_exists($parameter, $value) || null === $value[$parameter]) && isset($fixtures[$parameter])) {
×
693
                    $value[$parameter] = $fixtures[$parameter];
×
694
                }
695
            }
696

697
            foreach ($value as $parameter => $parameterValue) {
×
698
                if (method_exists($this, 'with'.ucfirst($parameter))) {
×
699
                    $parameterValue = $this->{'with'.ucfirst($parameter)}($parameterValue);
×
700
                }
701

702
                if (method_exists($operation, 'with'.ucfirst($parameter))) {
×
703
                    $operation = $operation->{'with'.ucfirst($parameter)}($parameterValue);
×
704
                    continue;
×
705
                }
706

NEW
707
                throw new \RuntimeException(\sprintf('Unknown GraphQlOperation parameter "%s".', $parameter));
×
708
            }
709

710
            $operationName = $operation->getName();
×
711
            $operations[$operationName] = $operation;
×
712
        }
713

714
        return $operations;
×
715
    }
716

717
    private function withStateOptions(array $values)
718
    {
719
        if (!$values) {
×
720
            return null;
×
721
        }
722

723
        if (1 !== \count($values)) {
×
724
            throw new \InvalidArgumentException('Only one options can be configured at a time.');
×
725
        }
726

727
        $configuration = reset($values);
×
728
        switch (key($values)) {
×
729
            case 'elasticsearchOptions':
×
730
                return null;
×
731
        }
732

NEW
733
        throw new \LogicException(\sprintf('Unsupported "%s" state options.', key($values)));
×
734
    }
735

736
    private function withLinks(array $values): ?array
737
    {
738
        if (!$values) {
×
739
            return null;
×
740
        }
741

742
        return [new Link($values[0]['rel'] ?? null, $values[0]['href'] ?? null)];
×
743
    }
744

745
    private function withParameters(array $values): ?array
746
    {
747
        if (!$values) {
×
748
            return null;
×
749
        }
750

751
        $parameters = [];
×
752
        foreach ($values as $k => $value) {
×
753
            $parameters[$k] = new QueryParameter(key: $value['key'], required: $value['required'], schema: $value['schema']);
×
754
        }
755

756
        return $parameters;
×
757
    }
758
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc