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

api-platform / core / 18046663088

26 Sep 2025 06:52PM UTC coverage: 0.0% (-21.8%) from 21.793%
18046663088

Pull #7397

github

web-flow
Merge 638ad9207 into 00fbdf724
Pull Request #7397: fix(jsonschema/jsonld): force input schema to json format instead of jsonld format

0 of 16 new or added lines in 1 file covered. (0.0%)

11928 existing lines in 393 files now uncovered.

0 of 53912 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/src/JsonSchema/SchemaFactory.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\JsonSchema;
15

16
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
17
use ApiPlatform\Metadata\ApiProperty;
18
use ApiPlatform\Metadata\CollectionOperationInterface;
19
use ApiPlatform\Metadata\HttpOperation;
20
use ApiPlatform\Metadata\Operation;
21
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
22
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
23
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
24
use ApiPlatform\Metadata\ResourceClassResolverInterface;
25
use ApiPlatform\Metadata\Util\TypeHelper;
26
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
27
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
28
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
29
use Symfony\Component\TypeInfo\Type\BuiltinType;
30
use Symfony\Component\TypeInfo\Type\CollectionType;
31
use Symfony\Component\TypeInfo\Type\CompositeTypeInterface;
32
use Symfony\Component\TypeInfo\Type\GenericType;
33
use Symfony\Component\TypeInfo\Type\ObjectType;
34
use Symfony\Component\TypeInfo\TypeIdentifier;
35

36
/**
37
 * {@inheritdoc}
38
 *
39
 * @author Kévin Dunglas <dunglas@gmail.com>
40
 */
