Passed
Pull Request — master (#6)
by Dominik
05:36
created

EmbedManyFieldDenormalizer::newCollection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Deserialization\Denormalizer\Relation;
6
7
use Chubbyphp\Deserialization\Accessor\AccessorInterface;
8
use Chubbyphp\Deserialization\Denormalizer\DenormalizerContextInterface;
9
use Chubbyphp\Deserialization\Denormalizer\DenormalizerInterface;
10
use Chubbyphp\Deserialization\Denormalizer\FieldDenormalizerInterface;
11
use Chubbyphp\Deserialization\DeserializerLogicException;
12
use Chubbyphp\Deserialization\DeserializerRuntimeException;
13
use Doctrine\Common\Persistence\Proxy;
14
15
final class EmbedManyFieldDenormalizer implements FieldDenormalizerInterface
16
{
17
    /**
18
     * @var string
19
     */
20
    private $class;
21
22
    /**
23
     * @var AccessorInterface
24
     */
25
    private $accessor;
26
27
    /**
28
     * @var string|null
29
     */
30
    private $collectionClass;
31
32
    /**
33
     * @param string            $class
34
     * @param AccessorInterface $accessor
35
     * @param string|null       $collectionClass
36
     */
37 8
    public function __construct(string $class, AccessorInterface $accessor, string $collectionClass = null)
38
    {
39 8
        $this->class = $class;
40 8
        $this->accessor = $accessor;
41 8
        $this->collectionClass = $collectionClass;
42 8
    }
43
44
    /**
45
     * @param string                       $path
46
     * @param object                       $object
47
     * @param mixed                        $value
48
     * @param DenormalizerContextInterface $context
49
     * @param DenormalizerInterface|null   $denormalizer
50
     *
51
     * @throws DeserializerLogicException
52
     * @throws DeserializerRuntimeException
53
     */
54 8
    public function denormalizeField(
55
        string $path,
56
        $object,
57
        $value,
58
        DenormalizerContextInterface $context,
59
        DenormalizerInterface $denormalizer = null
60
    ) {
61 8
        if (null === $value) {
62 1
            $this->accessor->setValue($object, $value);
63
64 1
            return;
65
        }
66
67 7
        if (null === $denormalizer) {
68 1
            throw DeserializerLogicException::createMissingDenormalizer($path);
69
        }
70
71 6
        if (!is_array($value)) {
72 1
            throw DeserializerRuntimeException::createInvalidDataType($path, gettype($value), 'array');
73
        }
74
75 5
        $existingEmbeddedObjects = $this->accessor->getValue($object) ?? [];
76
77 5
        $embeddedObjects = $this->newCollection();
78 5
        foreach ($value as $i => $subValue) {
79 5
            $subPath = $path.'['.$i.']';
80
81 5
            if (!is_array($subValue)) {
82 1
                throw DeserializerRuntimeException::createInvalidDataType($subPath, gettype($subValue), 'array');
83
            }
84
85 4
            $embeddedObject = $this->getEmbeddedObjectOrClass($i, $existingEmbeddedObjects);
86
87 4
            $embeddedObjects[$i] = $denormalizer->denormalize($embeddedObject, $subValue, $context, $subPath);
88
        }
89
90 4
        $this->accessor->setValue($object, $embeddedObjects);
91 4
    }
92
93
    /**
94
     * @param string|int         $i
95
     * @param array|\Traversable $existingEmbeddedObjects
96
     *
97
     * @return object|string
98
     */
99 4
    private function getEmbeddedObjectOrClass($i, $existingEmbeddedObjects)
100
    {
101 4
        if (isset($existingEmbeddedObjects[$i])) {
102 3
            $embeddedObject = $existingEmbeddedObjects[$i];
103
104 3
            if (interface_exists('Doctrine\Common\Persistence\Proxy')
105 3
                && $embeddedObject instanceof Proxy && !$embeddedObject->__isInitialized()
106
            ) {
107 1
                $embeddedObject->__load();
108
            }
109
110 3
            return $embeddedObject;
111
        }
112
113 1
        return $this->class;
114
    }
115
116
    /**
117
     * @return array|\ArrayAccess|\Traversable
118
     */
119 5
    private function newCollection()
120
    {
121 5
        if (null === $this->collectionClass) {
122 4
            return [];
123
        }
124
125 1
        $collectionClass = $this->collectionClass;
126
127 1
        return new $collectionClass();
128
    }
129
}
130