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

api-platform / core / 15040977736

15 May 2025 09:02AM UTC coverage: 21.754% (+13.3%) from 8.423%
15040977736

Pull #6960

github

web-flow
Merge 7a7a13526 into 1862d03b7
Pull Request #6960: feat(json-schema): mutualize json schema between formats

320 of 460 new or added lines in 24 files covered. (69.57%)

1863 existing lines in 109 files now uncovered.

11069 of 50882 relevant lines covered (21.75%)

29.49 hits per line

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

0.0
/src/OpenApi/Tests/Factory/OpenApiFactoryTest.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\OpenApi\Tests\Factory;
15

16
use ApiPlatform\JsonSchema\DefinitionNameFactory;
17
use ApiPlatform\JsonSchema\Schema;
18
use ApiPlatform\JsonSchema\SchemaFactory;
19
use ApiPlatform\Metadata\ApiProperty;
20
use ApiPlatform\Metadata\ApiResource;
21
use ApiPlatform\Metadata\Delete;
22
use ApiPlatform\Metadata\Error as ErrorOperation;
23
use ApiPlatform\Metadata\ErrorResource;
24
use ApiPlatform\Metadata\Get;
25
use ApiPlatform\Metadata\GetCollection;
26
use ApiPlatform\Metadata\HeaderParameter;
27
use ApiPlatform\Metadata\HttpOperation;
28
use ApiPlatform\Metadata\Link;
29
use ApiPlatform\Metadata\NotExposed;
30
use ApiPlatform\Metadata\Operations;
31
use ApiPlatform\Metadata\Post;
32
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
33
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
34
use ApiPlatform\Metadata\Property\PropertyNameCollection;
35
use ApiPlatform\Metadata\Put;
36
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
37
use ApiPlatform\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
38
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;
39
use ApiPlatform\Metadata\Resource\ResourceNameCollection;
40
use ApiPlatform\OpenApi\Attributes\Webhook;
41
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
42
use ApiPlatform\OpenApi\Model;
43
use ApiPlatform\OpenApi\Model\Components;
44
use ApiPlatform\OpenApi\Model\ExternalDocumentation;
45
use ApiPlatform\OpenApi\Model\Info;
46
use ApiPlatform\OpenApi\Model\MediaType;
47
use ApiPlatform\OpenApi\Model\OAuthFlow;
48
use ApiPlatform\OpenApi\Model\OAuthFlows;
49
use ApiPlatform\OpenApi\Model\Operation;
50
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
51
use ApiPlatform\OpenApi\Model\Parameter;
52
use ApiPlatform\OpenApi\Model\RequestBody;
53
use ApiPlatform\OpenApi\Model\Response;
54
use ApiPlatform\OpenApi\Model\Response as OpenApiResponse;
55
use ApiPlatform\OpenApi\Model\SecurityScheme;
56
use ApiPlatform\OpenApi\Model\Server;
57
use ApiPlatform\OpenApi\OpenApi;
58
use ApiPlatform\OpenApi\Options;
59
use ApiPlatform\OpenApi\Tests\Fixtures\Dummy;
60
use ApiPlatform\OpenApi\Tests\Fixtures\DummyErrorResource;
61
use ApiPlatform\OpenApi\Tests\Fixtures\DummyFilter;
62
use ApiPlatform\OpenApi\Tests\Fixtures\Issue6872\Diamond;
63
use ApiPlatform\OpenApi\Tests\Fixtures\OutputDto;
64
use ApiPlatform\State\ApiResource\Error;
65
use ApiPlatform\State\Pagination\PaginationOptions;
66
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\WithParameter;
67
use ApiPlatform\Validator\Exception\ValidationException;
68
use PHPUnit\Framework\TestCase;
69
use Prophecy\Argument;
70
use Prophecy\PhpUnit\ProphecyTrait;
71
use Psr\Container\ContainerInterface;
72
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
73
use Symfony\Component\TypeInfo\Type;
74