41
final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareInterface
42
{
43
    use ResourceMetadataTrait;
44
    use SchemaUriPrefixTrait;
45

46
    private ?SchemaFactoryInterface $schemaFactory = null;
47
    // Edge case where the related resource is not readable (for example: NotExposed) but we have groups to read the whole related object
48
    public const OPENAPI_DEFINITION_NAME = 'openapi_definition_name';
49

50
    public function __construct(ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, private readonly PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, private readonly PropertyMetadataFactoryInterface $propertyMetadataFactory, private readonly ?NameConverterInterface $nameConverter = null, ?ResourceClassResolverInterface $resourceClassResolver = null, ?array $distinctFormats = null, private ?DefinitionNameFactoryInterface $definitionNameFactory = null)
51
    {
UNCOV
52
        if (!$definitionNameFactory) {
×
53
            $this->definitionNameFactory = new DefinitionNameFactory($distinctFormats);
×
54
        }
55

UNCOV
56
        $this->resourceMetadataFactory = $resourceMetadataFactory;
×
UNCOV
57
        $this->resourceClassResolver = $resourceClassResolver;
×
58
    }
59

60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function buildSchema(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?Operation $operation = null, ?Schema $schema = null, ?array $serializerContext = null, bool $forceCollection = false): Schema
64
    {
UNCOV
65
        $schema = $schema ? clone $schema : new Schema();
×
66

UNCOV
67
        if (!$this->isResourceClass($className)) {
×
UNCOV
68
            $operation = null;
×
UNCOV
69
            $inputOrOutputClass = $className;
×
UNCOV
70
            $serializerContext ??= [];
×
71
        } else {
UNCOV
72
            $operation = $this->findOperation($className, $type, $operation, $serializerContext, $format);
×
UNCOV
73
            $inputOrOutputClass = $this->findOutputClass($className, $type, $operation, $serializerContext);
×
UNCOV
74
            $serializerContext ??= $this->getSerializerContext($operation, $type);
×
75
        }
76

UNCOV
77
        if (null === $inputOrOutputClass) {
×
78
            // input or output disabled
79
            return $schema;
×
80
        }
81

UNCOV
82
        $validationGroups = $operation ? $this->getValidationGroups($operation) : [];
×
UNCOV
83
        $version = $schema->getVersion();
×
UNCOV
84
        $definitionName = $this->definitionNameFactory->create($className, $format, $inputOrOutputClass, $operation, $serializerContext);
×
UNCOV
85
        $method = $operation instanceof HttpOperation ? $operation->getMethod() : 'GET';
×
UNCOV
86
        if (!$operation) {
×
UNCOV
87
            $method = Schema::TYPE_INPUT === $type ? 'POST' : 'GET';
×
88
        }
89

90
        // In case of FORCE_SUBSCHEMA an object can be writable through another class even though it has no POST operation
UNCOV
91
        if (!($serializerContext[self::FORCE_SUBSCHEMA] ?? false) && Schema::TYPE_OUTPUT !== $type && !\in_array($method, ['POST', 'PATCH', 'PUT'], true)) {
×
92
            return $schema;
×
93
        }
94

UNCOV
95
        if (!isset($schema['$ref']) && !isset($schema['type'])) {
×
UNCOV
96
            $ref = $this->getSchemaUriPrefix($version).$definitionName;
×
UNCOV
97
            if ($forceCollection || ('POST' !== $method && $operation instanceof CollectionOperationInterface)) {
×
UNCOV
98
                $schema['type'] = 'array';
×
UNCOV
99
                $schema['items'] = ['$ref' => $ref];
×
100
            } else {
UNCOV
101
                $schema['$ref'] = $ref;
×
102
            }
103
        }
104

UNCOV
105
        $definitions = $schema->getDefinitions();
×
UNCOV
106
        if (isset($definitions[$definitionName])) {
×
107
            // Already computed
UNCOV
108
            return $schema;
×
109
        }
110

111
        /** @var \ArrayObject<string, mixed> $definition */
UNCOV
112
        $definition = new \ArrayObject(['type' => 'object']);
×
UNCOV
113
        $definitions[$definitionName] = $definition;
×
UNCOV
114
        if ($description = $operation?->getDescription()) {
×
UNCOV
115
            $definition['description'] = $description;
×
116
        }
117

118
        // additionalProperties are allowed by default, so it does not need to be set explicitly, unless allow_extra_attributes is false
119
        // See https://json-schema.org/understanding-json-schema/reference/object.html#properties
UNCOV
120
        if (false === ($serializerContext[AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES] ?? true)) {
×
121
            $definition['additionalProperties'] = false;
×
122
        }
123

124
        // see https://github.com/json-schema-org/json-schema-spec/pull/737
UNCOV
125
        if (Schema::VERSION_SWAGGER !== $version && $operation && $operation->getDeprecationReason()) {
×
126
            $definition['deprecated'] = true;
×
127
        }
128

129
        // externalDocs is an OpenAPI specific extension, but JSON Schema allows additional keys, so we always add it
130
        // See https://json-schema.org/latest/json-schema-core.html#rfc.section.6.4
UNCOV
131
        if ($operation instanceof HttpOperation && ($operation->getTypes()[0] ?? null)) {
×
UNCOV
132
            $definition['externalDocs'] = ['url' => $operation->getTypes()[0]];
×
133
        }
134

UNCOV
135
        $options = ['schema_type' => $type] + $this->getFactoryOptions($serializerContext, $validationGroups, $operation instanceof HttpOperation ? $operation : null);
×
UNCOV
136
        foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) {
×
UNCOV
137
            $propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options);
×
138

UNCOV
139
            if (false === $propertyMetadata->isReadable() && false === $propertyMetadata->isWritable()) {
×
UNCOV
140
                continue;
×
141
            }
142

UNCOV
143
            $normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName, $inputOrOutputClass, $format, $serializerContext) : $propertyName;
×
UNCOV
144
            if ($propertyMetadata->isRequired()) {
×
UNCOV
145
                $definition['required'][] = $normalizedPropertyName;
×
146
            }
147

UNCOV
148
            if (!method_exists(PropertyInfoExtractor::class, 'getType')) {
×
149
                $this->buildLegacyPropertySchema($schema, $definitionName, $normalizedPropertyName, $propertyMetadata, $serializerContext, $format, $type);
×
150
            } else {
UNCOV
151
                $this->buildPropertySchema($schema, $definitionName, $normalizedPropertyName, $propertyMetadata, $serializerContext, $format, $type);
×
152
            }
