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

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

17 Apr 2026 03:57PM UTC coverage: 98.418% (-0.1%) from 98.551%
24574361886

Pull #126

github

Enno Woortmann
Merge remote-tracking branch 'origin/master' into jsonSchemaDraft7

# Conflicts:
#	composer.json
#	src/Model/GeneratorConfiguration.php
Pull Request #126: Json schema draft7

114 of 122 new or added lines in 6 files covered. (93.44%)

6 existing lines in 2 files now uncovered.

4666 of 4741 relevant lines covered (98.42%)

643.77 hits per line

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

98.05
/src/Model/GeneratorConfiguration.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace PHPModelGenerator\Model;
6

7
use Exception;
8
use PHPModelGenerator\Draft\AutoDetectionDraft;
9
use PHPModelGenerator\Draft\DraftFactoryInterface;
10
use PHPModelGenerator\Draft\DraftInterface;
11
use PHPModelGenerator\Exception\ErrorRegistryException;
12
use PHPModelGenerator\Exception\InvalidFilterException;
13
use PHPModelGenerator\Filter\FilterInterface;
14
use PHPModelGenerator\Filter\TransformingFilterInterface;
15
use PHPModelGenerator\Format\FormatValidatorFromRegEx;
16
use PHPModelGenerator\Format\FormatValidatorInterface;
17
use PHPModelGenerator\Format\IriFormatValidator;
18
use PHPModelGenerator\Format\IriReferenceFormatValidator;
19
use PHPModelGenerator\Format\Ipv6FormatValidator;
20
use PHPModelGenerator\Format\RegexFormatValidator;
21
use PHPModelGenerator\Format\UriFormatValidator;
22
use PHPModelGenerator\Format\UriReferenceFormatValidator;
23
use PHPModelGenerator\Format\UriTemplateFormatValidator;
24
use PHPModelGenerator\Model\Attributes\PhpAttribute;
25
use PHPModelGenerator\PropertyProcessor\Filter\DateTimeFilter;
26
use PHPModelGenerator\PropertyProcessor\Filter\NotEmptyFilter;
27
use PHPModelGenerator\PropertyProcessor\Filter\TrimFilter;
28
use PHPModelGenerator\Utils\ClassNameGenerator;
29
use PHPModelGenerator\Utils\ClassNameGeneratorInterface;
30

31
/**
32
 * Class GeneratorConfiguration
33
 *
34
 * @package PHPModelGenerator\Model
35
 */