75
class OpenApiFactoryTest extends TestCase
76
{
77
    use ProphecyTrait;
78

79
    private const OPERATION_FORMATS = [
80
        'input_formats' => ['jsonld' => ['application/ld+json']],
81
        'output_formats' => ['jsonld' => ['application/ld+json']],
82
    ];
83

84
    public function testInvoke(): void
85
    {
86
        $baseOperation = (new HttpOperation())->withTypes(['http://schema.example.com/Dummy'])->withInputFormats(self::OPERATION_FORMATS['input_formats'])->withOutputFormats(self::OPERATION_FORMATS['output_formats'])->withClass(Dummy::class)->withOutput([
×
87
            'class' => OutputDto::class,
×
88
        ])->withPaginationClientItemsPerPage(true)->withShortName('Dummy')->withDescription('This is a dummy');
×
89

90
        $dummyResourceWebhook = (new ApiResource())->withOperations(new Operations([
×
91
            'dummy webhook' => (new Get())->withUriTemplate('/dummy/{id}')->withShortName('short')->withOpenapi(new Webhook('first webhook')),
×
92
            'an other dummy webhook' => (new Post())->withUriTemplate('/dummies')->withShortName('short something')->withOpenapi(new Webhook('happy webhook', new Model\PathItem(post: new Operation(
×
93
                summary: 'well...',
×
94
                description: 'I dont\'t know what to say',
×
95
            )))),
×
96
        ]));
×
97

98
        $dummyResource = (new ApiResource())->withOperations(
×
99
            new Operations([
×
100
                'ignored' => new NotExposed(),
×
101
                'ignoredWithUriTemplate' => (new NotExposed())->withUriTemplate('/dummies/{id}'),
×
102
                'getDummyItem' => (new Get())->withUriTemplate('/dummies/{id}')->withOperation($baseOperation)->withUriVariables(['id' => (new Link())->withFromClass(Dummy::class)->withIdentifiers(['id'])]),
×
103
                'putDummyItem' => (new Put())->withUriTemplate('/dummies/{id}')->withOperation($baseOperation)->withUriVariables(['id' => (new Link())->withFromClass(Dummy::class)->withIdentifiers(['id'])]),
×
104
                'deleteDummyItem' => (new Delete())->withUriTemplate('/dummies/{id}')->withOperation($baseOperation)->withUriVariables(['id' => (new Link())->withFromClass(Dummy::class)->withIdentifiers(['id'])]),
×
105
                'customDummyItem' => (new HttpOperation())->withMethod('HEAD')->withUriTemplate('/foo/{id}')->withOperation($baseOperation)->withUriVariables(['id' => (new Link())->withFromClass(Dummy::class)->withIdentifiers(['id'])])->withOpenapi(new OpenApiOperation(
×
106
                    tags: ['Dummy', 'Profile'],
×
107
                    responses: [
×
108
                        '202' => new OpenApiResponse(
×
109
                            description: 'Success',
×
110
                            content: new \ArrayObject([
×
111
                                'application/json' => [
×
112
                                    'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
113
                                ],
×
114
                            ]),
×
115
                            headers: new \ArrayObject([
×
116
                                'Foo' => ['description' => 'A nice header', 'schema' => ['type' => 'integer']],
×
117
                            ]),
×
118
                            links: new \ArrayObject([
×
119
                                'Foo' => ['$ref' => '#/components/schemas/Dummy'],
×
120
                            ]),
×
121
                        ),
×
122
                        '205' => new OpenApiResponse(),
×
123
                    ],
×
124
                    description: 'Custom description',
×
125
                    externalDocs: new ExternalDocumentation(
×
126
                        description: 'See also',
×
127
                        url: 'http://schema.example.com/Dummy',
×
128
                    ),
×
129
                    parameters: [
×
130
                        new Parameter(
×
131
                            name: 'param',
×
132
                            in: 'path',
×
133
                            description: 'Test parameter',
×
134
                            required: true,
×
135
                        ),
×
136
                        new Parameter(
×
137
                            name: 'id',
×
138
                            in: 'path',
×
139
                            description: 'Replace parameter',
×
140
                            required: true,
×
141
                            schema: ['type' => 'string', 'format' => 'uuid'],
×
142
                        ),
×
143
                    ],
×
144
                    requestBody: new RequestBody(
×
145
                        description: 'Custom request body',
×
146
                        content: new \ArrayObject([
×
147
                            'multipart/form-data' => [
×
148
                                'schema' => [
×
149
                                    'type' => 'object',
×
150
                                    'properties' => [
×
151
                                        'file' => [
×
152
                                            'type' => 'string',
×
153
                                            'format' => 'binary',
×
154
                                        ],
×
155
                                    ],
×
156
                                ],
×
157
                            ],
×
158
                        ]),
×
159
                        required: true,
×
160
                    ),
×
161
                    extensionProperties: ['x-visibility' => 'hide'],
×
162
                )),
×
163
                'custom-http-verb' => (new HttpOperation())->withMethod('TEST')->withOperation($baseOperation),
×
164
                'withRoutePrefix' => (new GetCollection())->withUriTemplate('/dummies')->withRoutePrefix('/prefix')->withOperation($baseOperation),
×
165
                'formatsDummyItem' => (new Put())->withOperation($baseOperation)->withUriTemplate('/formatted/{id}')->withUriVariables(['id' => (new Link())->withFromClass(Dummy::class)->withIdentifiers(['id'])])->withInputFormats(['json' => ['application/json'], 'csv' => ['text/csv']])->withOutputFormats(['json' => ['application/json'], 'csv' => ['text/csv']]),
×
166
                'getDummyCollection' => (new GetCollection())->withUriTemplate('/dummies')->withOpenapi(new OpenApiOperation(
×
167
                    parameters: [
×
168
                        new Parameter(
×
169
                            name: 'page',
×
170
                            in: 'query',
×
171
                            description: 'Test modified collection page number',
×
172
                            required: false,
×
173
                            schema: ['type' => 'integer', 'default' => 1],
×
174
                        ),
×
175
                    ],
×
176
                ))->withOperation($baseOperation),
×
177
                'postDummyCollection' => (new Post())->withUriTemplate('/dummies')->withOperation($baseOperation),
×
178
                // Filtered
179
                'filteredDummyCollection' => (new GetCollection())->withUriTemplate('/filtered')->withFilters(['f1', 'f2', 'f3', 'f4', 'f5'])->withOperation($baseOperation),
×
180
                // Paginated
181
                'paginatedDummyCollection' => (new GetCollection())->withUriTemplate('/paginated')
×
182
                    ->withPaginationClientEnabled(true)
×
183
                    ->withPaginationClientItemsPerPage(true)
×
184
                    ->withPaginationItemsPerPage(20)
×
185
                    ->withPaginationMaximumItemsPerPage(80)
×
186
                    ->withOperation($baseOperation),
×
187
                'postDummyCollectionWithRequestBody' => (new Post())->withUriTemplate('/dummiesRequestBody')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
×
188
                    requestBody: new RequestBody(
×
189
                        description: 'List of Ids',
×
190
                        content: new \ArrayObject([
×
191
                            'application/json' => [
×
192
                                'schema' => [
×
193
                                    'type' => 'object',
×
194
                                    'properties' => [
×
195
                                        'ids' => [
×
196
                                            'type' => 'array',
×
197
                                            'items' => ['type' => 'string'],
×
198
                                            'example' => [
×
199
                                                '1e677e04-d461-4389-bedc-6d1b665cc9d6',
×
200
                                                '01111b43-f53a-4d50-8639-148850e5da19',
×
201
                                            ],
×
202
                                        ],
×
203
                                    ],
×
204
                                ],
×
205
                            ],
×
206
                        ]),
×
207
                    ),
×
208
                )),
×
209
                'postDummyCollectionWithRequestBodyWithoutContent' => (new Post())->withUriTemplate('/dummiesRequestBodyWithoutContent')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
×
210
                    requestBody: new RequestBody(
×
211
                        description: 'Extended description for the new Dummy resource',
×
212
                    ),
×
213
                )),
×
214
                'putDummyItemWithResponse' => (new Put())->withUriTemplate('/dummyitems/{id}')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
×
215
                    responses: [
×
216
                        '200' => new OpenApiResponse(
×
217
                            description: 'Success',
×
218
                            content: new \ArrayObject([
×
219
                                'application/json' => [
×
220
                                    'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
221
                                ],
×
222
                            ]),
×
223
                            headers: new \ArrayObject([
×
224
                                'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
×
225
                            ]),
×
226
                            links: new \ArrayObject([
×
227
                                'link' => ['$ref' => '#/components/schemas/Dummy'],
×
228
                            ]),
×
229
                        ),
×
230
                        '400' => new OpenApiResponse(
×
231
                            description: 'Error',
×
232
                        ),
×
233
                    ],
×
234
                )),
×
235
                'getDummyItemImageCollection' => (new GetCollection())->withUriTemplate('/dummyitems/{id}/images')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
×
236
                    responses: [
×
237
                        '200' => new OpenApiResponse(
×
238
                            description: 'Success',
×
239
                        ),
×
240
                    ],
×
241
                )),
×
242
                'postDummyItemWithResponse' => (new Post())->withUriTemplate('/dummyitems')->withOperation($baseOperation)->withOpenapi(new OpenApiOperation(
×
243
                    responses: [
×
244
                        '201' => new OpenApiResponse(
×
245
                            description: 'Created',
×
246
                            content: new \ArrayObject([
×
247
                                'application/json' => [
×
248
                                    'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
249
                                ],
×
250
                            ]),
×
251
                            headers: new \ArrayObject([
×
252
                                'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
×
253
                            ]),
×
254
                            links: new \ArrayObject([
×
255
                                'link' => ['$ref' => '#/components/schemas/Dummy'],
×
256
                            ]),
×
257
                        ),
×
258
                        '400' => new OpenApiResponse(
×
259
                            description: 'Error',
×
260
                        ),
×
261
                    ],
×
262
                )),
×
263
                'postDummyItemWithoutInput' => (new Post())->withUriTemplate('/dummyitem/noinput')->withOperation($baseOperation)->withInput(false),
×
264
                'getDummyCollectionWithErrors' => (new GetCollection())->withUriTemplate('erroredDummies')->withErrors([DummyErrorResource::class])->withOperation($baseOperation),
×
265
            ])
×
266
        );
×
267

268
        $baseOperation = (new HttpOperation())->withTypes(['http://schema.example.com/Dummy'])->withInputFormats(self::OPERATION_FORMATS['input_formats'])->withOutputFormats(self::OPERATION_FORMATS['output_formats'])->withClass(Dummy::class)->withShortName('Parameter')->withDescription('This is a dummy');
×
269
        $parameterResource = (new ApiResource())->withOperations(new Operations([
×
270
            'uriVariableSchema' => (new Get(uriTemplate: '/uri_variable_uuid', uriVariables: ['id' => new Link(schema: ['type' => 'string', 'format' => 'uuid'], description: 'hello', required: true, openApi: new Parameter('id', 'path'))]))->withOperation($baseOperation),
×
271
            'parameters' => (new Put(uriTemplate: '/parameters', parameters: [
×
272
                'foo' => new HeaderParameter(description: 'hi', schema: ['type' => 'string', 'format' => 'uuid']),
×
273
            ]))->withOperation($baseOperation),
×
274
        ]));
×
275

276
        $diamondResource = (new ApiResource())
×
277
            ->withOperations(new Operations([
×
278
                'getDiamondCollection' => (new GetCollection(uriTemplate: '/diamonds'))
×
279
                    ->withSecurity("is_granted('ROLE_USER')")
×
280
                    ->withOperation($baseOperation),
×
281
                'putDiamond' => (new Put(uriTemplate: '/diamond/{id}'))
×
282
                    ->withOperation($baseOperation),
×
283
            ]));
×
284

285
        $resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class);