153
        }
154

UNCOV
155
        return $schema;
×
156
    }
157

158
    /**
159
     * Builds the JSON Schema for a property using the legacy PropertyInfo component.
160
     */
161
    private function buildLegacyPropertySchema(Schema $schema, string $definitionName, string $normalizedPropertyName, ApiProperty $propertyMetadata, array $serializerContext, string $format, string $parentType): void
162
    {
163
        $version = $schema->getVersion();
×
164
        if (Schema::VERSION_SWAGGER === $version || Schema::VERSION_OPENAPI === $version) {
×
165
            $additionalPropertySchema = $propertyMetadata->getOpenapiContext();
×
166
        } else {
167
            $additionalPropertySchema = $propertyMetadata->getJsonSchemaContext();
×
168
        }
169

170
        $propertySchema = array_merge(
×
171
            $propertyMetadata->getSchema() ?? [],
×
172
            $additionalPropertySchema ?? []
×
173
        );
×
174

175
        // @see https://github.com/api-platform/core/issues/6299
176
        if (Schema::UNKNOWN_TYPE === ($propertySchema['type'] ?? null) && isset($propertySchema['$ref'])) {
×
177
            unset($propertySchema['type']);
×
178
        }
179

180
        $extraProperties = $propertyMetadata->getExtraProperties();
×
181
        // see AttributePropertyMetadataFactory
182
        if (true === ($extraProperties[SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED] ?? false)) {
×
183
            // schema seems to have been declared by the user: do not override nor complete user value
184
            $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
185

186
            return;
×
187
        }
188

189
        $types = $propertyMetadata->getBuiltinTypes() ?? [];
×
190

191
        // never override the following keys if at least one is already set
192
        // or if property has no type(s) defined
193
        // or if property schema is already fully defined (type=string + format || enum)
194
        $propertySchemaType = $propertySchema['type'] ?? false;
×
195

196
        $isUnknown = Schema::UNKNOWN_TYPE === $propertySchemaType
×
197
            || ('array' === $propertySchemaType && Schema::UNKNOWN_TYPE === ($propertySchema['items']['type'] ?? null))
×
198
            || ('object' === $propertySchemaType && Schema::UNKNOWN_TYPE === ($propertySchema['additionalProperties']['type'] ?? null));
×
199

200
        // Scalar properties
201
        if (
202
            !$isUnknown && (
×
203
                [] === $types
×
204
                || ($propertySchema['$ref'] ?? $propertySchema['anyOf'] ?? $propertySchema['allOf'] ?? $propertySchema['oneOf'] ?? false)
×
205
                || (\is_array($propertySchemaType) ? \array_key_exists('string', $propertySchemaType) : 'string' !== $propertySchemaType)
×
206
                || ($propertySchema['format'] ?? $propertySchema['enum'] ?? false)
×
207
            )
208
        ) {
209
            if (isset($propertySchema['$ref'])) {
×
210
                unset($propertySchema['type']);
×
211
            }
212

213
            $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
214

215
            return;
×
216
        }
217

218
        // property schema is created in SchemaPropertyMetadataFactory, but it cannot build resource reference ($ref)
219
        // complete property schema with resource reference ($ref) only if it's related to an object
220
        $version = $schema->getVersion();
×
221
        $refs = [];
×
222
        $isNullable = null;
×
223

224
        foreach ($types as $type) {
×
225
            $subSchema = new Schema($version);
×
226
            $subSchema->setDefinitions($schema->getDefinitions()); // Populate definitions of the main schema
×
227

228
            $isCollection = $type->isCollection();
×
229
            if ($isCollection) {
×
230
                $valueType = $type->getCollectionValueTypes()[0] ?? null;
×
231
            } else {
232
                $valueType = $type;
×
233
            }
234

235
            $className = $valueType?->getClassName();
×
236
            if (null === $className) {
×
237
                continue;
×
238
            }
239

240
            $subSchemaFactory = $this->schemaFactory ?: $this;
×
241
            $subSchema = $subSchemaFactory->buildSchema($className, $format, $parentType, null, $subSchema, $serializerContext + [self::FORCE_SUBSCHEMA => true], false);
×
242
            if (!isset($subSchema['$ref'])) {
×
243
                continue;
×
244
            }
245

246
            if (false === $propertyMetadata->getGenId()) {
×
247
                $subDefinitionName = $this->definitionNameFactory->create($className, $format, $className, null, $serializerContext);
×
248

249
                if (isset($subSchema->getDefinitions()[$subDefinitionName])) {
×
250
                    // @see https://github.com/api-platform/core/issues/7162
251
                    // Need to rebuild the definition without @id property and set it back to the sub-schema
252
                    $subSchemaDefinition = $subSchema->getDefinitions()[$subDefinitionName]->getArrayCopy();
×
253
                    unset($subSchemaDefinition['properties']['@id']);
×
254
                    $subSchema->getDefinitions()[$subDefinitionName] = new \ArrayObject($subSchemaDefinition);
×
255
                }
256
            }
257

258
            if ($isCollection) {
×
259
                $key = ($propertySchema['type'] ?? null) === 'object' ? 'additionalProperties' : 'items';
×
260
                $propertySchema[$key]['$ref'] = $subSchema['$ref'];
×
261
                unset($propertySchema[$key]['type']);
×
262
                break;
×
263
            }
264

265
            $refs[] = ['$ref' => $subSchema['$ref']];
×
266
            $isNullable = $isNullable ?? $type->isNullable();
×
267
        }
268

269
        if ($isNullable) {
×
270
            $refs[] = ['type' => 'null'];
×
271
        }
272

273
        $c = \count($refs);
×
274
        if ($c > 1) {
×
275
            $propertySchema['anyOf'] = $refs;
×
276
            unset($propertySchema['type']);
×
277
        } elseif (1 === $c) {
×
278
            $propertySchema['$ref'] = $refs[0]['$ref'];
×
279
            unset($propertySchema['type']);
×
280
        }
281

282
        $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
283
    }
