Passed
Pull Request — master (#1332)
by Asmir
02:32
created

SerializerBuilder   F

Complexity

Total Complexity 72

Size/Duplication

Total Lines 594
Duplicated Lines 0 %

Test Coverage

Coverage 75.9%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 204
c 7
b 0
f 0
dl 0
loc 594
rs 2.64
ccs 148
cts 195
cp 0.759
wmc 72

36 Methods

Rating   Name   Duplication   Size   Complexity  
A getDeserializationNavigatorFactory() 0 9 2
A addDefaultDeserializationVisitors() 0 9 1
A replaceMetadataDir() 0 13 3
A initializePropertyNamingStrategy() 0 7 2
A setDebug() 0 5 1
A getSerializationNavigatorFactory() 0 8 1
A setDeserializationVisitor() 0 6 1
A setMetadataDriverFactory() 0 5 1
A setSerializationVisitor() 0 6 1
A setPropertyNamingStrategy() 0 5 1
A create() 0 3 1
F build() 0 63 12
A setAnnotationReader() 0 5 1
A setTypeParser() 0 5 1
A addDefaultListeners() 0 6 1
A setDocBlockTypeResolver() 0 5 1
A decorateAnnotationReader() 0 14 3
A setDeserializationContextFactory() 0 13 3
A __construct() 0 15 5
A includeInterfaceMetadata() 0 5 1
A setMetadataDirs() 0 11 3
A createDir() 0 8 4
A setExpressionEvaluator() 0 5 1
A getAccessorStrategy() 0 7 2
A addMetadataDir() 0 13 3
A setAccessorStrategy() 0 5 1
A addDefaultSerializationVisitors() 0 9 1
A setMetadataCache() 0 5 1
A addDefaultHandlers() 0 9 1
A configureListeners() 0 6 1
A configureHandlers() 0 6 1
A setEnableAttributes() 0 5 1
A setSerializationContextFactory() 0 13 3
A setCacheDir() 0 13 3
A setObjectConstructor() 0 5 1
A addMetadataDirs() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like SerializerBuilder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SerializerBuilder, and based on these observations, apply Extract Interface, too.

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\PsrCachedReader;
10
use Doctrine\Common\Annotations\Reader;
11
use Doctrine\Common\Cache\FilesystemCache;
0 ignored issues
show
Bug introduced by
The type Doctrine\Common\Cache\FilesystemCache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

189
        return new static(/** @scrutinizer ignore-type */ ...$args);
Loading history...
190
    }
191 73
192
    public function __construct(?HandlerRegistryInterface $handlerRegistry = null, ?EventDispatcherInterface $eventDispatcher = null, bool $enableAttributes = false)
193 73
    {
194 73
        $this->typeParser = new Parser();
195
        $this->handlerRegistry = $handlerRegistry ?: new HandlerRegistry();
196 73
        $this->eventDispatcher = $eventDispatcher ?: new EventDispatcher();
197
        $this->serializationVisitors = [];
198
        $this->deserializationVisitors = [];
199 1
        $this->enableAttributes = $enableAttributes;
200
201 1
        if ($handlerRegistry) {
202 1
            $this->handlersConfigured = true;
203
        }
204 1
205
        if ($eventDispatcher) {
206
            $this->listenersConfigured = true;
207 4
        }
208
    }
209 4
210
    public function setAccessorStrategy(AccessorStrategyInterface $accessorStrategy): self
211 4
    {
212
        $this->accessorStrategy = $accessorStrategy;
213
214
        return $this;
215
    }
216
217
    private function getAccessorStrategy(): AccessorStrategyInterface
218
    {
219
        if (!$this->accessorStrategy) {
220
            $this->accessorStrategy = new DefaultAccessorStrategy($this->expressionEvaluator);
221 2
        }
222
223 2
        return $this->accessorStrategy;
224 2
    }
225
226 2
    public function setExpressionEvaluator(ExpressionEvaluatorInterface $expressionEvaluator): self
227
    {
228
        $this->expressionEvaluator = $expressionEvaluator;
229
230
        return $this;
231
    }
232
233
    public function setTypeParser(ParserInterface $parser): self
234
    {
235
        $this->typeParser = $parser;
236
237 329
        return $this;
238
    }
239 329
240 329
    public function setAnnotationReader(Reader $reader): self
241 329
    {
242 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...
243
244
        return $this;
245 329
    }
246
247
    public function setEnableAttributes(bool $bool): self
248 329
    {
249
        $this->enableAttributes = $bool;
250 329
251 329
        return $this;
252 329
    }
253 329
254
    public function setDebug(bool $bool): self
255
    {
256 329
        $this->debug = $bool;
257
258
        return $this;
259
    }
260
261
    public function setCacheDir(string $dir): self