×
286
        $resourceNameCollectionFactoryProphecy->create()->shouldBeCalled()->willReturn(new ResourceNameCollection([Dummy::class, WithParameter::class, Diamond::class]));
×
287

288
        $resourceCollectionMetadataFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class);
×
289
        $resourceCollectionMetadataFactoryProphecy->create(Dummy::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(Dummy::class, [$dummyResource, $dummyResourceWebhook]));
×
290
        $resourceCollectionMetadataFactoryProphecy->create(DummyErrorResource::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(DummyErrorResource::class, [new ErrorResource(operations: [new ErrorOperation(name: 'err', description: 'nice one!')])]));
×
291
        $resourceCollectionMetadataFactoryProphecy->create(WithParameter::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(WithParameter::class, [$parameterResource]));
×
292
        $resourceCollectionMetadataFactoryProphecy->create(Diamond::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(Diamond::class, [$diamondResource]));
×
293
        $resourceCollectionMetadataFactoryProphecy->create(Error::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(Error::class, []));
×
294
        $resourceCollectionMetadataFactoryProphecy->create(ValidationException::class)->shouldBeCalled()->willReturn(new ResourceMetadataCollection(ValidationException::class, []));
×
295

296
        $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
×
297
        $propertyNameCollectionFactoryProphecy->create(Dummy::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['id', 'name', 'description', 'dummyDate', 'enum']));
×
298
        $propertyNameCollectionFactoryProphecy->create(DummyErrorResource::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['type', 'title', 'status', 'detail', 'instance']));
×
299
        $propertyNameCollectionFactoryProphecy->create(OutputDto::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['id', 'name', 'description', 'dummyDate', 'enum']));
×
300
        $propertyNameCollectionFactoryProphecy->create(Error::class, Argument::any())->shouldBeCalled()->willReturn(new PropertyNameCollection(['type', 'title', 'status', 'detail', 'instance']));
×
301

302
        $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
×
303
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'id', Argument::any())->shouldBeCalled()->willReturn(
×
304
            (new ApiProperty())
×
305
                ->withNativeType(Type::int())
×
306
                ->withDescription('This is an id.')
×
307
                ->withReadable(true)
×
308
                ->withWritable(false)
×
309
                ->withIdentifier(true)
×
310
                ->withSchema(['type' => 'integer', 'readOnly' => true, 'description' => 'This is an id.'])
×
311
        );
×
312
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'name', Argument::any())->shouldBeCalled()->willReturn(
×
313
            (new ApiProperty())
×
314
                ->withNativeType(Type::string())
×
315
                ->withDescription('This is a name.')
×
316
                ->withReadable(true)
×
317
                ->withWritable(true)
×
318
                ->withReadableLink(true)
×
319
                ->withWritableLink(true)
×
320
                ->withRequired(false)
×
321
                ->withIdentifier(false)
×
322
                ->withSchema(['minLength' => 3, 'maxLength' => 20, 'pattern' => '^dummyPattern$', 'description' => 'This is a name.', 'type' => 'string'])
×
323
        );
×
324
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'description', Argument::any())->shouldBeCalled()->willReturn(
×
325
            (new ApiProperty())
×
326
                ->withNativeType(Type::string())
×
327
                ->withDescription('This is an initializable but not writable property.')
×
328
                ->withReadable(true)
×
329
                ->withWritable(false)
×
330
                ->withReadableLink(true)
×
331
                ->withWritableLink(true)
×
332
                ->withRequired(false)
×
333
                ->withIdentifier(false)
×
334
                ->withInitializable(true)
×
335
                ->withSchema(['type' => 'string', 'description' => 'This is an initializable but not writable property.'])
×
336
        );
×
337
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'dummyDate', Argument::any())->shouldBeCalled()->willReturn(
×
338
            (new ApiProperty())
×
339
                ->withNativeType(Type::nullable(Type::object(\DateTime::class)))
×
340
                ->withDescription('This is a \DateTimeInterface object.')
×
341
                ->withReadable(true)
×
342
                ->withWritable(true)
×
343
                ->withReadableLink(true)
×
344
                ->withWritableLink(true)
×
345
                ->withRequired(false)
×
346
                ->withIdentifier(false)
×
347
                ->withSchema(['type' => ['string', 'null'], 'description' => 'This is a \DateTimeInterface object.', 'format' => 'date-time'])
×
348
        );
×
349
        $propertyMetadataFactoryProphecy->create(Dummy::class, 'enum', Argument::any())->shouldBeCalled()->willReturn(
×
350
            (new ApiProperty())
×
351
                ->withNativeType(Type::string())
×
352
                ->withDescription('This is an enum.')
×
353
                ->withReadable(true)
×
354
                ->withWritable(true)
×
355
                ->withReadableLink(true)
×
356
                ->withWritableLink(true)
×
357
                ->withRequired(false)
×
358
                ->withIdentifier(false)
×
359
                ->withSchema(['type' => 'string', 'description' => 'This is an enum.'])
×
360
                ->withOpenapiContext(['type' => 'string', 'enum' => ['one', 'two'], 'example' => 'one'])
×
361
        );
×
362
        $propertyMetadataFactoryProphecy->create(OutputDto::class, 'id', Argument::any())->shouldBeCalled()->willReturn(
×
363
            (new ApiProperty())
×
364
                ->withNativeType(Type::int())
×
365
                ->withDescription('This is an id.')
×
366
                ->withReadable(true)
×
367
                ->withWritable(false)
×
368
                ->withIdentifier(true)
×
369
                ->withSchema(['type' => 'integer', 'description' => 'This is an id.', 'readOnly' => true])
×
370
        );
×
371
        $propertyMetadataFactoryProphecy->create(OutputDto::class, 'name', Argument::any())->shouldBeCalled()->willReturn(
×
372
            (new ApiProperty())
×
373
                ->withNativeType(Type::string())
×
374
                ->withDescription('This is a name.')
×
375
                ->withReadable(true)
×
376
                ->withWritable(true)
×
377
                ->withReadableLink(true)
×
378
                ->withWritableLink(true)
×
379
                ->withRequired(false)
×
380
                ->withIdentifier(false)
×
381
                ->withSchema(['type' => 'string', 'description' => 'This is a name.', 'minLength' => 3, 'maxLength' => 20, 'pattern' => '^dummyPattern$'])
×
382
        );
×
383
        $propertyMetadataFactoryProphecy->create(OutputDto::class, 'description', Argument::any())->shouldBeCalled()->willReturn(
×
384
            (new ApiProperty())
×
385
                ->withNativeType(Type::string())
×
386
                ->withDescription('This is an initializable but not writable property.')
×
387
                ->withReadable(true)
×
388
                ->withWritable(false)
×
389
                ->withReadableLink(true)
×
390
                ->withWritableLink(true)
×
391
                ->withInitializable(true)
×
392
                ->withSchema(['type' => 'string', 'description' => 'This is an initializable but not writable property.'])
×
393
        );
×
394
        $propertyMetadataFactoryProphecy->create(OutputDto::class, 'dummyDate', Argument::any())->shouldBeCalled()->willReturn(
×
395
            (new ApiProperty())
×
396
                ->withNativeType(Type::nullable(Type::object(\DateTime::class)))
×
397
                ->withDescription('This is a \DateTimeInterface object.')
×
398
                ->withReadable(true)
×
399
                ->withWritable(true)
×
400
                ->withReadableLink(true)
×
401
                ->withWritableLink(true)
×
402
                ->withSchema(['type' => ['string', 'null'], 'format' => 'date-time', 'description' => 'This is a \DateTimeInterface object.'])
×
403
        );
×
404
        $propertyMetadataFactoryProphecy->create(OutputDto::class, 'enum', Argument::any())->shouldBeCalled()->willReturn(
×
405
            (new ApiProperty())
×
406
                ->withNativeType(Type::string())
×
407
                ->withDescription('This is an enum.')
×
408
                ->withReadable(true)
×
409
                ->withWritable(true)
×
410
                ->withReadableLink(true)
×
411
                ->withWritableLink(true)
×
412
                ->withSchema(['type' => 'string', 'description' => 'This is an enum.'])
×
413
                ->withOpenapiContext(['type' => 'string', 'enum' => ['one', 'two'], 'example' => 'one'])
×
414
        );