284

285
    private function buildPropertySchema(Schema $schema, string $definitionName, string $normalizedPropertyName, ApiProperty $propertyMetadata, array $serializerContext, string $format, string $parentType): void
286
    {
UNCOV
287
        $version = $schema->getVersion();
×
UNCOV
288
        if (Schema::VERSION_SWAGGER === $version || Schema::VERSION_OPENAPI === $version) {
×
UNCOV
289
            $additionalPropertySchema = $propertyMetadata->getOpenapiContext();
×
290
        } else {
UNCOV
291
            $additionalPropertySchema = $propertyMetadata->getJsonSchemaContext();
×
292
        }
293

UNCOV
294
        $propertySchema = array_merge(
×
UNCOV
295
            $propertyMetadata->getSchema() ?? [],
×
UNCOV
296
            $additionalPropertySchema ?? []
×
UNCOV
297
        );
×
298

UNCOV
299
        $extraProperties = $propertyMetadata->getExtraProperties();
×
300
        // see AttributePropertyMetadataFactory
UNCOV
301
        if (true === ($extraProperties[SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED] ?? false)) {
×
302
            // schema seems to have been declared by the user: do not override nor complete user value
UNCOV
303
            $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
304

UNCOV
305
            return;
×
306
        }
307

UNCOV
308
        $type = $propertyMetadata->getNativeType();
×
309

310
        // Type is defined in an allOf, anyOf, or oneOf
UNCOV
311
        $propertySchemaType = $this->getSchemaValue($propertySchema, 'type');
×
UNCOV
312
        $currentRef = $this->getSchemaValue($propertySchema, '$ref');
×
UNCOV
313
        $isSchemaDefined = null !== ($currentRef ?? $this->getSchemaValue($propertySchema, 'format') ?? $this->getSchemaValue($propertySchema, 'enum'));
×
UNCOV
314
        if (!$isSchemaDefined && Schema::UNKNOWN_TYPE !== $propertySchemaType) {
×
UNCOV
315
            $isSchemaDefined = true;
×
316
        }
317

318
        // Check if the type is considered "unknown" by SchemaPropertyMetadataFactory
UNCOV
319
        if (isset($propertySchema['additionalProperties']['type']) && Schema::UNKNOWN_TYPE === $propertySchema['additionalProperties']['type']) {
×
UNCOV
320
            $isSchemaDefined = false;
×
321
        }
322

UNCOV
323
        if ($isSchemaDefined && Schema::UNKNOWN_TYPE !== $propertySchemaType) {
×
324
            // If schema is defined and not marked as unknown, or if no type info exists, return early
UNCOV
325
            $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
326

UNCOV
327
            return;
×
328
        }
329

UNCOV
330
        if (Schema::UNKNOWN_TYPE === $propertySchemaType) {
×
UNCOV
331
            $propertySchema = [];
×
332
        }
333

334
        // property schema is created in SchemaPropertyMetadataFactory, but it cannot build resource reference ($ref)
335
        // complete property schema with resource reference ($ref) if it's related to an object/resource
UNCOV
336
        $refs = [];
×
UNCOV
337
        $isNullable = $type?->isNullable() ?? false;
×
338

339
        // TODO: refactor this with TypeInfo we shouldn't have to loop like this, the below code handles object refs
UNCOV
340
        if ($type) {
×
UNCOV
341
            foreach ($type instanceof CompositeTypeInterface ? $type->getTypes() : [$type] as $t) {
×
UNCOV
342
                if ($t instanceof BuiltinType && TypeIdentifier::NULL === $t->getTypeIdentifier()) {
×
UNCOV
343
                    continue;
×
344
                }
345

UNCOV
346
                $valueType = $t;
×
UNCOV
347
                $isCollection = $t instanceof CollectionType;
×
348

UNCOV
349
                if ($isCollection) {
×
UNCOV
350
                    $valueType = TypeHelper::getCollectionValueType($t);
×
351
                }
352

UNCOV
353
                if (!$valueType instanceof ObjectType && !$valueType instanceof GenericType) {
×
354
                    continue;
×
355
                }
356

UNCOV
357
                if ($valueType instanceof ObjectType) {
×
UNCOV
358
                    $className = $valueType->getClassName();
×
359
                } else {
360
                    // GenericType
361
                    $className = $valueType->getWrappedType()->getClassName();
×
362
                }
363

UNCOV
364
                $subSchemaInstance = new Schema($version);
×
UNCOV
365
                $subSchemaInstance->setDefinitions($schema->getDefinitions());
×
UNCOV
366
                $subSchemaFactory = $this->schemaFactory ?: $this;
×
UNCOV
367
                $subSchemaResult = $subSchemaFactory->buildSchema($className, $format, $parentType, null, $subSchemaInstance, $serializerContext + [self::FORCE_SUBSCHEMA => true], false);
×
UNCOV
368
                if (!isset($subSchemaResult['$ref'])) {
×
369
                    continue;
×
370
                }
371

UNCOV
372
                if (false === $propertyMetadata->getGenId()) {
×
UNCOV
373
                    $subDefinitionName = $this->definitionNameFactory->create($className, $format, $className, null, $serializerContext);
×
UNCOV
374
                    if (isset($subSchemaResult->getDefinitions()[$subDefinitionName]['properties']['@id'])) {
×
375
                        unset($subSchemaResult->getDefinitions()[$subDefinitionName]['properties']['@id']);
×
376
                    }
377
                }
378

UNCOV
379
                if ($isCollection) {
×
UNCOV
380
                    $key = ($propertySchema['type'] ?? null) === 'object' ? 'additionalProperties' : 'items';
×
UNCOV
381
                    if (!isset($propertySchema['type'])) {
×
UNCOV
382
                        $propertySchema['type'] = 'array';
×
383
                    }
384

UNCOV
385
                    if (!isset($propertySchema[$key]) || !\is_array($propertySchema[$key])) {
×
UNCOV
386
                        $propertySchema[$key] = [];
×
387
                    }
UNCOV
388
                    $propertySchema[$key] = ['$ref' => $subSchemaResult['$ref']];
×
UNCOV
389
                    $refs = [];
×
UNCOV
390
                    break;
×
391
                }
392

UNCOV
393
                $refs[] = ['$ref' => $subSchemaResult['$ref']];
×
394
            }
395
        }
396

UNCOV
397
        if (!empty($refs)) {
×
UNCOV
398
            if ($isNullable) {
×
UNCOV
399
                $refs[] = ['type' => 'null'];
×
400
            }
401

UNCOV
402
            if (($c = \count($refs)) > 1) {
×
UNCOV
403
                $propertySchema = ['anyOf' => $refs];
×
UNCOV
404
            } elseif (1 === $c) {
×
UNCOV
405
                $propertySchema = ['$ref' => $refs[0]['$ref']];
×
406
            }
407
        }
408

UNCOV
409
        if (null !== $propertyMetadata->getUriTemplate() || (!\array_key_exists('readOnly', $propertySchema) && false === $propertyMetadata->isWritable() && !$propertyMetadata->isInitializable()) && !isset($propertySchema['$ref'])) {
×
UNCOV
410
            $propertySchema['readOnly'] = true;
×
411
        }
412

UNCOV
413
        $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = new \ArrayObject($propertySchema);
×
414
    }
