Completed
Pull Request — master (#1320)
by
unknown
03:30 queued 13s
created

SerializerBuilder::setAnnotationReader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
rs 10
ccs 4
cts 4
cp 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace JMS\Serializer;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\CachedReader;
9
use Doctrine\Common\Annotations\Reader;
10
use Doctrine\Common\Cache\FilesystemCache;
11
use JMS\Serializer\Accessor\AccessorStrategyInterface;
12
use JMS\Serializer\Accessor\DefaultAccessorStrategy;
13
use JMS\Serializer\Builder\DefaultDriverFactory;
14
use JMS\Serializer\Builder\DocBlockDriverFactory;
15
use JMS\Serializer\Builder\DriverFactoryInterface;
16
use JMS\Serializer\Construction\ObjectConstructorInterface;
17
use JMS\Serializer\Construction\UnserializeObjectConstructor;
18
use JMS\Serializer\ContextFactory\CallableDeserializationContextFactory;
19
use JMS\Serializer\ContextFactory\CallableSerializationContextFactory;
20
use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
21
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
22
use JMS\Serializer\EventDispatcher\EventDispatcher;
23
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
24
use JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber;
25
use JMS\Serializer\Exception\InvalidArgumentException;
26
use JMS\Serializer\Exception\RuntimeException;
27
use JMS\Serializer\Expression\CompilableExpressionEvaluatorInterface;
28
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
29
use JMS\Serializer\GraphNavigator\Factory\DeserializationGraphNavigatorFactory;
30
use JMS\Serializer\GraphNavigator\Factory\GraphNavigatorFactoryInterface;
31
use JMS\Serializer\GraphNavigator\Factory\SerializationGraphNavigatorFactory;
32
use JMS\Serializer\Handler\ArrayCollectionHandler;
33
use JMS\Serializer\Handler\DateHandler;
34
use JMS\Serializer\Handler\HandlerRegistry;
35
use JMS\Serializer\Handler\HandlerRegistryInterface;
36
use JMS\Serializer\Handler\IteratorHandler;
37
use JMS\Serializer\Handler\StdClassHandler;
38
use JMS\Serializer\Naming\CamelCaseNamingStrategy;
39
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
40
use JMS\Serializer\Naming\SerializedNameAnnotationStrategy;
41
use JMS\Serializer\Type\Parser;
42
use JMS\Serializer\Type\ParserInterface;
43
use JMS\Serializer\Visitor\Factory\DeserializationVisitorFactory;
44
use JMS\Serializer\Visitor\Factory\JsonDeserializationVisitorFactory;
45
use JMS\Serializer\Visitor\Factory\JsonSerializationVisitorFactory;
46
use JMS\Serializer\Visitor\Factory\SerializationVisitorFactory;
47
use JMS\Serializer\Visitor\Factory\XmlDeserializationVisitorFactory;
48
use JMS\Serializer\Visitor\Factory\XmlSerializationVisitorFactory;
49
use Metadata\Cache\CacheInterface;
50
use Metadata\Cache\FileCache;
51
use Metadata\MetadataFactory;
52
use Metadata\MetadataFactoryInterface;
53
54
/**
55
 * Builder for serializer instances.
56
 *
57
 * This object makes serializer construction a breeze for projects that do not use
58
 * any special dependency injection container.
59
 *
60
 * @author Johannes M. Schmitt <[email protected]>
61
 */
62
final class SerializerBuilder
63
{
64
    /**
65
     * @var string[]
66
     */
67
    private $metadataDirs = [];
68
69
    /**
70
     * @var HandlerRegistryInterface
71
     */
72
    private $handlerRegistry;
73
74
    /**
75
     * @var bool
76
     */
77
    private $handlersConfigured = false;
78
79
    /**
80
     * @var EventDispatcherInterface
81
     */
82
    private $eventDispatcher;
83
84
    /**
85
     * @var bool
86
     */
87
    private $enableAttributes = false;
88
89
    /**
90
     * @var bool
91
     */
92
    private $listenersConfigured = false;
93
94
    /**
95
     * @var ObjectConstructorInterface
96 330
     */
97
    private $objectConstructor;
98 330
99
    /**
100
     * @var SerializationVisitorFactory[]
101 330
     */
102
    private $serializationVisitors;
103 330
104 330
    /**
105 330
     * @var DeserializationVisitorFactory[]
106 330
     */
107 330
    private $deserializationVisitors;
108
109 330
    /**
110 284
     * @var bool
111
     */
112 330
    private $visitorsAdded = false;
113 284
114
    /**
115 330
     * @var PropertyNamingStrategyInterface
116
     */
117
    private $propertyNamingStrategy;
118
119
    /**
120
     * @var bool
121
     */
122
    private $debug = false;
123 330
124
    /**
125 330
     * @var string
126 330
     */
127
    private $cacheDir;
128 330
129
    /**
130
     * @var AnnotationReader
131 25
     */
132
    private $annotationReader;
133 25
134
    /**
135 25
     * @var bool
136
     */
137
    private $includeInterfaceMetadata = false;
138 1
139
    /**
140 1
     * @var DriverFactoryInterface
141
     */
142 1
    private $driverFactory;
143
144
    /**
145
     * @var SerializationContextFactoryInterface
146
     */
147
    private $serializationContextFactory;
148
149
    /**
150
     * @var DeserializationContextFactoryInterface
151
     */
152
    private $deserializationContextFactory;
153
154
    /**
155
     * @var ParserInterface
156
     */
157
    private $typeParser;
158
159 1
    /**
160
     * @var ExpressionEvaluatorInterface
161 1
     */
162 1
    private $expressionEvaluator;
163
164 1
    /**
165
     * @var AccessorStrategyInterface
166
     */
167
    private $accessorStrategy;
168 1
169
    /**
170 1
     * @var CacheInterface
171
     */
172
    private $metadataCache;
173 71
174
    /**
175 71
     * @var bool
176 71
     */
177 71
    private $docBlockTyperResolver;
178 71
179
    /**
180 71
     * @param mixed ...$args
181
     *
182
     * @return SerializerBuilder
183 3
     */
184
    public static function create(...$args): self
185 3
    {
186 3
        return new static(...$args);
0 ignored issues
show
Bug introduced by
$args is expanded, but the parameter $handlerRegistry of JMS\Serializer\SerializerBuilder::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

186
        return new static(/** @scrutinizer ignore-type */ ...$args);
Loading history...
187
    }
188 3
189
    public function __construct(?HandlerRegistryInterface $handlerRegistry = null, ?EventDispatcherInterface $eventDispatcher = null, bool $enableAttributes = false)
190
    {
191 73
        $this->typeParser = new Parser();
192
        $this->handlerRegistry = $handlerRegistry ?: new HandlerRegistry();
193 73
        $this->eventDispatcher = $eventDispatcher ?: new EventDispatcher();
194 73
        $this->serializationVisitors = [];
195
        $this->deserializationVisitors = [];
196 73
        $this->enableAttributes = $enableAttributes;
197
198
        if ($handlerRegistry) {
199 1
            $this->handlersConfigured = true;
200
        }
201 1
202 1
        if ($eventDispatcher) {
203
            $this->listenersConfigured = true;
204 1
        }
205
    }
206
207 4
    public function setAccessorStrategy(AccessorStrategyInterface $accessorStrategy): self
208
    {
209 4
        $this->accessorStrategy = $accessorStrategy;
210
211 4
        return $this;
212
    }
213
214
    private function getAccessorStrategy(): AccessorStrategyInterface
215
    {
216
        if (!$this->accessorStrategy) {
217
            $this->accessorStrategy = new DefaultAccessorStrategy($this->expressionEvaluator);
218
        }
219
220
        return $this->accessorStrategy;
221 2
    }
222
223 2
    public function setExpressionEvaluator(ExpressionEvaluatorInterface $expressionEvaluator): self
224 2
    {
225
        $this->expressionEvaluator = $expressionEvaluator;
226 2
227
        return $this;
228
    }
229
230
    public function setTypeParser(ParserInterface $parser): self
231
    {
232
        $this->typeParser = $parser;
233
234
        return $this;
235
    }
236
237 329
    public function setAnnotationReader(Reader $reader): self
238
    {
239 329
        $this->annotationReader = $reader;
0 ignored issues
show
Documentation Bug introduced by
$reader is of type Doctrine\Common\Annotations\Reader, but the property $annotationReader was declared to be of type Doctrine\Common\Annotations\AnnotationReader. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
240 329
241 329
        return $this;
242 329
    }
243
244
    public function setDebug(bool $bool): self
245 329
    {
246
        $this->debug = $bool;
247
248 329
        return $this;
249
    }
250 329
251 329
    public function setCacheDir(string $dir): self
252 329
    {
253 329
        if (!is_dir($dir)) {
254
            $this->createDir($dir);
255
        }
256 329
257
        if (!is_writable($dir)) {
258
            throw new InvalidArgumentException(sprintf('The cache directory "%s" is not writable.', $dir));
259
        }
260
261
        $this->cacheDir = $dir;
262
263
        return $this;
264 1
    }
265
266 1
    public function addDefaultHandlers(): self
267
    {
268 1
        $this->handlersConfigured = true;
269
        $this->handlerRegistry->registerSubscribingHandler(new DateHandler());
270
        $this->handlerRegistry->registerSubscribingHandler(new StdClassHandler());
271
        $this->handlerRegistry->registerSubscribingHandler(new ArrayCollectionHandler());
272
        $this->handlerRegistry->registerSubscribingHandler(new IteratorHandler());
273
274
        return $this;
275
    }
276
277
    public function configureHandlers(\Closure $closure): self
278
    {
279
        $this->handlersConfigured = true;
280
        $closure($this->handlerRegistry);
281
282 2
        return $this;
283
    }
284 2
285 2
    public function addDefaultListeners(): self
286 2
    {
287
        $this->listenersConfigured = true;
288
        $this->eventDispatcher->addSubscriber(new DoctrineProxySubscriber());
289
290 2
        return $this;
291
    }
292 2
293
    public function configureListeners(\Closure $closure): self
294
    {
295
        $this->listenersConfigured = true;
296
        $closure($this->eventDispatcher);
297
298
        return $this;
299
    }
300
301
    public function setObjectConstructor(ObjectConstructorInterface $constructor): self
302
    {
303
        $this->objectConstructor = $constructor;
304
305
        return $this;
306
    }
307
308
    public function setPropertyNamingStrategy(PropertyNamingStrategyInterface $propertyNamingStrategy): self
309
    {
310
        $this->propertyNamingStrategy = $propertyNamingStrategy;
311
312
        return $this;
313
    }
314
315
    public function setSerializationVisitor(string $format, SerializationVisitorFactory $visitor): self
316
    {
317
        $this->visitorsAdded = true;
318
        $this->serializationVisitors[$format] = $visitor;
319
320
        return $this;
321
    }
322
323
    public function setDeserializationVisitor(string $format, DeserializationVisitorFactory $visitor): self
324
    {
325
        $this->visitorsAdded = true;
326
        $this->deserializationVisitors[$format] = $visitor;
327
328
        return $this;
329
    }
330
331
    public function addDefaultSerializationVisitors(): self
332
    {
333
        $this->visitorsAdded = true;
334
        $this->serializationVisitors = [
335
            'xml' => new XmlSerializationVisitorFactory(),
336
            'json' => new JsonSerializationVisitorFactory(),
337
        ];
338
339
        return $this;
340
    }
341
342
    public function addDefaultDeserializationVisitors(): self
343
    {
344
        $this->visitorsAdded = true;
345
        $this->deserializationVisitors = [
346
            'xml' => new XmlDeserializationVisitorFactory(),
347
            'json' => new JsonDeserializationVisitorFactory(),
348
        ];
349
350
        return $this;
351
    }
352
353
    /**
354
     * @param bool $include Whether to include the metadata from the interfaces
355
     *
356
     * @return SerializerBuilder
357
     */
358
    public function includeInterfaceMetadata(bool $include): self
359
    {
360
        $this->includeInterfaceMetadata = $include;
361
362
        return $this;
363
    }
364
365
    /**
366
     * Sets a map of namespace prefixes to directories.
367
     *
368
     * This method overrides any previously defined directories.
369
     *
370
     * @param array <string,string> $namespacePrefixToDirMap
0 ignored issues
show
Documentation Bug introduced by
The doc comment <string,string> at position 0 could not be parsed: Unknown type name '<' at position 0 in <string,string>.
Loading history...
371
     *
372
     * @return SerializerBuilder
373
     *
374
     * @throws InvalidArgumentException When a directory does not exist.
375
     */
376
    public function setMetadataDirs(array $namespacePrefixToDirMap): self
377
    {
378 13
        foreach ($namespacePrefixToDirMap as $dir) {
379
            if (!is_dir($dir)) {
380 13
                throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
381
            }
382 13
        }
383
384
        $this->metadataDirs = $namespacePrefixToDirMap;
385
386
        return $this;
387
    }
388
389
    /**
390 5
     * Adds a directory where the serializer will look for class metadata.
391
     *
392 5
     * The namespace prefix will make the names of the actual metadata files a bit shorter. For example, let's assume
393 3
     * that you have a directory where you only store metadata files for the ``MyApplication\Entity`` namespace.
394 2
     *
395 2
     * If you use an empty prefix, your metadata files would need to look like:
396 2
     *
397
     * ``my-dir/MyApplication.Entity.SomeObject.yml``
398
     * ``my-dir/MyApplication.Entity.OtherObject.xml``
399
     *
400
     * If you use ``MyApplication\Entity`` as prefix, your metadata files would need to look like:
401
     *
402 5
     * ``my-dir/SomeObject.yml``
403
     * ``my-dir/OtherObject.yml``
404
     *
405
     * Please keep in mind that you currently may only have one directory per namespace prefix.
406
     *
407
     * @param string $dir             The directory where metadata files are located.
408
     * @param string $namespacePrefix An optional prefix if you only store metadata for specific namespaces in this directory.
409
     *
410 3
     * @return SerializerBuilder
411
     *
412 3
     * @throws InvalidArgumentException When a directory does not exist.
413 3
     * @throws InvalidArgumentException When a directory has already been registered.
414
     */
415
    public function addMetadataDir(string $dir, string $namespacePrefix = ''): self
416
    {
417
        if (!is_dir($dir)) {
418
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
419
        }
420
421
        if (isset($this->metadataDirs[$namespacePrefix])) {
422 3
            throw new InvalidArgumentException(sprintf('There is already a directory configured for the namespace prefix "%s". Please use replaceMetadataDir() to override directories.', $namespacePrefix));
423
        }
424
425
        $this->metadataDirs[$namespacePrefix] = $dir;
426
427
        return $this;
428
    }
429
430
    /**
431 330
     * Adds a map of namespace prefixes to directories.
432
     *
433 330
     * @param array <string,string> $namespacePrefixToDirMap
0 ignored issues
show
Documentation Bug introduced by
The doc comment <string,string> at position 0 could not be parsed: Unknown type name '<' at position 0 in <string,string>.
Loading history...
434 330
     *
435 330
     * @return SerializerBuilder
436
     */
437 330
    public function addMetadataDirs(array $namespacePrefixToDirMap): self
438 1
    {
439 1
        foreach ($namespacePrefixToDirMap as $prefix => $dir) {
440 1
            $this->addMetadataDir($dir, $prefix);
441
        }
442
443
        return $this;
444 330
    }
445 318
446 318
    /**
447
     * Similar to addMetadataDir(), but overrides an existing entry.
448
     *
449 330
     * @return SerializerBuilder
450 330
     *
451
     * @throws InvalidArgumentException When a directory does not exist.
452 330
     * @throws InvalidArgumentException When no directory is configured for the ns prefix.
453
     */
454 330
    public function replaceMetadataDir(string $dir, string $namespacePrefix = ''): self
455
    {
456 330
        if (!is_dir($dir)) {
457 1
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
458 1
        }
459
460
        if (!isset($this->metadataDirs[$namespacePrefix])) {
461 330
            throw new InvalidArgumentException(sprintf('There is no directory configured for namespace prefix "%s". Please use addMetadataDir() for adding new directories.', $namespacePrefix));
462 71
        }
463
464
        $this->metadataDirs[$namespacePrefix] = $dir;
465 330
466 73
        return $this;
467
    }
468
469 330
    public function setMetadataDriverFactory(DriverFactoryInterface $driverFactory): self
470 329
    {
471 329
        $this->driverFactory = $driverFactory;
472
473
        return $this;
474 330
    }
475 330
476
    /**
477
     * @param SerializationContextFactoryInterface|callable $serializationContextFactory
478 330
     */
479 330
    public function setSerializationContextFactory($serializationContextFactory): self
480 330
    {
481 330
        if ($serializationContextFactory instanceof SerializationContextFactoryInterface) {
482 330
            $this->serializationContextFactory = $serializationContextFactory;
483 330
        } elseif (is_callable($serializationContextFactory)) {
484 330
            $this->serializationContextFactory = new CallableSerializationContextFactory(
485 330
                $serializationContextFactory
486
            );
487
        } else {
488 330
            throw new InvalidArgumentException('expected SerializationContextFactoryInterface or callable.');
489
        }
490
491 330
        return $this;
492
    }
493 330
494 330
    /**
495 330
     * @param DeserializationContextFactoryInterface|callable $deserializationContextFactory
496 330
     */
497 330
    public function setDeserializationContextFactory($deserializationContextFactory): self
498 330
    {
499
        if ($deserializationContextFactory instanceof DeserializationContextFactoryInterface) {
500
            $this->deserializationContextFactory = $deserializationContextFactory;
501
        } elseif (is_callable($deserializationContextFactory)) {
502 330
            $this->deserializationContextFactory = new CallableDeserializationContextFactory(
503
                $deserializationContextFactory
504 330
            );
505 330
        } else {
506 330
            throw new InvalidArgumentException('expected DeserializationContextFactoryInterface or callable.');
507 330
        }
508 330
509 330
        return $this;
510 330
    }
511
512
    public function setMetadataCache(CacheInterface $cache): self
513
    {
514 318
        $this->metadataCache = $cache;
515
516 318
        return $this;
517
    }
518
519
    public function setDocBlockTypeResolver(bool $docBlockTypeResolver): self
520 318
    {
521 318
        $this->docBlockTyperResolver = $docBlockTypeResolver;
522
523 1
        return $this;
524
    }
525 1
526
    public function build(): Serializer
527
    {
528
        $annotationReader = $this->annotationReader;
529 1
530
        if (null === $annotationReader) {
531
            if (PHP_VERSION_ID >= 80000 && true === $this->enableAttributes) {
532 1
                $annotationReader = new AttributeReader();
533
            } else {
534
                $annotationReader = new AnnotationReader();
535
536
                if (null !== $this->cacheDir) {
537
                    $this->createDir($this->cacheDir . '/annotations');
538
                    $annotationsCache = new FilesystemCache($this->cacheDir . '/annotations');
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Cache\FilesystemCache has been deprecated: Deprecated without replacement in doctrine/cache 1.11. This class will be dropped in 2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

538
                    $annotationsCache = /** @scrutinizer ignore-deprecated */ new FilesystemCache($this->cacheDir . '/annotations');
Loading history...
539
                    $annotationReader = new CachedReader($annotationReader, $annotationsCache, $this->debug);
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Annotations\CachedReader has been deprecated: the CachedReader is deprecated and will be removed in version 2.0.0 of doctrine/annotations. Please use the {@see \Doctrine\Common\Annotations\PsrCachedReader} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

539
                    $annotationReader = /** @scrutinizer ignore-deprecated */ new CachedReader($annotationReader, $annotationsCache, $this->debug);
Loading history...
540
                }
541
            }
542
        }
543
544
        if (null === $this->driverFactory) {
545
            $this->initializePropertyNamingStrategy();
546
            $this->driverFactory = new DefaultDriverFactory(
547
                $this->propertyNamingStrategy,
548
                $this->typeParser,
549
                $this->expressionEvaluator instanceof CompilableExpressionEvaluatorInterface ? $this->expressionEvaluator : null
550
            );
551
        }
552
553
        if ($this->docBlockTyperResolver) {
554
            $this->driverFactory = new DocBlockDriverFactory($this->driverFactory, $this->typeParser);
555
        }
556
557
        $metadataDriver = $this->driverFactory->createDriver($this->metadataDirs, $annotationReader);
558
        $metadataFactory = new MetadataFactory($metadataDriver, null, $this->debug);
559
560
        $metadataFactory->setIncludeInterfaces($this->includeInterfaceMetadata);
561
562
        if (null !== $this->metadataCache) {
563
            $metadataFactory->setCache($this->metadataCache);
564
        } elseif (null !== $this->cacheDir) {
565
            $this->createDir($this->cacheDir . '/metadata');
566
            $metadataFactory->setCache(new FileCache($this->cacheDir . '/metadata'));
567
        }
568
569
        if (!$this->handlersConfigured) {
570
            $this->addDefaultHandlers();
571
        }
572
573
        if (!$this->listenersConfigured) {
574
            $this->addDefaultListeners();
575
        }
576
577
        if (!$this->visitorsAdded) {
578
            $this->addDefaultSerializationVisitors();
579
            $this->addDefaultDeserializationVisitors();
580
        }
581
582
        $navigatorFactories = [
583
            GraphNavigatorInterface::DIRECTION_SERIALIZATION => $this->getSerializationNavigatorFactory($metadataFactory),
584
            GraphNavigatorInterface::DIRECTION_DESERIALIZATION => $this->getDeserializationNavigatorFactory($metadataFactory),
585
        ];
586
587
        return new Serializer(
588
            $metadataFactory,
589
            $navigatorFactories,
590
            $this->serializationVisitors,
591
            $this->deserializationVisitors,
592
            $this->serializationContextFactory,
593
            $this->deserializationContextFactory,
594
            $this->typeParser
595
        );
596
    }
597
598
    private function getSerializationNavigatorFactory(MetadataFactoryInterface $metadataFactory): GraphNavigatorFactoryInterface
599
    {
600
        return new SerializationGraphNavigatorFactory(
601
            $metadataFactory,
602
            $this->handlerRegistry,
603
            $this->getAccessorStrategy(),
604
            $this->eventDispatcher,
605
            $this->expressionEvaluator
606
        );
607
    }
608
609
    private function getDeserializationNavigatorFactory(MetadataFactoryInterface $metadataFactory): GraphNavigatorFactoryInterface
610
    {
611
        return new DeserializationGraphNavigatorFactory(
612
            $metadataFactory,
613
            $this->handlerRegistry,
614
            $this->objectConstructor ?: new UnserializeObjectConstructor(),
615
            $this->getAccessorStrategy(),
616
            $this->eventDispatcher,
617
            $this->expressionEvaluator
618
        );
619
    }
620
621
    private function initializePropertyNamingStrategy(): void
622
    {
623
        if (null !== $this->propertyNamingStrategy) {
624
            return;
625
        }
626
627
        $this->propertyNamingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy());
628
    }
629
630
    private function createDir(string $dir): void
631
    {
632
        if (is_dir($dir)) {
633
            return;
634
        }
635
636
        if (false === @mkdir($dir, 0777, true) && false === is_dir($dir)) {
637
            throw new RuntimeException(sprintf('Could not create directory "%s".', $dir));
638
        }
639
    }
640
}
641