×
415

416
        foreach ([DummyErrorResource::class, Error::class] as $cl) {
×
417
            $propertyMetadataFactoryProphecy->create($cl, 'type', Argument::any())->shouldBeCalled()->willReturn(
×
418
                (new ApiProperty())
×
419
                    ->withNativeType(Type::string())
×
420
                    ->withDescription('This is an error type.')
×
421
                    ->withReadable(true)
×
422
                    ->withWritable(false)
×
423
                    ->withReadableLink(true)
×
424
                    ->withWritableLink(true)
×
425
                    ->withInitializable(true)
×
426
                    ->withSchema(['type' => 'string', 'description' => 'This is an error type.'])
×
427
            );
×
428
            $propertyMetadataFactoryProphecy->create($cl, 'title', Argument::any())->shouldBeCalled()->willReturn(
×
429
                (new ApiProperty())
×
430
                    ->withNativeType(Type::string())
×
431
                    ->withDescription('This is an error title.')
×
432
                    ->withReadable(true)
×
433
                    ->withWritable(false)
×
434
                    ->withReadableLink(true)
×
435
                    ->withWritableLink(true)
×
436
                    ->withInitializable(true)
×
437
                    ->withSchema(['type' => 'string', 'description' => 'This is an error title.'])
×
438
            );
×
439
            $propertyMetadataFactoryProphecy->create($cl, 'status', Argument::any())->shouldBeCalled()->willReturn(
×
440
                (new ApiProperty())
×
441
                    ->withNativeType(Type::int())
×
442
                    ->withDescription('This is an error status.')
×
443
                    ->withReadable(true)
×
444
                    ->withWritable(false)
×
445
                    ->withIdentifier(true)
×
446
                    ->withSchema(['type' => 'integer', 'description' => 'This is an error status.', 'readOnly' => true])
×
447
            );
×
448
            $propertyMetadataFactoryProphecy->create($cl, 'detail', Argument::any())->shouldBeCalled()->willReturn(
×
449
                (new ApiProperty())
×
450
                    ->withNativeType(Type::string())
×
451
                    ->withDescription('This is an error detail.')
×
452
                    ->withReadable(true)
×
453
                    ->withWritable(false)
×
454
                    ->withReadableLink(true)
×
455
                    ->withWritableLink(true)
×
456
                    ->withInitializable(true)
×
457
                    ->withSchema(['type' => 'string', 'description' => 'This is an error detail.'])
×
458
            );
×
459
            $propertyMetadataFactoryProphecy->create($cl, 'instance', Argument::any())->shouldBeCalled()->willReturn(
×
460
                (new ApiProperty())
×
461
                    ->withNativeType(Type::string())
×
462
                    ->withDescription('This is an error instance.')
×
463
                    ->withReadable(true)
×
464
                    ->withWritable(false)
×
465
                    ->withReadableLink(true)
×
466
                    ->withWritableLink(true)
×
467
                    ->withInitializable(true)
×
468
                    ->withSchema(['type' => 'string', 'description' => 'This is an error instance.'])
×
469
            );
×
470
        }
471

472
        $filterLocatorProphecy = $this->prophesize(ContainerInterface::class);
×
473
        $filters = [
×
474
            'f1' => new DummyFilter(['name' => [
×
475
                'property' => 'name',
×
476
                'type' => 'string',
×
477
                'required' => true,
×
478
                'strategy' => 'exact',
×
479
                'openapi' => new Parameter(in: 'query', name: 'name', example: 'bar', deprecated: true, allowReserved: true, explode: true),
×
480
            ]]),
×
481
            'f2' => new DummyFilter(['ha' => [
×
482
                'property' => 'foo',
×
483
                'type' => 'int',
×
484
                'required' => false,
×
485
                'strategy' => 'partial',
×
486
            ]]),
×
487
            'f3' => new DummyFilter(['toto' => [
×
488
                'property' => 'name',
×
489
                'type' => 'array',
×
490
                'is_collection' => true,
×
491
                'required' => true,
×
492
                'strategy' => 'exact',
×
493
            ]]),
×
494
            'f4' => new DummyFilter(['order[name]' => [
×
495
                'property' => 'name',
×
496
                'type' => 'string',
×
497
                'required' => false,
×
498
                'schema' => [
×
499
                    'type' => 'string',
×
500
                    'enum' => ['asc', 'desc'],
×
501
                ],
×
502
            ]]),
×
503
        ];
×
504

505
        foreach ($filters as $filterId => $filter) {
×
506
            $filterLocatorProphecy->has($filterId)->willReturn(true)->shouldBeCalled();
×
507
            $filterLocatorProphecy->get($filterId)->willReturn($filter)->shouldBeCalled();
×
508
        }
509

510
        $filterLocatorProphecy->has('f5')->willReturn(false)->shouldBeCalled();
×
511

512
        $resourceCollectionMetadataFactory = $resourceCollectionMetadataFactoryProphecy->reveal();
×
513
        $propertyNameCollectionFactory = $propertyNameCollectionFactoryProphecy->reveal();
×
514

515
        $propertyMetadataFactory = $propertyMetadataFactoryProphecy->reveal();
×
516

517
        $definitionNameFactory = new DefinitionNameFactory([]);
×
518

519
        $schemaFactory = new SchemaFactory(
×
520
            resourceMetadataFactory: $resourceCollectionMetadataFactory,
×
521
            propertyNameCollectionFactory: $propertyNameCollectionFactory,
×
522
            propertyMetadataFactory: $propertyMetadataFactory,
×
523
            nameConverter: new CamelCaseToSnakeCaseNameConverter(),
×
524
            definitionNameFactory: $definitionNameFactory,
×
525
        );
×
526

527
        $factory = new OpenApiFactory(
×
528
            $resourceNameCollectionFactoryProphecy->reveal(),
×
529
            $resourceCollectionMetadataFactory,
×
530
            $propertyNameCollectionFactory,
×
531
            $propertyMetadataFactory,
×
532
            $schemaFactory,
×
533
            $filterLocatorProphecy->reveal(),
×
534
            [],
×
535
            new Options('Test API', 'This is a test API.', '1.2.3', true, 'oauth2', 'authorizationCode', '/oauth/v2/token', '/oauth/v2/auth', '/oauth/v2/refresh', ['scope param'], [
×
536
                'header' => [
×
537
                    'type' => 'header',
×
538
                    'name' => 'Authorization',
×
539
                ],
×
540
                'query' => [
×
541
                    'type' => 'query',
×
542
                    'name' => 'key',
×
543
                ],
×
544
            ], null, null, null, null, null, null, true, true, [
×
545
                'bearer' => [
×
546
                    'scheme' => 'bearer',
×
547
                    'bearerFormat' => 'JWT',
×
548
                ],
×
549
                'basic' => [
×
550
                    'scheme' => 'basic',
×
551
                ],
×
552
            ]),
×
553
            new PaginationOptions(true, 'page', true, 'itemsPerPage', true, 'pagination'),
×
554
            null,
×
555
            ['json' => ['application/problem+json']]
×
556
        );
×
557

558
        $dummySchema = new Schema('openapi');