262
    {
263
        if (!is_dir($dir)) {
264 1
            $this->createDir($dir);
265
        }
266 1
267
        if (!is_writable($dir)) {
268 1
            throw new InvalidArgumentException(sprintf('The cache directory "%s" is not writable.', $dir));
269
        }
270
271
        $this->cacheDir = $dir;
272
273
        return $this;
274
    }
275
276
    public function addDefaultHandlers(): self
277
    {
278
        $this->handlersConfigured = true;
279
        $this->handlerRegistry->registerSubscribingHandler(new DateHandler());
280
        $this->handlerRegistry->registerSubscribingHandler(new StdClassHandler());
281
        $this->handlerRegistry->registerSubscribingHandler(new ArrayCollectionHandler());
282 2
        $this->handlerRegistry->registerSubscribingHandler(new IteratorHandler());
283
284 2
        return $this;
285 2
    }
286 2
287
    public function configureHandlers(\Closure $closure): self
288
    {
289
        $this->handlersConfigured = true;
290 2
        $closure($this->handlerRegistry);
291
292 2
        return $this;
293
    }
294
295
    public function addDefaultListeners(): self
296
    {
297
        $this->listenersConfigured = true;
298
        $this->eventDispatcher->addSubscriber(new DoctrineProxySubscriber());
299
300
        return $this;
301
    }
302
303
    public function configureListeners(\Closure $closure): self
304
    {
305
        $this->listenersConfigured = true;
306
        $closure($this->eventDispatcher);
307
308
        return $this;
309
    }
310
311
    public function setObjectConstructor(ObjectConstructorInterface $constructor): self
312
    {
313
        $this->objectConstructor = $constructor;
314
315
        return $this;
316
    }
317
318
    public function setPropertyNamingStrategy(PropertyNamingStrategyInterface $propertyNamingStrategy): self
319
    {
320
        $this->propertyNamingStrategy = $propertyNamingStrategy;
321
322
        return $this;
323
    }
324
325
    public function setSerializationVisitor(string $format, SerializationVisitorFactory $visitor): self
326
    {
327
        $this->visitorsAdded = true;
328
        $this->serializationVisitors[$format] = $visitor;
329
330
        return $this;
331
    }
332
333
    public function setDeserializationVisitor(string $format, DeserializationVisitorFactory $visitor): self
334
    {
335
        $this->visitorsAdded = true;
336
        $this->deserializationVisitors[$format] = $visitor;
337
338
        return $this;
339
    }
340
341
    public function addDefaultSerializationVisitors(): self
342
    {
343
        $this->visitorsAdded = true;
344
        $this->serializationVisitors = [
345
            'xml' => new XmlSerializationVisitorFactory(),
346
            'json' => new JsonSerializationVisitorFactory(),
347
        ];
348
349
        return $this;
350
    }
351
352
    public function addDefaultDeserializationVisitors(): self
353
    {
354
        $this->visitorsAdded = true;
355
        $this->deserializationVisitors = [
356
            'xml' => new XmlDeserializationVisitorFactory(),
357
            'json' => new JsonDeserializationVisitorFactory(),
358
        ];
359
360
        return $this;
361
    }
362
363
    /**
364
     * @param bool $include Whether to include the metadata from the interfaces
365
     *
366
     * @return SerializerBuilder
367
     */
368
    public function includeInterfaceMetadata(bool $include): self
369
    {
370
        $this->includeInterfaceMetadata = $include;
371
372
        return $this;
373
    }
374
375
    /**
376
     * Sets a map of namespace prefixes to directories.
377
     *
378 13
     * This method overrides any previously defined directories.
379
     *
380 13
     * @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...
381
     *
382 13
     * @return SerializerBuilder
383
     *
384
     * @throws InvalidArgumentException When a directory does not exist.
385
     */
386
    public function setMetadataDirs(array $namespacePrefixToDirMap): self
387
    {
388
        foreach ($namespacePrefixToDirMap as $dir) {
389
            if (!is_dir($dir)) {
390 5
                throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
391
            }
392 5
        }
393 3
394 2
        $this->metadataDirs = $namespacePrefixToDirMap;
395 2
396 2
        return $this;
397
    }
