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

wol-soft / php-json-schema-model-generator / 23736478174

30 Mar 2026 08:39AM UTC coverage: 98.332%. First build
23736478174

push

github

Enno Woortmann
Implement Phase 8: eliminate all legacy processor classes; introduce ConstModifier, IntToFloatModifier, NullModifier

- Delete all PropertyProcessor/Property/* classes (AbstractPropertyProcessor,
  AbstractValueProcessor, AbstractTypedValueProcessor, AbstractNumericProcessor,
  StringProcessor, IntegerProcessor, NumberProcessor, BooleanProcessor,
  ArrayProcessor, ObjectProcessor, NullProcessor, AnyProcessor, ConstProcessor,
  ReferenceProcessor, BasereferenceProcessor, BaseProcessor)
- Delete PropertyProcessorFactory and ProcessorFactoryInterface
- Remove ProcessorFactoryInterface constructor parameter from PropertyFactory
- Inline $ref / baseReference routing as private methods on PropertyFactory
- Refactor PropertyFactory::create into focused dispatch + four extracted methods
  (createObjectProperty, createBaseProperty, createTypedProperty, buildProperty)
  with a single unified applyModifiers helper replacing three separate methods
- Add ConstModifier (registered on 'any' type): sets PropertyType from const value
  type and adds InvalidConstException validator; immutability is fully respected
- Add IntToFloatModifier (registered on 'number' type): adds IntToFloatCastDecorator
- Add NullModifier (registered on 'null' type): clears PropertyType and adds TypeHintDecorator
- Register object type in Draft_07 with typeCheck=false (PropertyFactory handles
  object type-check via wireObjectProperty, not via Draft modifier dispatch)
- Remove stale PropertyProcessorFactory imports from validator/schema files
- Add ConstPropertyTest::testConstPropertyHasNoSetterWhenImmutable
- Add docs/source/generator/custom/customDraft.rst: custom draft / modifier guide
- Update setDraft documentation in gettingStarted.rst with seealso link
- Update CLAUDE.md architecture section to document the final Draft modifier system

177 of 178 new or added lines in 16 files covered. (99.44%)

4244 of 4316 relevant lines covered (98.33%)

588.77 hits per line

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

99.24
/src/PropertyProcessor/PropertyFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace PHPModelGenerator\PropertyProcessor;
6

7
use Exception;
8
use PHPModelGenerator\Draft\Draft;
9
use PHPModelGenerator\Draft\DraftFactoryInterface;
10
use PHPModelGenerator\Draft\Modifier\ObjectType\ObjectModifier;
11
use PHPModelGenerator\Draft\Modifier\TypeCheckModifier;
12
use PHPModelGenerator\Exception\SchemaException;
13
use PHPModelGenerator\Model\Property\BaseProperty;
14
use PHPModelGenerator\Model\Property\Property;
15
use PHPModelGenerator\Model\Property\PropertyInterface;
16
use PHPModelGenerator\Model\Property\PropertyType;
17
use PHPModelGenerator\Model\Schema;
18
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
19
use PHPModelGenerator\Model\Validator\MultiTypeCheckValidator;
20
use PHPModelGenerator\Model\Validator\RequiredPropertyValidator;
21
use PHPModelGenerator\Model\Validator\TypeCheckInterface;
22
use PHPModelGenerator\PropertyProcessor\Decorator\Property\PropertyTransferDecorator;
23
use PHPModelGenerator\PropertyProcessor\Decorator\SchemaNamespaceTransferDecorator;
24
use PHPModelGenerator\PropertyProcessor\Decorator\TypeHint\TypeHintDecorator;
25
use PHPModelGenerator\SchemaProcessor\SchemaProcessor;
26
use PHPModelGenerator\Utils\TypeConverter;
27

28
/**
29
 * Class PropertyFactory
30
 *
31
 * @package PHPModelGenerator\PropertyProcessor
32
 */