×
559
        $dummySchema->setDefinitions(new \ArrayObject([
×
560
            'type' => 'object',
×
561
            'description' => 'This is a dummy',
×
562
            'externalDocs' => ['url' => 'http://schema.example.com/Dummy'],
×
563
            'properties' => [
×
564
                'id' => new \ArrayObject([
×
565
                    'type' => 'integer',
×
566
                    'description' => 'This is an id.',
×
567
                    'readOnly' => true,
×
568
                ]),
×
569
                'name' => new \ArrayObject([
×
570
                    'type' => 'string',
×
571
                    'description' => 'This is a name.',
×
572
                    'minLength' => 3,
×
573
                    'maxLength' => 20,
×
574
                    'pattern' => '^dummyPattern$',
×
575
                ]),
×
576
                'description' => new \ArrayObject([
×
577
                    'type' => 'string',
×
578
                    'description' => 'This is an initializable but not writable property.',
×
579
                ]),
×
580
                'dummy_date' => new \ArrayObject([
×
581
                    'type' => ['string', 'null'],
×
582
                    'description' => 'This is a \DateTimeInterface object.',
×
583
                    'format' => 'date-time',
×
584
                ]),
×
585
                'enum' => new \ArrayObject([
×
586
                    'type' => 'string',
×
587
                    'enum' => ['one', 'two'],
×
588
                    'example' => 'one',
×
589
                    'description' => 'This is an enum.',
×
590
                ]),
×
591
            ],
×
592
        ]));
×
593
        $dummyErrorSchema = new Schema('openapi');
×
594
        $dummyErrorSchema->setDefinitions(new \ArrayObject([
×
595
            'type' => 'object',
×
596
            'description' => 'nice one!',
×
597
            'properties' => [
×
598
                'type' => new \ArrayObject([
×
599
                    'type' => 'string',
×
600
                    'description' => 'This is an error type.',
×
601
                ]),
×
602
                'title' => new \ArrayObject([
×
603
                    'type' => 'string',
×
604
                    'description' => 'This is an error title.',
×
605
                ]),
×
606
                'status' => new \ArrayObject([
×
607
                    'type' => 'integer',
×
608
                    'description' => 'This is an error status.',
×
609
                    'readOnly' => true,
×
610
                ]),
×
611
                'detail' => new \ArrayObject([
×
612
                    'type' => 'string',
×
613
                    'description' => 'This is an error detail.',
×
614
                ]),
×
615
                'instance' => new \ArrayObject([
×
616
                    'type' => 'string',
×
617
                    'description' => 'This is an error instance.',
×
618
                ]),
×
619
            ],
×
620
        ]));
×
621
        $errorSchema = clone $dummyErrorSchema->getDefinitions();
×
NEW
622
        unset($errorSchema['description']);
×
623

624
        $openApi = $factory(['base_url' => '/app_dev.php/']);
×
625

626
        $this->assertInstanceOf(OpenApi::class, $openApi);
×
627
        $this->assertEquals($openApi->getInfo(), new Info('Test API', '1.2.3', 'This is a test API.'));
×
628
        $this->assertEquals($openApi->getServers(), [new Server('/app_dev.php/')]);
×
629

630
        $webhooks = $openApi->getWebhooks();
×
631
        $this->assertCount(2, $webhooks);
×
632

633
        $firstOperationWebhook = $webhooks['first webhook'];
×
634
        $secondOperationWebhook = $webhooks['happy webhook'];
×
635
        $this->assertSame('dummy webhook', $firstOperationWebhook->getGet()->getOperationId());
×
636
        $this->assertSame('an other dummy webhook', $secondOperationWebhook->getPost()->getOperationId());
×
637
        $this->assertSame('I dont\'t know what to say', $secondOperationWebhook->getPost()->getDescription());
×
638
        $this->assertSame('well...', $secondOperationWebhook->getPost()->getSummary());
×
639

640
        $components = $openApi->getComponents();
×
641
        $this->assertInstanceOf(Components::class, $components);
×
642

643
        $parameterSchema = $dummySchema->getDefinitions();
×
644
        $this->assertEquals($components->getSchemas(), new \ArrayObject([
×
645
            'Dummy' => $dummySchema->getDefinitions(),
×
646
            'Dummy.OutputDto' => $dummySchema->getDefinitions(),
×
NEW
647
            'Dummy.jsonld' => $dummySchema->getDefinitions(),
×
NEW
648
            'Dummy.OutputDto.jsonld' => $dummySchema->getDefinitions(),
×
NEW
649
            'Parameter.jsonld' => $parameterSchema,
×
650
            'DummyErrorResource' => $dummyErrorSchema->getDefinitions(),
×
651
            'Error' => $errorSchema,
×
652
        ]));
×
653

654
        $this->assertEquals($components->getSecuritySchemes(), new \ArrayObject([
×
655
            'oauth' => new SecurityScheme('oauth2', 'OAuth 2.0 authorization code Grant', null, null, null, null, new OAuthFlows(null, null, null, new OAuthFlow('/oauth/v2/auth', '/oauth/v2/token', '/oauth/v2/refresh', new \ArrayObject(['scope param'])))),
×
656
            'header' => new SecurityScheme('apiKey', 'Value for the Authorization header parameter.', 'Authorization', 'header'),
×
657
            'query' => new SecurityScheme('apiKey', 'Value for the key query parameter.', 'key', 'query'),
×
658
            'bearer' => new SecurityScheme('http', 'Value for the http bearer parameter.', null, null, 'bearer', 'JWT'),
×
659
            'basic' => new SecurityScheme('http', 'Value for the http basic parameter.', null, null, 'basic', null),
×
660
        ]));
×
661

662
        $this->assertEquals([
×
663
            ['oauth' => []],
×
664
            ['header' => []],
×
665
            ['query' => []],
×
666
            ['bearer' => []],
×
667
            ['basic' => []],
×
668
        ], $openApi->getSecurity());
×
669

670
        $paths = $openApi->getPaths();
×
671
        $dummiesPath = $paths->getPath('/dummies');
×
672
        $this->assertNotNull($dummiesPath);
×
673
        foreach (['Put', 'Head', 'Trace', 'Delete', 'Options', 'Patch'] as $method) {
×
674
            $this->assertNull($dummiesPath->{'get'.$method}());
×
675
        }
676

677
        $this->assertEquals(new Operation(
×
678
            'getDummyCollection',
×
679
            ['Dummy'],
×
680
            [
×
681
                '200' => new Response('Dummy collection', new \ArrayObject([
×
682
                    'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject([
×
683
                        'type' => 'array',
×
NEW
684
                        'items' => ['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld'],
×
685
                    ]))),
×
686
                ])),
×
687
            ],
×
688
            'Retrieves the collection of Dummy resources.',
×
689
            'Retrieves the collection of Dummy resources.',
×
690
            null,
×
691
            [
×
692
                new Parameter('page', 'query', 'Test modified collection page number', false, false, null, [
×
693
                    'type' => 'integer',
×
694
                    'default' => 1,
×
695
                ]),
×
696
                new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
×
697
                    'type' => 'integer',
×
698
                    'default' => 30,
×
699
                    'minimum' => 0,
×
700
                ]),
×
701
                new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
×
702
                    'type' => 'boolean',
×
703
                ]),
×
704
            ]
×
705
        ), $dummiesPath->getGet());
×
706

707
        $this->assertEquals(new Operation(
×
708
            'postDummyCollection',
×
709
            ['Dummy'],
×
710
            [
×
711
                '201' => new Response(
×
712
                    'Dummy resource created',
×
713
                    new \ArrayObject([
×
NEW
714
                        'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld']))),
×
715
                    ]),
×
716
                    null,
×
717
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
718
                ),
×
719
                '400' => new Response(
×
720
                    'Invalid input',
×
721
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
722
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
723
                ),
×
724
                '422' => new Response(
×
725
                    'Unprocessable entity',
×
726
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
727
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
728
                ),
×
729
            ],
×
730
            'Creates a Dummy resource.',
×
731
            'Creates a Dummy resource.',
×
732
            null,
×
733
            [],
×
734
            new RequestBody(
×
735
                'The new Dummy resource',
×
736
                new \ArrayObject([
×
NEW
737
                    'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.jsonld']))),
×
738
                ]),
×
739
                true
×
740
            )
×
741
        ), $dummiesPath->getPost());
×
742

743
        $dummyPath = $paths->getPath('/dummies/{id}');
×
744
        $this->assertNotNull($dummyPath);
×
745
        foreach (['Post', 'Head', 'Trace', 'Options', 'Patch'] as $method) {
×
746
            $this->assertNull($dummyPath->{'get'.$method}());
×
747
        }
