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

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

03 Dec 2025 04:23PM UTC coverage: 98.665%. Remained the same
19900971490

push

github

wol-soft
Make code output stable across multiple runs (#41)

2 of 2 new or added lines in 2 files covered. (100.0%)

3399 of 3445 relevant lines covered (98.66%)

566.51 hits per line

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

94.85
/src/Model/Schema.php
1
<?php
2

3
declare(strict_types = 1);
4

5
namespace PHPModelGenerator\Model;
6

7
use PHPModelGenerator\Interfaces\JSONModelInterface;
8
use PHPModelGenerator\Model\Property\PropertyInterface;
9
use PHPModelGenerator\Model\SchemaDefinition\JsonSchema;
10
use PHPModelGenerator\Model\SchemaDefinition\JsonSchemaTrait;
11
use PHPModelGenerator\Model\SchemaDefinition\SchemaDefinitionDictionary;
12
use PHPModelGenerator\Model\Validator\AbstractComposedPropertyValidator;
13
use PHPModelGenerator\Model\Validator\PropertyValidatorInterface;
14
use PHPModelGenerator\Model\Validator\SchemaDependencyValidator;
15
use PHPModelGenerator\PropertyProcessor\Decorator\SchemaNamespaceTransferDecorator;
16
use PHPModelGenerator\SchemaProcessor\Hook\SchemaHookInterface;
17

18
/**
19
 * Class Schema
20
 *
21
 * @package PHPModelGenerator\Model
22
 */
23
class Schema
24
{
25
    use JsonSchemaTrait;
26

27
    /** @var string */
28
    protected $description;
29

30
    /** @var string[] */
31
    protected $traits = [];
32
    /** @var string[] */
33
    protected $interfaces = [];
34
    /** @var PropertyInterface[] The properties which are part of the class */
35
    protected $properties = [];
36
    /** @var MethodInterface[] */
37
    protected $methods = [];
38

39
    /** @var PropertyValidatorInterface[] A Collection of validators which must be applied
40
     *                                    before adding properties to the model
41
     */
42
    protected $baseValidators = [];
43
    /** @var string[] */
44
    protected $usedClasses = [];
45
    /** @var SchemaNamespaceTransferDecorator[] */
46
    protected $namespaceTransferDecorators = [];
47
    /** @var SchemaHookInterface[] */
48
    protected $schemaHooks = [];
49

50
    protected SchemaDefinitionDictionary $schemaDefinitionDictionary;
51

52
    private int $resolvedProperties = 0;
53
    /** @var callable[] */
54
    private array $onAllPropertiesResolvedCallbacks = [];
55

56
    /**
57
     * Schema constructor.
58
     */
59
    public function __construct(
1,984✔
60
        protected string $targetFileName,
61
        protected string $classPath,
62
        protected string $className,
63
        JsonSchema $schema,
64
        ?SchemaDefinitionDictionary $dictionary = null,
65
        protected bool $initialClass = false,
66
    ) {
67
        $this->jsonSchema = $schema;
1,984✔
68
        $this->schemaDefinitionDictionary = $dictionary ?? new SchemaDefinitionDictionary('');
1,984✔
69
        $this->description = $schema->getJson()['description'] ?? '';
1,984✔
70

71
        $this->addInterface(JSONModelInterface::class);
1,984✔
72
    }
73

74
    public function getTargetFileName(): string
1,916✔
75
    {
76
        return $this->targetFileName;
1,916✔
77
    }
78

79
    public function getClassName(): string
1,906✔
80
    {
81
        return $this->className;
1,906✔
82
    }
83

84
    public function getClassPath(): string
1,903✔
85
    {
86
        return $this->classPath;
1,903✔
87
    }
88

89
    public function getDescription(): string
1,901✔
90
    {
91
        return $this->description;
1,901✔
92
    }
93

94
    public function onAllPropertiesResolved(callable $callback): self
294✔
95
    {
96
        $this->resolvedProperties === count($this->properties)
294✔
97
            ? $callback()
294✔
98
            : $this->onAllPropertiesResolvedCallbacks[] = $callback;
×
99

100
        return $this;
294✔
101
    }
102

103
    /**
104
     * @return PropertyInterface[]
105
     */
106
    public function getProperties(): array
1,916✔
107
    {
108
        $hasSchemaDependencyValidator = static function (PropertyInterface $property): bool {
1,916✔
109
            foreach ($property->getValidators() as $validator) {
1,008✔
110
                if ($validator->getValidator() instanceof SchemaDependencyValidator) {
828✔
111
                    return true;
63✔
112
                }
113
            }
114

115
            return false;
1,008✔
116
        };
1,916✔
117

118
        // order the properties to make sure properties with a SchemaDependencyValidator are validated at the beginning
119
        // of the validation process for correct exception order of the messages
120
        usort(
1,916✔
121
            $this->properties,
1,916✔
122
            static function (
1,916✔
123
                PropertyInterface $property,
1,916✔
124
                PropertyInterface $comparedProperty,
1,916✔
125
            ) use ($hasSchemaDependencyValidator): int {
1,916✔
126
                $propertyHasSchemaDependencyValidator = $hasSchemaDependencyValidator($property);
1,008✔
127
                $comparedPropertyHasSchemaDependencyValidator = $hasSchemaDependencyValidator($comparedProperty);
1,008✔
128
                return $comparedPropertyHasSchemaDependencyValidator <=> $propertyHasSchemaDependencyValidator;
1,008✔
129
            },
1,916✔
130
        );
1,916✔
131

132
        return $this->properties;
1,916✔
133
    }
134

135
    public function addProperty(PropertyInterface $property): self
1,887✔
136
    {
137
        if (!isset($this->properties[$property->getName()])) {
1,887✔
138
            $this->properties[$property->getName()] = $property;
1,887✔
139

140
            $property->onResolve(function (): void {
1,887✔
141
                if (++$this->resolvedProperties === count($this->properties)) {
1,843✔
142
                    foreach ($this->onAllPropertiesResolvedCallbacks as $callback) {
1,843✔
143
                        $callback();
×
144

145
                        $this->onAllPropertiesResolvedCallbacks = [];
×
146
                    }
147
                }
148
            });
1,887✔
149
        } else {
150
            // TODO tests:
151
            // testConditionalObjectProperty
152
            // testInvalidConditionalObjectPropertyThrowsAnException
153
            // testInvalidValuesForMultipleValuesInCompositionThrowsAnException
154
          //  throw new SchemaException("Duplicate attribute name {$property->getName()}");
155
        }
156

157
        return $this;
1,887✔
158
    }
159

160
    /**
161
     * @return PropertyValidatorInterface[]
162
     */
163
    public function getBaseValidators(): array
1,916✔
164
    {
165
        return $this->baseValidators;
1,916✔
166
    }
167

168
    /**
169
     * Get the keys of all composition base validators
170
     */
171
    public function getCompositionValidatorKeys(): array
1,901✔
172
    {
173
        $keys = [];
1,901✔
174

175
        foreach ($this->baseValidators as $key => $validator) {
1,901✔
176
            if (is_a($validator, AbstractComposedPropertyValidator::class)) {
514✔
177
                $keys[] = $key;
206✔
178
            }
179
        }
180

181
        return $keys;
1,901✔
182
    }
183

184
    public function addBaseValidator(PropertyValidatorInterface $baseValidator): self
517✔
185
    {
186
        $this->baseValidators[] = $baseValidator;
517✔
187

188
        return $this;
517✔
189
    }
190

191
    public function getSchemaDictionary(): SchemaDefinitionDictionary
1,976✔
192
    {
193
        return $this->schemaDefinitionDictionary;
1,976✔
194
    }
195

196
    /**
197
     * Add a class to the schema which is required
198
     */
199
    public function addUsedClass(string $fqcn): self
1,984✔
200
    {
201
        $this->usedClasses[] = trim($fqcn, '\\');
1,984✔
202

203
        return $this;
1,984✔
204
    }
205

206
    public function addNamespaceTransferDecorator(SchemaNamespaceTransferDecorator $decorator): self
825✔
207
    {
208
        $this->namespaceTransferDecorators[] = $decorator;
825✔
209

210
        return $this;
825✔
211
    }
212

213
    /**
214
     * @param Schema[] $visitedSchema
215
     *
216
     * @return string[]
217
     */
218
    public function getUsedClasses(array $visitedSchema = []): array
1,901✔
219
    {
220
        $usedClasses = $this->usedClasses;
1,901✔
221

222
        foreach ($this->namespaceTransferDecorators as $decorator) {
1,901✔
223
            $usedClasses = array_merge($usedClasses, $decorator->resolve(array_merge($visitedSchema, [$this])));
823✔
224
        }
225

226
        return $usedClasses;
1,901✔
227
    }
228

229
    /**
230
     * @param string $methodKey An unique key in the scope of the schema to identify the method
231
     */
232
    public function addMethod(string $methodKey, MethodInterface $method): self
960✔
233
    {
234
        $this->methods[$methodKey] = $method;
960✔
235

236
        return $this;
960✔
237
    }
238

239
    /**
240
     * @return MethodInterface[]
241
     */
242
    public function getMethods(): array
1,901✔
243
    {
244
        return $this->methods;
1,901✔
245
    }
246

247
    public function hasMethod(string $methodKey): bool
688✔
248
    {
249
        return isset($this->methods[$methodKey]);
688✔
250
    }
251

252
    /**
253
     * @return string[]
254
     */
255
    public function getTraits(): array
1,901✔
256
    {
257
        return $this->traits;
1,901✔
258
    }
259

260
    public function addTrait(string $trait): self
46✔
261
    {
262
        $this->traits[] = $trait;
46✔
263
        $this->addUsedClass($trait);
46✔
264

265
        return $this;
46✔
266
    }
267

268
    /**
269
     * @return string[]
270
     */
271
    public function getInterfaces(): array
1,901✔
272
    {
273
        return $this->interfaces;
1,901✔
274
    }
275

276
    public function addInterface(string $interface): self
1,984✔
277
    {
278
        $this->interfaces[] = $interface;
1,984✔
279
        $this->addUsedClass($interface);
1,984✔
280

281
        return $this;
1,984✔
282
    }
283

284
    /**
285
     * Add an additional schema hook
286
     */
287
    public function addSchemaHook(SchemaHookInterface $schemaHook): self
1,915✔
288
    {
289
        $this->schemaHooks[] = $schemaHook;
1,915✔
290

291
        return $this;
1,915✔
292
    }
293

294
    /**
295
     * @return SchemaHookInterface[]
296
     */
297
    public function getSchemaHooks(): array
1,901✔
298
    {
299
        return $this->schemaHooks;
1,901✔
300
    }
301

302
    public function isInitialClass(): bool
×
303
    {
304
        return $this->initialClass;
×
305
    }
306
}
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