33
class PropertyFactory
34
{
35
    /** @var Draft[] Keyed by draft class name */
36
    private array $draftCache = [];
37

38
    /**
39
     * Create a property, applying all applicable Draft modifiers.
40
     *
41
     * @throws SchemaException
42
     */
43
    public function create(
2,179✔
44
        SchemaProcessor $schemaProcessor,
45
        Schema $schema,
46
        string $propertyName,
47
        JsonSchema $propertySchema,
48
        bool $required = false,
49
    ): PropertyInterface {
50
        $json = $propertySchema->getJson();
2,179✔
51

52
        // $ref: replace the property entirely via the definition dictionary.
53
        // This is a schema-identity primitive — it cannot be a Draft modifier because
54
        // ModifierInterface::modify returns void and cannot replace the property object.
55
        if (isset($json['$ref'])) {
2,179✔
56
            if (isset($json['type']) && $json['type'] === 'base') {
545✔
57
                return $this->processBaseReference(
41✔
58
                    $schemaProcessor,
41✔
59
                    $schema,
41✔
60
                    $propertyName,
41✔
61
                    $propertySchema,
41✔
62
                    $required,
41✔
63
                );
41✔
64
            }
65

66
            return $this->processReference($schemaProcessor, $schema, $propertyName, $propertySchema, $required);
507✔
67
        }
68

69
        $resolvedType = $json['type'] ?? 'any';
2,179✔
70

71
        if (is_array($resolvedType)) {
2,179✔
72
            return $this->createMultiTypeProperty(
72✔
73
                $schemaProcessor,
72✔
74
                $schema,
72✔
75
                $propertyName,
72✔
76
                $propertySchema,
72✔
77
                $resolvedType,
72✔
78
                $required,
72✔
79
            );
72✔
80
        }
81

82
        $this->checkType($resolvedType, $schema);
2,179✔
83

84
        return match ($resolvedType) {
2,179✔
85
            'object' => $this->createObjectProperty(
952✔
86
                $schemaProcessor,
952✔
87
                $schema,
952✔
88
                $propertyName,
952✔
89
                $propertySchema,
952✔
90
                $required,
952✔
91
            ),
952✔
92
            'base'   => $this->createBaseProperty($schemaProcessor, $schema, $propertyName, $propertySchema),
2,178✔
93
            default  => $this->createTypedProperty(
2,164✔
94
                $schemaProcessor,
2,164✔
95
                $schema,
2,164✔
96
                $propertyName,
2,164✔
97
                $propertySchema,
2,164✔
98
                $resolvedType,
2,164✔
99
                $required,
2,164✔
100
            ),
2,164✔
101
        };
2,179✔
102
    }
103

104
    /**
105
     * Handle a nested object property: generate the nested class, wire the outer property,
106
     * then apply universal modifiers (filter, enum, default, const) on the outer property.
107
     *
108
     * @throws SchemaException
109
     */
110
    private function createObjectProperty(
959✔
111
        SchemaProcessor $schemaProcessor,
112
        Schema $schema,
113
        string $propertyName,
114
        JsonSchema $propertySchema,
115
        bool $required,
116
    ): PropertyInterface {
117
        $json     = $propertySchema->getJson();
959✔
118
        $property = $this->buildProperty($schemaProcessor, $propertyName, null, $propertySchema, $required);
959✔
119

120
        $className = $schemaProcessor->getGeneratorConfiguration()->getClassNameGenerator()->getClassName(
959✔
121
            $propertyName,
959✔
122
            $propertySchema,
959✔
123
            false,
959✔
124
            $schemaProcessor->getCurrentClassName(),
959✔
125
        );
959✔
126

127
        // Strip property-level keywords before passing the schema to processSchema: these keywords
128
        // target the outer property and are handled by the universal modifiers below.
129
        $nestedJson = $json;
959✔
130
        unset($nestedJson['filter'], $nestedJson['enum'], $nestedJson['default']);
959✔
131
        $nestedSchema = $schemaProcessor->processSchema(
959✔
132
            $propertySchema->withJson($nestedJson),
959✔
133
            $schemaProcessor->getCurrentClassPath(),
959✔
134
            $className,
959✔
135
            $schema->getSchemaDictionary(),
959✔
136
        );
959✔
137

138
        if ($nestedSchema !== null) {
959✔
139
            $property->setNestedSchema($nestedSchema);
959✔
140
            $this->wireObjectProperty($schemaProcessor, $schema, $property, $propertySchema);
959✔
141
        }
142

143
        // Universal modifiers (filter, enum, default, const) run on the outer property.
144
        $this->applyModifiers($schemaProcessor, $schema, $property, $propertySchema, anyOnly: true);
959✔
145

146
        return $property;
957✔
147
    }
148

149
    /**
150
     * Handle a root-level schema (type=base): set up definitions, run all Draft modifiers,
151
     * then transfer any composed properties to the schema.
152
     *
153
     * @throws SchemaException
154
     */
155
    private function createBaseProperty(
2,178✔
156
        SchemaProcessor $schemaProcessor,
157
        Schema $schema,
158
        string $propertyName,
159
        JsonSchema $propertySchema,
160
    ): PropertyInterface {
161
        $schema->getSchemaDictionary()->setUpDefinitionDictionary($schemaProcessor, $schema);
2,178✔
162
        $property = new BaseProperty($propertyName, new PropertyType('object'), $propertySchema);
2,178✔
163

164
        $objectJson         = $propertySchema->getJson();
2,178✔
165
        $objectJson['type'] = 'object';
2,178✔
166
        $this->applyModifiers($schemaProcessor, $schema, $property, $propertySchema->withJson($objectJson));
2,178✔
167

168
        $schemaProcessor->transferComposedPropertiesToSchema($property, $schema);
2,119✔
169

170
        return $property;
2,118✔
171
    }
172

173
    /**
174
     * Handle scalar, array, and untyped properties: construct directly and run all Draft modifiers.
175
     *
176
     * @throws SchemaException
177
     */
178
    private function createTypedProperty(
2,109✔
179
        SchemaProcessor $schemaProcessor,
180
        Schema $schema,
181
        string $propertyName,
182
        JsonSchema $propertySchema,
183
        string $type,
184
        bool $required,
185
    ): PropertyInterface {
186
        $phpType  = $type !== 'any' ? TypeConverter::jsonSchemaToPhp($type) : null;
2,109✔
187
        $property = $this->buildProperty(
2,109✔
188
            $schemaProcessor,
2,109✔
189
            $propertyName,
2,109✔
190
            $phpType !== null ? new PropertyType($phpType) : null,
2,109✔
191
            $propertySchema,
2,109✔
192
            $required,
2,109✔
193
        );
2,109✔
194

195
        $this->applyModifiers($schemaProcessor, $schema, $property, $propertySchema);
2,108✔
196

197
        return $property;
2,066✔
198
    }
199

200
    /**
201
     * Construct a Property with the common required/readOnly setup.
202
     */
203
    private function buildProperty(
2,152✔
204
        SchemaProcessor $schemaProcessor,
205
        string $propertyName,
206
        ?PropertyType $type,
207
        JsonSchema $propertySchema,
208
        bool $required,
209
    ): Property {
210
        $json = $propertySchema->getJson();
2,152✔
211

212
        $property = (new Property($propertyName, $type, $propertySchema, $json['description'] ?? ''))
2,152✔
213
            ->setRequired($required)
2,152✔
214
            ->setReadOnly(
2,152✔
215
                (isset($json['readOnly']) && $json['readOnly'] === true) ||
2,152✔
216
                $schemaProcessor->getGeneratorConfiguration()->isImmutable(),
2,152✔
217
            );
2,152✔
218

219
        if ($required && !str_starts_with($propertyName, 'item of array ')) {
2,151✔
220
            $property->addValidator(new RequiredPropertyValidator($property), 1);
1,067✔
221
        }
222

223
        return $property;
2,151✔
224
    }
225

226
    /**
227
     * Resolve a $ref reference by looking it up in the definition dictionary.
228
     *
229
     * @throws SchemaException
230
     */
231
    private function processReference(
545✔
232
        SchemaProcessor $schemaProcessor,
233
        Schema $schema,
234
        string $propertyName,
235
        JsonSchema $propertySchema,
236
        bool $required,
237
    ): PropertyInterface {
238
        $path       = [];
545✔
239
        $reference  = $propertySchema->getJson()['$ref'];
545✔
240
        $dictionary = $schema->getSchemaDictionary();
545✔
241

242
        try {
243
            $definition = $dictionary->getDefinition($reference, $schemaProcessor, $path);
545✔
244

245
            if ($definition) {
538✔
246
                $definitionSchema = $definition->getSchema();
538✔
247

248
                if (
249
                    $schema->getClassPath() !== $definitionSchema->getClassPath() ||
538✔
250
                    $schema->getClassName() !== $definitionSchema->getClassName() ||
537✔
251
                    (
252
                        $schema->getClassName() === 'ExternalSchema' &&
538✔
253
                        $definitionSchema->getClassName() === 'ExternalSchema'
538✔
254
                    )
255
                ) {
256
                    $schema->addNamespaceTransferDecorator(
259✔
257
                        new SchemaNamespaceTransferDecorator($definitionSchema),
259✔
258
                    );
259✔
259

260
                    if ($definitionSchema->getClassName() !== 'ExternalSchema') {
259✔
261
                        $schema->addUsedClass(join('\\', array_filter([
72✔
262
                            $schemaProcessor->getGeneratorConfiguration()->getNamespacePrefix(),
72✔
263
                            $definitionSchema->getClassPath(),
72✔
264
                            $definitionSchema->getClassName(),
72✔
265
                        ])));
72✔
266
                    }
267
                }
268

269
                return $definition->resolveReference(
538✔
270
                    $propertyName,
538✔
271
                    $path,
538✔
272
                    $required,
538✔
273
                    $propertySchema->getJson()['_dependencies'] ?? null,
538✔
274
                );
538✔
275
            }
276
        } catch (Exception $exception) {
7✔
277
            throw new SchemaException(
7✔
278
                "Unresolved Reference $reference in file {$propertySchema->getFile()}",
7✔
279
                0,
7✔
280
                $exception,
7✔
281
            );
7✔
282
        }
283

NEW
284
        throw new SchemaException("Unresolved Reference $reference in file {$propertySchema->getFile()}");
×
285
    }
286

287
    /**
288
     * Resolve a $ref on a base-level schema: set up definitions, delegate to processReference,
289
     * then copy the referenced schema's properties to the parent schema.
290
     *
291
     * @throws SchemaException
292
     */
293
    private function processBaseReference(
41✔
294
        SchemaProcessor $schemaProcessor,
295
        Schema $schema,
296
        string $propertyName,
297
        JsonSchema $propertySchema,
298
        bool $required,
299
    ): PropertyInterface {
300
        $schema->getSchemaDictionary()->setUpDefinitionDictionary($schemaProcessor, $schema);
41✔
301

302
        $property = $this->processReference($schemaProcessor, $schema, $propertyName, $propertySchema, $required);
41✔
303

304
        if (!$property->getNestedSchema()) {
41✔
305
            throw new SchemaException(
1✔
306
                sprintf(
1✔
307
                    'A referenced schema on base level must provide an object definition for property %s in file %s',
1✔
308
                    $propertyName,
1✔
309
                    $propertySchema->getFile(),
1✔
310
                )
1✔
311
            );
1✔
312
        }
313

314
        foreach ($property->getNestedSchema()->getProperties() as $propertiesOfReferencedObject) {
40✔
315
            $schema->addProperty($propertiesOfReferencedObject);
40✔
316
        }
317

318
        return $property;
40✔
319
    }
320

321
    /**
322
     * Handle "type": [...] properties by processing each type through its Draft modifiers,
323
     * merging validators and decorators onto a single property, then consolidating type checks.
324
     *
325
     * @param string[] $types
326
     *
327
     * @throws SchemaException
328
     */
329
    private function createMultiTypeProperty(
72✔
330
        SchemaProcessor $schemaProcessor,
331
        Schema $schema,
332
        string $propertyName,
333
        JsonSchema $propertySchema,
334
        array $types,
335
        bool $required,
336
    ): PropertyInterface {
337
        $json     = $propertySchema->getJson();
72✔
338
        $property = $this->buildProperty($schemaProcessor, $propertyName, null, $propertySchema, $required);
72✔
339

340
        $collectedTypes   = [];
72✔
341
        $typeHints        = [];
72✔
342
        $resolvedSubCount = 0;
72✔
343
        $totalSubCount    = count($types);
72✔
344

345
        // Strip the default from sub-schemas so that default handling runs only once via the
346
        // universal DefaultValueModifier below, which already handles the multi-type case.
347
        $subJson = $json;
72✔
348
        unset($subJson['default']);
72✔
349

350
        foreach ($types as $type) {
72✔
351
            $this->checkType($type, $schema);
72✔
352

353
            $subJson['type'] = $type;
72✔
354
            $subSchema       = $propertySchema->withJson($subJson);
72✔
355

356
            // For type=object, delegate to the same object path (processSchema + wireObjectProperty).
357
            $subProperty = $type === 'object'
72✔
358
                ? $this->createObjectProperty($schemaProcessor, $schema, $propertyName, $subSchema, $required)
7✔
359
                : $this->createSubTypeProperty(
72✔
360
                    $schemaProcessor,
72✔
361
                    $schema,
72✔
362
                    $propertyName,
72✔
363
                    $subSchema,
72✔
364
                    $type,
72✔
365
                    $required,
72✔
366
                    $json,
72✔
367
                );
72✔
368

369
            $subProperty->onResolve(function () use (
72✔
370
                $property,
72✔
371
                $subProperty,
72✔
372
                $schemaProcessor,
72✔
373
                $schema,
72✔
374
                $propertySchema,
72✔
375
                $totalSubCount,
72✔
376
                &$collectedTypes,
72✔
377
                &$typeHints,
72✔
378
                &$resolvedSubCount,
72✔
379
            ): void {
72✔
380
                foreach ($subProperty->getValidators() as $validatorContainer) {
72✔
381
                    $validator = $validatorContainer->getValidator();
72✔
382

383
                    if ($validator instanceof TypeCheckInterface) {
72✔
384
                        array_push($collectedTypes, ...$validator->getTypes());
72✔
385
                        continue;
72✔
386
                    }
387

388
                    $property->addValidator($validator, $validatorContainer->getPriority());
43✔
389
                }
390

391
                if ($subProperty->getDecorators()) {
72✔
392
                    $property->addDecorator(new PropertyTransferDecorator($subProperty));
33✔
393
                }
394

395
                $typeHints[] = $subProperty->getTypeHint();
72✔
396

397
                if (++$resolvedSubCount < $totalSubCount || empty($collectedTypes)) {
72✔
398
                    return;
72✔
399
                }
400

401
                $this->finalizeMultiTypeProperty(
72✔
402
                    $property,
72✔
403
                    array_unique($collectedTypes),
72✔
404
                    $typeHints,
72✔
405
                    $schemaProcessor,
72✔
406
                    $schema,
72✔
407
                    $propertySchema,
72✔
408
                );
72✔
409
            });
72✔
410
        }
411

412
        return $property;
68✔
413
    }
414

415
    /**
416
     * Build a non-object sub-property for a multi-type array, applying only type-specific
417
     * modifiers (no universal 'any' modifiers — those run once on the parent after finalization).
418
     *
419
     * @throws SchemaException
420
     */
421
    private function createSubTypeProperty(
72✔
422
        SchemaProcessor $schemaProcessor,
423
        Schema $schema,
424
        string $propertyName,
425
        JsonSchema $propertySchema,
426
        string $type,
427
        bool $required,
428
        array $parentJson,
429
    ): Property {
430
        $subProperty = $this->buildProperty(
72✔
431
            $schemaProcessor,
72✔
432
            $propertyName,
72✔
433
            new PropertyType(TypeConverter::jsonSchemaToPhp($type)),
72✔
434
            $propertySchema,
72✔
435
            $required,
72✔
436
        );
72✔
437

438
        $this->applyModifiers($schemaProcessor, $schema, $subProperty, $propertySchema, anyOnly: false, typeOnly: true);
72✔
439

440
        return $subProperty;
72✔
441
    }
442

443
    /**
444
     * Called once all sub-properties of a multi-type property have resolved.
445
     * Adds the consolidated MultiTypeCheckValidator, sets the union PropertyType,
446
     * attaches the type-hint decorator, and runs universal modifiers.
447
     *
448
     * @param string[] $collectedTypes
449
     * @param string[] $typeHints
450
     *
451
     * @throws SchemaException
452
     */
453
    private function finalizeMultiTypeProperty(
72✔
454
        PropertyInterface $property,
455
        array $collectedTypes,
456
        array $typeHints,
457
        SchemaProcessor $schemaProcessor,
458
        Schema $schema,
459
        JsonSchema $propertySchema,
460
    ): void {
461
        $hasNull      = in_array('null', $collectedTypes, true);
72✔
462
        $nonNullTypes = array_values(array_filter(
72✔
463
            $collectedTypes,
72✔
464
            static fn(string $t): bool => $t !== 'null',
72✔
465
        ));
72✔
466

467
        $allowImplicitNull = $schemaProcessor->getGeneratorConfiguration()->isImplicitNullAllowed()
72✔
468
            && !$property->isRequired();
72✔
469

470
        $property->addValidator(
72✔
471
            new MultiTypeCheckValidator($collectedTypes, $property, $allowImplicitNull),
72✔
472
            2,
72✔
473
        );
72✔
474

475
        if ($nonNullTypes) {
72✔
476
            $property->setType(
72✔
477
                new PropertyType($nonNullTypes, $hasNull ? true : null),
72✔
478
                new PropertyType($nonNullTypes, $hasNull ? true : null),
72✔
479
            );
72✔
480
        }
481

482
        $property->addTypeHintDecorator(new TypeHintDecorator($typeHints));
72✔
483

484
        $this->applyModifiers($schemaProcessor, $schema, $property, $propertySchema, anyOnly: true);
72✔
485
    }
486

487
    /**
488
     * Wire the outer property for a nested object: add the type-check validator and instantiation
489
     * linkage. Schema-targeting modifiers are intentionally NOT run here because processSchema
490
     * already applied them to the nested schema.
491
     *
492
     * @throws SchemaException
493
     */
494
    private function wireObjectProperty(
959✔
495
        SchemaProcessor $schemaProcessor,
496
        Schema $schema,
497
        PropertyInterface $property,
498
        JsonSchema $propertySchema,
499
    ): void {
500
        (new TypeCheckModifier(TypeConverter::jsonSchemaToPhp('object')))->modify(
959✔
501
            $schemaProcessor,
959✔
502
            $schema,
959✔
503
            $property,
959✔
504
            $propertySchema,
959✔
505
        );
959✔
506

507
        (new ObjectModifier())->modify($schemaProcessor, $schema, $property, $propertySchema);
959✔
508
    }
509

510
    /**
511
     * Run Draft modifiers for the given property.
512
     *
513
     * By default all covered types (type-specific + 'any') run. Pass $anyOnly=true to run
514
     * only the 'any' entry (used for object outer-property universal keywords), or $typeOnly=true
515
     * to run only type-specific entries (used for multi-type sub-properties).
516
     *
517
     * @throws SchemaException
518
     */
519
    private function applyModifiers(
2,179✔
520
        SchemaProcessor $schemaProcessor,
521
        Schema $schema,
522
        PropertyInterface $property,
523
        JsonSchema $propertySchema,
524
        bool $anyOnly = false,
525
        bool $typeOnly = false,
526
    ): void {
527
        $type       = $propertySchema->getJson()['type'] ?? 'any';
2,179✔
528
        $builtDraft = $this->resolveBuiltDraft($schemaProcessor, $propertySchema);
2,179✔
529

530
        // For untyped properties ('any'), only run the 'any' entry — getCoveredTypes('any')
531
        // returns all types, which would incorrectly apply type-specific modifiers.
532
        $coveredTypes = $type === 'any'
2,179✔
533
            ? array_filter($builtDraft->getCoveredTypes('any'), static fn($t) => $t->getType() === 'any')
557✔
534
            : $builtDraft->getCoveredTypes($type);
2,179✔
535

536
        foreach ($coveredTypes as $coveredType) {
2,179✔
537
            $isAnyEntry = $coveredType->getType() === 'any';
2,179✔
538

539
            if ($anyOnly && !$isAnyEntry) {
2,179✔
540
                continue;
1,017✔
541
            }
542

543
            if ($typeOnly && $isAnyEntry) {
2,179✔
544
                continue;
72✔
545
            }
546

547
            foreach ($coveredType->getModifiers() as $modifier) {
2,179✔
548
                $modifier->modify($schemaProcessor, $schema, $property, $propertySchema);
2,179✔
549
            }
550
        }
551
    }
552

553
    /**
554
     * @throws SchemaException
555
     */
556
    private function checkType(mixed $type, Schema $schema): void
2,179✔
557
    {
558
        if (is_string($type)) {
2,179✔
559
            return;
2,179✔
560
        }
561

562
        throw new SchemaException(
1✔
563
            sprintf(
1✔
564
                'Invalid property type %s in file %s',
1✔
565
                $type,
1✔
566
                $schema->getJsonSchema()->getFile(),
1✔
567
            )
1✔
568
        );
1✔
569
    }
570

571
    private function resolveBuiltDraft(SchemaProcessor $schemaProcessor, JsonSchema $propertySchema): Draft
2,179✔
572
    {
573
        $configDraft = $schemaProcessor->getGeneratorConfiguration()->getDraft();
2,179✔
574

575
        $draft = $configDraft instanceof DraftFactoryInterface
2,179✔
576
            ? $configDraft->getDraftForSchema($propertySchema)
2,179✔
577
            : $configDraft;
×
578

579
        return $this->draftCache[$draft::class] ??= $draft->getDefinition()->build();
2,179✔
580
    }
581
}
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

© 2026 Coveralls, Inc