748

749
        $this->assertEquals(new Operation(
×
750
            'getDummyItem',
×
751
            ['Dummy'],
×
752
            [
×
753
                '200' => new Response(
×
754
                    'Dummy resource',
×
755
                    new \ArrayObject([
×
NEW
756
                        'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld']))),
×
757
                    ])
×
758
                ),
×
759
                '404' => new Response(
×
760
                    'Not found',
×
761
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
762
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
763
                ),
×
764
            ],
×
765
            'Retrieves a Dummy resource.',
×
766
            'Retrieves a Dummy resource.',
×
767
            null,
×
768
            [new Parameter('id', 'path', 'Dummy identifier', true, false, false, ['type' => 'string'])]
×
769
        ), $dummyPath->getGet());
×
770

771
        $this->assertEquals(new Operation(
×
772
            'putDummyItem',
×
773
            ['Dummy'],
×
774
            [
×
775
                '200' => new Response(
×
776
                    'Dummy resource updated',
×
777
                    new \ArrayObject([
×
NEW
778
                        'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld'])),
×
779
                    ]),
×
780
                    null,
×
781
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
782
                ),
×
783
                '400' => new Response(
×
784
                    'Invalid input',
×
785
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
786
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
787
                ),
×
788
                '422' => new Response(
×
789
                    'Unprocessable entity',
×
790
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
791
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
792
                ),
×
793
                '404' => new Response(
×
794
                    'Not found',
×
795
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
796
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
797
                ),
×
798
            ],
×
799
            'Replaces the Dummy resource.',
×
800
            'Replaces the Dummy resource.',
×
801
            null,
×
802
            [new Parameter('id', 'path', 'Dummy identifier', true, false, false, ['type' => 'string'])],
×
803
            new RequestBody(
×
804
                'The updated Dummy resource',
×
805
                new \ArrayObject([
×
NEW
806
                    'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.jsonld'])),
×
807
                ]),
×
808
                true
×
809
            )
×
810
        ), $dummyPath->getPut());
×
811

812
        $this->assertEquals(new Operation(
×
813
            'deleteDummyItem',
×
814
            ['Dummy'],
×
815
            [
×
816
                '204' => new Response('Dummy resource deleted'),
×
817
                '404' => new Response(
×
818
                    'Not found',
×
819
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
820
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
821
                ),
×
822
            ],
×
823
            'Removes the Dummy resource.',
×
824
            'Removes the Dummy resource.',
×
825
            null,
×
826
            [new Parameter('id', 'path', 'Dummy identifier', true, false, false, ['type' => 'string'])]
×
827
        ), $dummyPath->getDelete());
×
828

829
        $customPath = $paths->getPath('/foo/{id}');
×
830
        $this->assertEquals(new Operation(
×
831
            'customDummyItem',
×
832
            ['Dummy', 'Profile'],
×
833
            [
×
834
                '202' => new Response('Success', new \ArrayObject([
×
835
                    'application/json' => [
×
836
                        'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
837
                    ],
×
838
                ]), new \ArrayObject([
×
839
                    'Foo' => ['description' => 'A nice header', 'schema' => ['type' => 'integer']],
×
840
                ]), new \ArrayObject([
×
841
                    'Foo' => ['$ref' => '#/components/schemas/Dummy'],
×
842
                ])),
×
843
                '205' => new Response(),
×
844
                '404' => new Response(
×
845
                    'Not found',
×
846
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
847
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
848
                ),
×
849
            ],
×
850
            'Dummy',
×
851
            'Custom description',
×
852
            new ExternalDocumentation('See also', 'http://schema.example.com/Dummy'),
×
853
            [new Parameter('param', 'path', 'Test parameter', true), new Parameter('id', 'path', 'Replace parameter', true, false, false, ['type' => 'string', 'format' => 'uuid'])],
×
854
            new RequestBody('Custom request body', new \ArrayObject([
×
855
                'multipart/form-data' => [
×
856
                    'schema' => [
×
857
                        'type' => 'object',
×
858
                        'properties' => [
×
859
                            'file' => [
×
860
                                'type' => 'string',
×
861
                                'format' => 'binary',
×
862
                            ],
×
863
                        ],
×
864
                    ],
×
865
                ],
×
866
            ]), true),
×
867
            null,
×
868
            false,
×
869
            null,
×
870
            null,
×
871
            ['x-visibility' => 'hide']
×
872
        ), $customPath->getHead());
×
873

874
        $prefixPath = $paths->getPath('/prefix/dummies');
×
875
        $this->assertNotNull($prefixPath);
×
876

877
        $formattedPath = $paths->getPath('/formatted/{id}');
×
878
        $this->assertEquals(new Operation(
×
879
            'formatsDummyItem',
×
880
            ['Dummy'],
×
881
            [
×
882
                '200' => new Response(
×
883
                    'Dummy resource updated',
×
884
                    new \ArrayObject([
×
885
                        'application/json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto'])),
×
NEW
886
                        'text/csv' => new \ArrayObject(),
×
887
                    ]),
×
888
                    null,
×
889
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
890
                ),
×
891
                '400' => new Response(
×
892
                    'Invalid input',
×
893
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
894
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
895
                ),
×
896
                '422' => new Response(
×
897
                    'Unprocessable entity',
×
898
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
899
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
900
                ),
×
901
                '404' => new Response(
×
902
                    'Not found',
×
903
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
904
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$request.path.id']), null, 'This is a dummy')])
×
905
                ),
×
906
            ],
×
907
            'Replaces the Dummy resource.',
×
908
            'Replaces the Dummy resource.',
×
909
            null,
×
910
            [new Parameter('id', 'path', 'Dummy identifier', true, false, false, ['type' => 'string'])],
×
911
            new RequestBody(
×
912
                'The updated Dummy resource',
×
913
                new \ArrayObject([
×
914
                    'application/json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy'])),
×
NEW
915
                    'text/csv' => new \ArrayObject(),
×
916
                ]),
×
917
                true
×
918
            )
×
919
        ), $formattedPath->getPut());
×
920

921
        $filteredPath = $paths->getPath('/filtered');
×
922
        $this->assertEquals(new Operation(
×
923
            'filteredDummyCollection',
×
924
            ['Dummy'],
×
925
            [
×
926
                '200' => new Response('Dummy collection', new \ArrayObject([
×
927
                    'application/ld+json' => new MediaType(new \ArrayObject([
×
928
                        'type' => 'array',
×
NEW
929
                        'items' => ['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld'],
×
930
                    ])),
×
931
                ])),
×
932
            ],
×
933
            'Retrieves the collection of Dummy resources.',
×
934
            'Retrieves the collection of Dummy resources.',
×
935
            null,
×
936
            [
×
937
                new Parameter('page', 'query', 'The collection page number', false, false, null, [
×
938
                    'type' => 'integer',
×
939
                    'default' => 1,
×
940
                ]),
×
941
                new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
×
942
                    'type' => 'integer',
×
943
                    'default' => 30,
×
944
                    'minimum' => 0,
×
945
                ]),
×
946
                new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
×
947
                    'type' => 'boolean',
×
948
                ]),
×
949
                new Parameter('name', 'query', '', true, true, null, [
×
950
                    'type' => 'string',
×
951
                ], 'form', true, true, 'bar'),
×
952
                new Parameter('ha', 'query', '', false, false, null, [
×
953
                    'type' => 'integer',
×
954
                ]),
×
955
                new Parameter('toto', 'query', '', true, false, null, [
×
956
                    'type' => 'array',
×
957
                    'items' => ['type' => 'string'],
×
958
                ], 'deepObject', true),
×
959
                new Parameter('order[name]', 'query', '', false, false, null, [
×
960
                    'type' => 'string',
×
961
                    'enum' => ['asc', 'desc'],
×
962
                ]),
×
963
            ],
×
964
        ), $filteredPath->getGet());
×
965