36
class GeneratorConfiguration
37
{
38
    /** @var string */
39
    protected $namespacePrefix = '';
40
    /** @var bool */
41
    protected $immutable = true;
42
    /** @var bool */
43
    protected $allowImplicitNull = false;
44
    /** @var bool */
45
    protected $defaultArraysToEmptyArray = false;
46
    /** @var bool */
47
    protected $denyAdditionalProperties = false;
48
    /** @var bool */
49
    protected $outputEnabled = true;
50
    /** @var bool */
51
    protected $collectErrors = true;
52
    /** @var string */
53
    protected $errorRegistryClass = ErrorRegistryException::class;
54
    /** @var bool */
55
    protected $serialization = false;
56
    /** @var int */
57
    protected $enabledAttributes = PhpAttribute::JSON_POINTER
58
        | PhpAttribute::SCHEMA_NAME
59
        | PhpAttribute::REQUIRED
60
        | PhpAttribute::READ_WRITE_ONLY
61
        | PhpAttribute::DEPRECATED;
62

63
    /** @var DraftInterface | DraftFactoryInterface */
64
    protected $draft;
65

66
    /** @var ClassNameGeneratorInterface */
67
    protected $classNameGenerator;
68

69
    /** @var FilterInterface[] */
70
    protected $filter;
71
    /** @var FormatValidatorInterface[] */
72
    protected $formats;
73

74
    /**
75
     * GeneratorConfiguration constructor.
76
     */
77
    public function __construct()
2,360✔
78
    {
79
        $this->draft = new AutoDetectionDraft();
2,360✔
80
        $this->classNameGenerator = new ClassNameGenerator();
2,360✔
81

82
        // add all built-in filter and format validators
83
        $this->initFilter();
2,360✔
84
        $this->initFormatValidator();
2,360✔
85
    }
86

87
    /**
88
     * Add an additional filter
89
     *
90
     * @throws Exception
91
     * @throws InvalidFilterException
92
     */
93
    public function addFilter(FilterInterface ...$additionalFilter): self
2,360✔
94
    {
95
        foreach ($additionalFilter as $filter) {
2,360✔
96
            $this->validateFilterCallback(
2,360✔
97
                $filter->getFilter(),
2,360✔
98
                "Invalid filter callback for filter {$filter->getToken()}",
2,360✔
99
            );
2,360✔
100

101
            if ($filter instanceof TransformingFilterInterface) {
2,360✔
102
                $this->validateFilterCallback(
2,360✔
103
                    $filter->getSerializer(),
2,360✔
104
                    "Invalid serializer callback for filter {$filter->getToken()}"
2,360✔
105
                );
2,360✔
106
            }
107

108
            $this->filter[$filter->getToken()] = $filter;
2,360✔
109
        }
110

111
        return $this;
2,360✔
112
    }
113

114
    /**
115
     * Add an additional format
116
     */
117
    public function addFormat(string $formatKey, FormatValidatorInterface $format): self
2,360✔
118
    {
119
        $this->formats[$formatKey] = $format;
2,360✔
120

121
        return $this;
2,360✔
122
    }
123

124
    public function getFormat(string $formatKey): ?FormatValidatorInterface
67✔
125
    {
126
        return $this->formats[$formatKey] ?? null;
67✔
127
    }
128

129
    /**
130
     * @throws InvalidFilterException
131
     */
132
    private function validateFilterCallback(array $callback, string $message): void
2,360✔
133
    {
134
        if (
135
            !(count($callback) === 2) ||
2,360✔
136
            !is_string($callback[0]) ||
2,360✔
137
            !is_string($callback[1]) ||
2,360✔
138
            !is_callable($callback)
2,360✔
139
        ) {
140
            throw new InvalidFilterException($message);
14✔
141
        }
142
    }
143

144
    /**
145
     * Get a filter by the given token
146
     */
147
    public function getFilter(string $token): ?FilterInterface
159✔
148
    {
149
        return $this->filter[$token] ?? null;
159✔
150
    }
151

152
    public function getClassNameGenerator(): ClassNameGeneratorInterface
2,308✔
153
    {
154
        return $this->classNameGenerator;
2,308✔
155
    }
156

157
    public function setClassNameGenerator(ClassNameGeneratorInterface $classNameGenerator): self
2,282✔
158
    {
159
        $this->classNameGenerator = $classNameGenerator;
2,282✔
160

161
        return $this;
2,282✔
162
    }
163

164
    public function getNamespacePrefix(): string
2,208✔
165
    {
166
        return $this->namespacePrefix;
2,208✔
167
    }
168

169
    public function setNamespacePrefix(string $namespacePrefix): self
42✔
170
    {
171
        $this->namespacePrefix = trim($namespacePrefix, '\\');
42✔
172

173
        return $this;
42✔
174
    }
175

176
    public function isDefaultArraysToEmptyArrayEnabled(): bool
538✔
177
    {
178
        return $this->defaultArraysToEmptyArray;
538✔
179
    }
180

181
    public function setDefaultArraysToEmptyArray(bool $defaultArraysToEmptyArray): self
5✔
182
    {
183
        $this->defaultArraysToEmptyArray = $defaultArraysToEmptyArray;
5✔
184

185
        return $this;
5✔
186
    }
187

188
    public function isImmutable(): bool
2,277✔
189
    {
190
        return $this->immutable;
2,277✔
191
    }
192

193
    public function setImmutable(bool $immutable): self
270✔
194
    {
195
        $this->immutable = $immutable;
270✔
196

197
        return $this;
270✔
198
    }
199

200
    public function denyAdditionalProperties(): bool
2,145✔
201
    {
202
        return $this->denyAdditionalProperties;
2,145✔
203
    }
204

205
    public function setDenyAdditionalProperties(bool $denyAdditionalProperties): self
10✔
206
    {
207
        $this->denyAdditionalProperties = $denyAdditionalProperties;
10✔
208

209
        return $this;
10✔
210
    }
211

212
    public function hasSerializationEnabled(): bool
2,309✔
213
    {
214
        return $this->serialization;
2,309✔
215
    }
216

217
    public function setSerialization(bool $serialization): self
59✔
218
    {
219
        $this->serialization = $serialization;
59✔
220

221
        return $this;
59✔
222
    }
223

224
    public function setOutputEnabled(bool $outputEnabled): self
2,311✔
225
    {
226
        $this->outputEnabled = $outputEnabled;
2,311✔
227

228
        return $this;
2,311✔
229
    }
230

231
    public function isOutputEnabled(): bool
2,224✔
232
    {
233
        return $this->outputEnabled;
2,224✔
234
    }
235

236
    public function collectErrors(): bool
2,200✔
237
    {
238
        return $this->collectErrors;
2,200✔
239
    }
240

241
    public function setCollectErrors(bool $collectErrors): self
1,421✔
242
    {
243
        $this->collectErrors = $collectErrors;
1,421✔
244

245
        return $this;
1,421✔
246
    }
247

248
    public function getErrorRegistryClass(): string
620✔
249
    {
250
        return $this->errorRegistryClass;
620✔
251
    }
252

UNCOV
253
    public function setErrorRegistryClass(string $errorRegistryClass): self
×
254
    {
UNCOV
255
        $this->errorRegistryClass = $errorRegistryClass;
×
256

UNCOV
257
        return $this;
×
258
    }
259

260
    public function getDraft(): DraftInterface | DraftFactoryInterface
2,311✔
261
    {
262
        return $this->draft;
2,311✔
263
    }
264

265
    public function setDraft(DraftInterface | DraftFactoryInterface $draft): self
7✔
266
    {
267
        $this->draft = $draft;
7✔
268

269
        return $this;
7✔
270
    }
271

272
    public function isImplicitNullAllowed(): bool
2,269✔
273
    {
274
        return $this->allowImplicitNull;
2,269✔
275
    }
276

277
    public function setImplicitNull(bool $allowImplicitNull): self
2,286✔
278
    {
279
        $this->allowImplicitNull = $allowImplicitNull;
2,286✔
280

281
        return $this;
2,286✔
282
    }
283

284
    private function initFilter(): void
2,360✔
285
    {
286
        $this
2,360✔
287
            ->addFilter(new DateTimeFilter())
2,360✔
288
            ->addFilter(new NotEmptyFilter())
2,360✔
289
            ->addFilter(new TrimFilter());
2,360✔
290
    }
291

292
    public function getEnabledAttributes(): int
2,308✔
293
    {
294
        return $this->enabledAttributes;
2,308✔
295
    }
296

297
    public function setEnabledAttributes(int $enabledAttributes): self
1✔
298
    {
299
        $this->enabledAttributes = $enabledAttributes | PhpAttribute::ALWAYS_ENABLED_ATTRIBUTES;
1✔
300

301
        return $this;
1✔
302
    }
303

304
    public function enableAttributes(int $attributes): self
1✔
305
    {
306
        $this->enabledAttributes = $this->enabledAttributes | $attributes;
1✔
307

308
        return $this;
1✔
309
    }
310

311
    public function disableAttributes(int $attributes): self
1✔
312
    {
313
        $this->enabledAttributes = $this->enabledAttributes & ~$attributes | PhpAttribute::ALWAYS_ENABLED_ATTRIBUTES;
1✔
314

315
        return $this;
1✔
316
    }
317

318
    private function initFormatValidator(): void
2,360✔
319
    {
320
        // RFC 3339 date-time: YYYY-MM-DDTHH:MM:SS with optional fractional seconds and timezone
321
        $this->addFormat(
2,360✔
322
            'date-time',
2,360✔
323
            new FormatValidatorFromRegEx(
2,360✔
324
                '/^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+\-]\d{2}:\d{2})$/',
2,360✔
325
            ),
2,360✔
326
        );
2,360✔
327

328
        // RFC 3339 full-date: YYYY-MM-DD
329
        $this->addFormat(
2,360✔
330
            'date',
2,360✔
331
            new FormatValidatorFromRegEx('/^\d{4}-\d{2}-\d{2}$/'),
2,360✔
332
        );
2,360✔
333

334
        // RFC 3339 full-time: HH:MM:SS with optional fractional seconds and timezone
335
        $this->addFormat(
2,360✔
336
            'time',
2,360✔
337
            new FormatValidatorFromRegEx(
2,360✔
338
                '/^\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+\-]\d{2}:\d{2})$/',
2,360✔
339
            ),
2,360✔
340
        );
2,360✔
341

342
        // RFC 5322 email address (simplified)
343
        $this->addFormat(
2,360✔
344
            'email',
2,360✔
345
            new FormatValidatorFromRegEx('/^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/'),
2,360✔
346
        );
2,360✔
347

348
        // idn-email: internationalized email — same simplified check allowing unicode
349
        $this->addFormat(
2,360✔
350
            'idn-email',
2,360✔
351
            new FormatValidatorFromRegEx('/^[^\s@]+@[^\s@]+\.[^\s@]+$/u'),
2,360✔
352
        );
2,360✔
353

354
        // RFC 1123 hostname
355
        $hostnamePattern = '/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*'
2,360✔
356
            . '[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?$/';
2,360✔
357
        $this->addFormat('hostname', new FormatValidatorFromRegEx($hostnamePattern));
2,360✔
358

359
        // idn-hostname: internationalized hostname — allow unicode labels
360
        $idnHostnamePattern = '/^(?:[a-zA-Z0-9\pL](?:[a-zA-Z0-9\pL\-]{0,61}[a-zA-Z0-9\pL])?\.)*'
2,360✔
361
            . '[a-zA-Z0-9\pL](?:[a-zA-Z0-9\pL\-]{0,61}[a-zA-Z0-9\pL])?$/u';
2,360✔
362
        $this->addFormat('idn-hostname', new FormatValidatorFromRegEx($idnHostnamePattern));
2,360✔
363

364
        // IPv4 address
365
        $this->addFormat(
2,360✔
366
            'ipv4',
2,360✔
367
            new FormatValidatorFromRegEx(
2,360✔
368
                '/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/',
2,360✔
369
            ),
2,360✔
370
        );
2,360✔
371

372
        // RFC 6901 JSON Pointer
373
        $this->addFormat(
2,360✔
374
            'json-pointer',
2,360✔
375
            new FormatValidatorFromRegEx('/^(\/([^~]|~[01])*)*$/'),
2,360✔
376
        );
2,360✔
377

378
        // JSON Schema relative JSON pointer: optional integer prefix + JSON pointer
379
        $this->addFormat(
2,360✔
380
            'relative-json-pointer',
2,360✔
381
            new FormatValidatorFromRegEx('/^\d+(\/([^~]|~[01])*)*$|^\d+#$/'),
2,360✔
382
        );
2,360✔
383

384
        // Class-based validators from the production package
385
        $this->addFormat('ipv6', new Ipv6FormatValidator());
2,360✔
386
        $this->addFormat('uri', new UriFormatValidator());
2,360✔
387
        $this->addFormat('uri-reference', new UriReferenceFormatValidator());
2,360✔
388
        $this->addFormat('uri-template', new UriTemplateFormatValidator());
2,360✔
389
        $this->addFormat('iri', new IriFormatValidator());
2,360✔
390
        $this->addFormat('iri-reference', new IriReferenceFormatValidator());
2,360✔
391
        $this->addFormat('regex', new RegexFormatValidator());
2,360✔
392
    }
393
}
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