398
399
    /**
400
     * Adds a directory where the serializer will look for class metadata.
401
     *
402 5
     * The namespace prefix will make the names of the actual metadata files a bit shorter. For example, let's assume
403
     * that you have a directory where you only store metadata files for the ``MyApplication\Entity`` namespace.
404
     *
405
     * If you use an empty prefix, your metadata files would need to look like:
406
     *
407
     * ``my-dir/MyApplication.Entity.SomeObject.yml``
408
     * ``my-dir/MyApplication.Entity.OtherObject.xml``
409
     *
410 3
     * If you use ``MyApplication\Entity`` as prefix, your metadata files would need to look like:
411
     *
412 3
     * ``my-dir/SomeObject.yml``
413 3
     * ``my-dir/OtherObject.yml``
414
     *
415
     * Please keep in mind that you currently may only have one directory per namespace prefix.
416
     *
417
     * @param string $dir             The directory where metadata files are located.
418
     * @param string $namespacePrefix An optional prefix if you only store metadata for specific namespaces in this directory.
419
     *
420
     * @return SerializerBuilder
421
     *
422 3
     * @throws InvalidArgumentException When a directory does not exist.
423
     * @throws InvalidArgumentException When a directory has already been registered.
424
     */
425
    public function addMetadataDir(string $dir, string $namespacePrefix = ''): self
426
    {
427
        if (!is_dir($dir)) {
428
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
429
        }
430
431 330
        if (isset($this->metadataDirs[$namespacePrefix])) {
432
            throw new InvalidArgumentException(sprintf('There is already a directory configured for the namespace prefix "%s". Please use replaceMetadataDir() to override directories.', $namespacePrefix));
433 330
        }
434 330
435 330
        $this->metadataDirs[$namespacePrefix] = $dir;
436
437 330
        return $this;
438 1
    }
439 1
440 1
    /**
441
     * Adds a map of namespace prefixes to directories.
442
     *
443
     * @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...
444 330
     *
445 318
     * @return SerializerBuilder
446 318
     */
447
    public function addMetadataDirs(array $namespacePrefixToDirMap): self
448
    {
449 330
        foreach ($namespacePrefixToDirMap as $prefix => $dir) {
450 330
            $this->addMetadataDir($dir, $prefix);
451
        }
452 330
453
        return $this;
454 330
    }
455
456 330
    /**
457 1
     * Similar to addMetadataDir(), but overrides an existing entry.
458 1
     *
459
     * @return SerializerBuilder
460
     *
461 330
     * @throws InvalidArgumentException When a directory does not exist.
462 71
     * @throws InvalidArgumentException When no directory is configured for the ns prefix.
463
     */
464
    public function replaceMetadataDir(string $dir, string $namespacePrefix = ''): self
465 330
    {
466 73
        if (!is_dir($dir)) {
467
            throw new InvalidArgumentException(sprintf('The directory "%s" does not exist.', $dir));
468
        }
469 330
470 329
        if (!isset($this->metadataDirs[$namespacePrefix])) {
471 329
            throw new InvalidArgumentException(sprintf('There is no directory configured for namespace prefix "%s". Please use addMetadataDir() for adding new directories.', $namespacePrefix));
472
        }
473
474 330
        $this->metadataDirs[$namespacePrefix] = $dir;
475 330
476
        return $this;
477
    }
478 330
479 330
    public function setMetadataDriverFactory(DriverFactoryInterface $driverFactory): self
480 330
    {
481 330
        $this->driverFactory = $driverFactory;
482 330
483 330
        return $this;
484 330
    }
485 330
486
    /**
487
     * @param SerializationContextFactoryInterface|callable $serializationContextFactory
488 330
     */
489
    public function setSerializationContextFactory($serializationContextFactory): self
490
    {
491 330
        if ($serializationContextFactory instanceof SerializationContextFactoryInterface) {
492
            $this->serializationContextFactory = $serializationContextFactory;
493 330
        } elseif (is_callable($serializationContextFactory)) {
494 330
            $this->serializationContextFactory = new CallableSerializationContextFactory(
495 330
                $serializationContextFactory
496 330
            );
497 330
        } else {
498 330
            throw new InvalidArgumentException('expected SerializationContextFactoryInterface or callable.');
499
        }
500
501
        return $this;
502 330
    }
503
504 330
    /**
505 330
     * @param DeserializationContextFactoryInterface|callable $deserializationContextFactory
506 330
     */
507 330
    public function setDeserializationContextFactory($deserializationContextFactory): self
508 330
    {
509 330
        if ($deserializationContextFactory instanceof DeserializationContextFactoryInterface) {
510 330
            $this->deserializationContextFactory = $deserializationContextFactory;
511
        } elseif (is_callable($deserializationContextFactory)) {
512
            $this->deserializationContextFactory = new CallableDeserializationContextFactory(
513
                $deserializationContextFactory
514 318
            );
515
        } else {
516 318
            throw new InvalidArgumentException('expected DeserializationContextFactoryInterface or callable.');
517
        }
518
519
        return $this;
520 318
    }
521 318
522
    public function setMetadataCache(CacheInterface $cache): self
523 1
    {
524
        $this->metadataCache = $cache;
525 1
526
        return $this;
527
    }
528
529 1
    public function setDocBlockTypeResolver(bool $docBlockTypeResolver): self