966
        $paginatedPath = $paths->getPath('/paginated');
×
967
        $this->assertEquals(new Operation(
×
968
            'paginatedDummyCollection',
×
969
            ['Dummy'],
×
970
            [
×
971
                '200' => new Response('Dummy collection', new \ArrayObject([
×
972
                    'application/ld+json' => new MediaType(new \ArrayObject([
×
973
                        'type' => 'array',
×
NEW
974
                        'items' => ['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld'],
×
975
                    ])),
×
976
                ])),
×
977
            ],
×
978
            'Retrieves the collection of Dummy resources.',
×
979
            'Retrieves the collection of Dummy resources.',
×
980
            null,
×
981
            [
×
982
                new Parameter('page', 'query', 'The collection page number', false, false, null, [
×
983
                    'type' => 'integer',
×
984
                    'default' => 1,
×
985
                ]),
×
986
                new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
×
987
                    'type' => 'integer',
×
988
                    'default' => 20,
×
989
                    'minimum' => 0,
×
990
                    'maximum' => 80,
×
991
                ]),
×
992
                new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
×
993
                    'type' => 'boolean',
×
994
                ]),
×
995
            ]
×
996
        ), $paginatedPath->getGet());
×
997

998
        $requestBodyPath = $paths->getPath('/dummiesRequestBody');
×
999
        $this->assertEquals(new Operation(
×
1000
            'postDummyCollectionWithRequestBody',
×
1001
            ['Dummy'],
×
1002
            [
×
1003
                '201' => new Response(
×
1004
                    'Dummy resource created',
×
1005
                    new \ArrayObject([
×
NEW
1006
                        'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld']))),
×
1007
                    ]),
×
1008
                    null,
×
1009
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1010
                ),
×
1011
                '400' => new Response(
×
1012
                    'Invalid input',
×
1013
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1014
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1015
                ),
×
1016
                '422' => new Response(
×
1017
                    'Unprocessable entity',
×
1018
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1019
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1020
                ),
×
1021
            ],
×
1022
            'Creates a Dummy resource.',
×
1023
            'Creates a Dummy resource.',
×
1024
            null,
×
1025
            [],
×
1026
            new RequestBody(
×
1027
                'List of Ids',
×
1028
                new \ArrayObject([
×
1029
                    'application/json' => [
×
1030
                        'schema' => [
×
1031
                            'type' => 'object',
×
1032
                            'properties' => [
×
1033
                                'ids' => [
×
1034
                                    'type' => 'array',
×
1035
                                    'items' => ['type' => 'string'],
×
1036
                                    'example' => [
×
1037
                                        '1e677e04-d461-4389-bedc-6d1b665cc9d6',
×
1038
                                        '01111b43-f53a-4d50-8639-148850e5da19',
×
1039
                                    ],
×
1040
                                ],
×
1041
                            ],
×
1042
                        ],
×
1043
                    ],
×
1044
                ]),
×
1045
                false
×
1046
            ),
×
1047
        ), $requestBodyPath->getPost());
×
1048

1049
        $requestBodyPath = $paths->getPath('/dummiesRequestBodyWithoutContent');
×
1050
        $this->assertEquals(new Operation(
×
1051
            'postDummyCollectionWithRequestBodyWithoutContent',
×
1052
            ['Dummy'],
×
1053
            [
×
1054
                '201' => new Response(
×
1055
                    'Dummy resource created',
×
1056
                    new \ArrayObject([
×
NEW
1057
                        'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld']))),
×
1058
                    ]),
×
1059
                    null,
×
1060
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1061
                ),
×
1062
                '400' => new Response(
×
1063
                    'Invalid input',
×
1064
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1065
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1066
                ),
×
1067
                '422' => new Response(
×
1068
                    'Unprocessable entity',
×
1069
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1070
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1071
                ),
×
1072
            ],
×
1073
            'Creates a Dummy resource.',
×
1074
            'Creates a Dummy resource.',
×
1075
            null,
×
1076
            [],
×
1077
            new RequestBody(
×
1078
                'Extended description for the new Dummy resource',
×
1079
                new \ArrayObject([
×
NEW
1080
                    'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.jsonld']))),
×
1081
                ]),
×
1082
                false
×
1083
            ),
×
1084
        ), $requestBodyPath->getPost());
×
1085

1086
        $dummyItemPath = $paths->getPath('/dummyitems/{id}');
×
1087
        $this->assertEquals(new Operation(
×
1088
            'putDummyItemWithResponse',
×
1089
            ['Dummy'],
×
1090
            [
×
1091
                '200' => new Response(
×
1092
                    'Success',
×
1093
                    new \ArrayObject([
×
1094
                        'application/json' => [
×
1095
                            'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
1096
                        ],
×
1097
                    ]),
×
1098
                    new \ArrayObject([
×
1099
                        'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
×
1100
                    ]),
×
1101
                    new \ArrayObject([
×
1102
                        'link' => ['$ref' => '#/components/schemas/Dummy'],
×
1103
                    ])
×
1104
                ),
×
1105
                '400' => new Response('Error'),
×
1106
                '422' => new Response(
×
1107
                    'Unprocessable entity',
×
1108
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1109
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1110
                ),
×
1111
                '404' => new Response(
×
1112
                    'Not found',
×
1113
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1114
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1115
                ),
×
1116
            ],
×
1117
            'Replaces the Dummy resource.',
×
1118
            'Replaces the Dummy resource.',
×
1119
            null,
×
1120
            [],
×
1121
            new RequestBody(
×
1122
                'The updated Dummy resource',
×
1123
                new \ArrayObject([
×
NEW
1124
                    'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.jsonld'])),
×
1125
                ]),
×
1126
                true
×
1127
            ),
×
1128
        ), $dummyItemPath->getPut());
×
1129

1130
        $dummyItemPath = $paths->getPath('/dummyitems');
×
1131
        $this->assertEquals(new Operation(
×
1132
            'postDummyItemWithResponse',
×
1133
            ['Dummy'],
×
1134
            [
×
1135
                '201' => new Response(
×
1136
                    'Created',
×
1137
                    new \ArrayObject([
×
1138
                        'application/json' => [
×
1139
                            'schema' => ['$ref' => '#/components/schemas/Dummy'],
×
1140
                        ],
×
1141
                    ]),
×
1142
                    new \ArrayObject([
×
1143
                        'API_KEY' => ['description' => 'Api Key', 'schema' => ['type' => 'string']],
×
1144
                    ]),
×
1145
                    new \ArrayObject([
×
1146
                        'link' => ['$ref' => '#/components/schemas/Dummy'],
×
1147
                    ])
×
1148
                ),
×
1149
                '400' => new Response('Error'),
×
1150
                '422' => new Response(
×
1151
                    'Unprocessable entity',
×
1152
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1153
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1154
                ),
×
1155
            ],
×
1156
            'Creates a Dummy resource.',
×
1157
            'Creates a Dummy resource.',
×
1158
            null,
×
1159
            [],
×
1160
            new RequestBody(
×
1161
                'The new Dummy resource',
×
1162
                new \ArrayObject([
×
NEW
1163
                    'application/ld+json' => new MediaType(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.jsonld'])),
×
1164
                ]),
×
1165
                true
×
1166
            ),
×
1167
        ), $dummyItemPath->getPost());
×
1168

1169
        $dummyItemPath = $paths->getPath('/dummyitems/{id}/images');
×
1170

1171
        $this->assertEquals(new Operation(
×
1172
            'getDummyItemImageCollection',
×
1173
            ['Dummy'],
×
1174
            [
×
1175
                '200' => new Response(
×
1176
                    'Success'
×
1177
                ),
×
1178
            ],
×
1179
            'Retrieves the collection of Dummy resources.',
×
1180
            'Retrieves the collection of Dummy resources.',
×
1181
            null,
×
1182
            [
×
1183
                new Parameter('page', 'query', 'The collection page number', false, false, null, [
×
1184
                    'type' => 'integer',
×
1185
                    'default' => 1,
×
1186
                ]),
×
1187
                new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
×
1188
                    'type' => 'integer',
×
1189
                    'default' => 30,
×
1190
                    'minimum' => 0,
×
1191
                ]),
×
1192
                new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
×
1193
                    'type' => 'boolean',
×
1194
                ]),