415

416
    private function getValidationGroups(Operation $operation): array
417
    {
UNCOV
418
        $groups = $operation->getValidationContext()['groups'] ?? [];
×
419

UNCOV
420
        return \is_array($groups) ? $groups : [$groups];
×
421
    }
422

423
    /**
424
     * Gets the options for the property name collection / property metadata factories.
425
     */
426
    private function getFactoryOptions(array $serializerContext, array $validationGroups, ?HttpOperation $operation = null): array
427
    {
UNCOV
428
        $options = [
×
429
            /* @see https://github.com/symfony/symfony/blob/v5.1.0/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php */
UNCOV
430
            'enable_getter_setter_extraction' => true,
×
UNCOV
431
        ];
×
432

UNCOV
433
        if (isset($serializerContext[AbstractNormalizer::GROUPS])) {
×
434
            /* @see https://github.com/symfony/symfony/blob/v4.2.6/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php */
UNCOV
435
            $options['serializer_groups'] = (array) $serializerContext[AbstractNormalizer::GROUPS];
×
436
        }
437

UNCOV
438
        if ($operation && ($normalizationGroups = $operation->getNormalizationContext()['groups'] ?? null)) {
×
UNCOV
439
            $options['normalization_groups'] = $normalizationGroups;
×
440
        }
441

UNCOV
442
        if ($operation && ($denormalizationGroups = $operation->getDenormalizationContext()['groups'] ?? null)) {
×
UNCOV
443
            $options['denormalization_groups'] = $denormalizationGroups;
×
444
        }
445

UNCOV
446
        if ($validationGroups) {
×
447
            $options['validation_groups'] = $validationGroups;
×
448
        }
449

UNCOV
450
        if ($operation && ($ignoredAttributes = $operation->getNormalizationContext()['ignored_attributes'] ?? null)) {
×
UNCOV
451
            $options['ignored_attributes'] = $ignoredAttributes;
×
452
        }
453

UNCOV
454
        return $options;
×
455
    }
456

457
    public function setSchemaFactory(SchemaFactoryInterface $schemaFactory): void
458
    {
UNCOV
459
        $this->schemaFactory = $schemaFactory;
×
460
    }
461

462
    private function getSchemaValue(array $schema, string $key): array|string|null
463
    {
UNCOV
464
        if (isset($schema['items'])) {
×
UNCOV
465
            $schema = $schema['items'];
×
466
        }
467

UNCOV
468
        return $schema[$key] ?? $schema['allOf'][0][$key] ?? $schema['anyOf'][0][$key] ?? $schema['oneOf'][0][$key] ?? null;
×
469
    }
470
}
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