530
    {
531
        $this->docBlockTyperResolver = $docBlockTypeResolver;
532 1
533
        return $this;
534
    }
535
536
    public function build(): Serializer
537
    {
538
        $annotationReader = $this->annotationReader;
539
        if (null === $annotationReader) {
540
            $annotationReader = new AnnotationReader();
541
            $annotationReader = $this->decorateAnnotationReader($annotationReader);
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
        if (PHP_VERSION_ID >= 80000 && true === $this->enableAttributes) {
558
            $this->driverFactory = new AttributeDriverFactory($this->driverFactory, $this->propertyNamingStrategy, $this->typeParser);
559
        }
560
561
        $metadataDriver = $this->driverFactory->createDriver($this->metadataDirs, $annotationReader);
562
        $metadataFactory = new MetadataFactory($metadataDriver, null, $this->debug);
563
564
        $metadataFactory->setIncludeInterfaces($this->includeInterfaceMetadata);
565
566
        if (null !== $this->metadataCache) {
567
            $metadataFactory->setCache($this->metadataCache);
568
        } elseif (null !== $this->cacheDir) {
569
            $this->createDir($this->cacheDir . '/metadata');
570
            $metadataFactory->setCache(new FileCache($this->cacheDir . '/metadata'));
571
        }
572
573
        if (!$this->handlersConfigured) {
574
            $this->addDefaultHandlers();
575
        }
576
577
        if (!$this->listenersConfigured) {
578
            $this->addDefaultListeners();
579
        }
580
581
        if (!$this->visitorsAdded) {
582
            $this->addDefaultSerializationVisitors();
583
            $this->addDefaultDeserializationVisitors();
584
        }
585
586
        $navigatorFactories = [
587
            GraphNavigatorInterface::DIRECTION_SERIALIZATION => $this->getSerializationNavigatorFactory($metadataFactory),
588
            GraphNavigatorInterface::DIRECTION_DESERIALIZATION => $this->getDeserializationNavigatorFactory($metadataFactory),
589
        ];
590
591
        return new Serializer(
592
            $metadataFactory,
593
            $navigatorFactories,
594
            $this->serializationVisitors,
595
            $this->deserializationVisitors,
596
            $this->serializationContextFactory,
597
            $this->deserializationContextFactory,
598
            $this->typeParser
599
        );
600
    }
601
602
    private function getSerializationNavigatorFactory(MetadataFactoryInterface $metadataFactory): GraphNavigatorFactoryInterface
603
    {
604
        return new SerializationGraphNavigatorFactory(
605
            $metadataFactory,
606
            $this->handlerRegistry,
607
            $this->getAccessorStrategy(),
608
            $this->eventDispatcher,
609
            $this->expressionEvaluator
610
        );
611
    }
612
613
    private function getDeserializationNavigatorFactory(MetadataFactoryInterface $metadataFactory): GraphNavigatorFactoryInterface
614
    {
615
        return new DeserializationGraphNavigatorFactory(
616
            $metadataFactory,
617
            $this->handlerRegistry,
618
            $this->objectConstructor ?: new UnserializeObjectConstructor(),
619
            $this->getAccessorStrategy(),
620
            $this->eventDispatcher,
621
            $this->expressionEvaluator
622
        );
623
    }
624
625
    private function initializePropertyNamingStrategy(): void
626
    {
627
        if (null !== $this->propertyNamingStrategy) {
628
            return;
629
        }
630
631
        $this->propertyNamingStrategy = new SerializedNameAnnotationStrategy(new CamelCaseNamingStrategy());
632
    }
633
634
    private function createDir(string $dir): void
635
    {
636
        if (is_dir($dir)) {
637
            return;
638
        }
639
640
        if (false === @mkdir($dir, 0777, true) && false === is_dir($dir)) {
641
            throw new RuntimeException(sprintf('Could not create directory "%s".', $dir));
642
        }
643
    }
644
645
    private function decorateAnnotationReader(Reader $annotationReader): Reader
646
    {
647
        if (null !== $this->cacheDir) {
648
            $this->createDir($this->cacheDir . '/annotations');
649
            if (class_exists(FilesystemAdapter::class)) {
650
                $annotationsCache = new FilesystemAdapter('', 0, $this->cacheDir . '/annotations');
651
                $annotationReader = new PsrCachedReader($annotationReader, $annotationsCache, $this->debug);
652
            } else {
653
                $annotationsCache = new FilesystemCache($this->cacheDir . '/annotations');
654
                $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

654
                $annotationReader = /** @scrutinizer ignore-deprecated */ new CachedReader($annotationReader, $annotationsCache, $this->debug);
Loading history...
655
            }
656
        }
657
658
        return $annotationReader;
659
    }
660
}
661