×
1195
            ]
×
1196
        ), $dummyItemPath->getGet());
×
1197

1198
        $emptyRequestBodyPath = $paths->getPath('/dummyitem/noinput');
×
1199
        $this->assertEquals(new Operation(
×
1200
            'postDummyItemWithoutInput',
×
1201
            ['Dummy'],
×
1202
            [
×
1203
                '201' => new Response(
×
1204
                    'Dummy resource created',
×
1205
                    new \ArrayObject([
×
NEW
1206
                        'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject(['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld']))),
×
1207
                    ]),
×
1208
                    null,
×
1209
                    new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1210
                ),
×
1211
                '400' => new Response(
×
1212
                    'Invalid input',
×
1213
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1214
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1215
                ),
×
1216
                '422' => new Response(
×
1217
                    'Unprocessable entity',
×
1218
                    content: new \ArrayObject(['application/problem+json' => new MediaType(schema: new \ArrayObject(['$ref' => '#/components/schemas/Error']))]),
×
1219
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1220
                ),
×
1221
            ],
×
1222
            'Creates a Dummy resource.',
×
1223
            'Creates a Dummy resource.',
×
1224
            null,
×
1225
            [],
×
1226
            null
×
1227
        ), $emptyRequestBodyPath->getPost());
×
1228

1229
        $parameter = $paths->getPath('/uri_variable_uuid')->getGet()->getParameters()[0];
×
1230
        $this->assertEquals(['type' => 'string', 'format' => 'uuid'], $parameter->getSchema());
×
1231

1232
        $parameter = $paths->getPath('/parameters')->getPut()->getParameters()[0];
×
1233
        $this->assertEquals(['type' => 'string', 'format' => 'uuid'], $parameter->getSchema());
×
1234
        $this->assertEquals('header', $parameter->getIn());
×
1235
        $this->assertEquals('hi', $parameter->getDescription());
×
1236

1237
        $this->assertEquals(new Operation(
×
1238
            'getDummyCollectionWithErrors',
×
1239
            ['Dummy'],
×
1240
            [
×
1241
                '200' => new Response('Dummy collection', new \ArrayObject([
×
1242
                    'application/ld+json' => new MediaType(new \ArrayObject(new \ArrayObject([
×
1243
                        'type' => 'array',
×
NEW
1244
                        'items' => ['$ref' => '#/components/schemas/Dummy.OutputDto.jsonld'],
×
1245
                    ]))),
×
1246
                ])),
×
1247
                '418' => new Response(
×
1248
                    'A Teapot Exception',
×
1249
                    new \ArrayObject([
×
1250
                        'application/problem+json' => new MediaType(new \ArrayObject(new \ArrayObject([
×
1251
                            '$ref' => '#/components/schemas/DummyErrorResource',
×
1252
                        ]))),
×
1253
                    ]),
×
1254
                    links: new \ArrayObject(['getDummyItem' => new Model\Link('getDummyItem', new \ArrayObject(['id' => '$response.body#/id']), null, 'This is a dummy')])
×
1255
                ),
×
1256
            ],
×
1257
            'Retrieves the collection of Dummy resources.',
×
1258
            'Retrieves the collection of Dummy resources.',
×
1259
            null,
×
1260
            [
×
1261
                new Parameter('page', 'query', 'The collection page number', false, false, null, [
×
1262
                    'type' => 'integer',
×
1263
                    'default' => 1,
×
1264
                ]),
×
1265
                new Parameter('itemsPerPage', 'query', 'The number of items per page', false, false, null, [
×
1266
                    'type' => 'integer',
×
1267
                    'default' => 30,
×
1268
                    'minimum' => 0,
×
1269
                ]),
×
1270
                new Parameter('pagination', 'query', 'Enable or disable pagination', false, false, null, [
×
1271
                    'type' => 'boolean',
×
1272
                ]),
×
1273
            ],
×
1274
        ), $paths->getPath('/erroredDummies')->getGet());
×
1275

1276
        $diamondsGetPath = $paths->getPath('/diamonds');
×
1277
        $diamondGetOperation = $diamondsGetPath->getGet();
×
1278
        $diamondGetResponses = $diamondGetOperation->getResponses();
×
1279

1280
        $this->assertNotNull($diamondGetOperation);
×
1281
        $this->assertArrayHasKey('403', $diamondGetResponses);
×
1282
        $this->assertSame('Forbidden', $diamondGetResponses['403']->getDescription());
×
1283

1284
        $diamondsPutPath = $paths->getPath('/diamond/{id}');
×
1285
        $diamondPutOperation = $diamondsPutPath->getPut();
×
1286
        $diamondPutResponses = $diamondPutOperation->getResponses();
×
1287

1288
        $this->assertNotNull($diamondPutOperation);
×
1289
        $this->assertArrayNotHasKey('403', $diamondPutResponses);
×
1290
    }
1291

1292
    public function testGetExtensionPropertiesWithFalseValue(): void
1293
    {
1294
        $resourceNameCollectionFactory = $this->createMock(ResourceNameCollectionFactoryInterface::class);
×
1295
        $resourceCollectionMetadataFactory = $this->createMock(ResourceMetadataCollectionFactoryInterface::class);
×
1296
        $propertyNameCollectionFactory = $this->createMock(PropertyNameCollectionFactoryInterface::class);
×
1297
        $propertyMetadataFactory = $this->createMock(PropertyMetadataFactoryInterface::class);
×
1298
        $definitionNameFactory = new DefinitionNameFactory([]);
×
1299

1300
        $resourceCollectionMetadata = new ResourceMetadataCollection(Dummy::class, [(new ApiResource(operations: [
×
1301
            (new Get())->withOpenapi(true)->withShortName('Dummy')->withName('api_dummies_get_collection')->withRouteName('api_dummies_get_collection'),
×
1302
        ]))->withClass(Dummy::class)]);
×
1303

1304
        $resourceCollectionMetadataFactory
×
1305
            ->method('create')
×
1306
            ->willReturnCallback(fn (string $resourceClass): ResourceMetadataCollection => match ($resourceClass) {
×
1307
                default => new ResourceMetadataCollection($resourceClass, []),
×
1308
                Dummy::class => $resourceCollectionMetadata,
×
1309
            });
×
1310

1311
        $resourceNameCollectionFactory->expects($this->once())
×
1312
            ->method('create')
×
1313
            ->willReturn(new ResourceNameCollection([Dummy::class]));
×
1314

1315
        $propertyNameCollectionFactory->method('create')->willReturn(new PropertyNameCollection([]));
×
1316

1317
        $schemaFactory = new SchemaFactory(
×
1318
            resourceMetadataFactory: $resourceCollectionMetadataFactory,
×
1319
            propertyNameCollectionFactory: $propertyNameCollectionFactory,
×
1320
            propertyMetadataFactory: $propertyMetadataFactory,
×
1321
            nameConverter: new CamelCaseToSnakeCaseNameConverter(),
×
1322
            definitionNameFactory: $definitionNameFactory,
×
1323
        );
×
1324

1325
        $factory = new OpenApiFactory(
×
1326
            $resourceNameCollectionFactory,
×
1327
            $resourceCollectionMetadataFactory,
×
1328
            $propertyNameCollectionFactory,
×
1329
            $propertyMetadataFactory,
×
1330
            $schemaFactory,
×
1331
            null,
×
1332
            [],
×
1333
            new Options('Test API', 'This is a test API.', '1.2.3'),
×
1334
            new PaginationOptions(),
×
1335
            null,
×
1336
            ['json' => ['application/problem+json']]
×
1337
        );
×
1338

1339
        $openApi = $factory->__invoke();
×
1340
    }
1341
}
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