Passed
Pull Request — master (#5)
by Sébastien
10:01
created

PropertyNormalizer::denormalize()   B

Complexity

Conditions 9
Paths 33

Size

Total Lines 51
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 9.648

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 26
c 1
b 0
f 0
nc 33
nop 3
dl 0
loc 51
ccs 20
cts 25
cp 0.8
crap 9.648
rs 8.0555

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Bdf\Serializer\Normalizer;
4
5
use Bdf\Serializer\Context\DenormalizationContext;
6
use Bdf\Serializer\Context\NormalizationContext;
7
use Bdf\Serializer\Exception\UnexpectedValueException;
8
use Bdf\Serializer\Metadata\MetadataFactoryInterface;
9
use Bdf\Serializer\PropertyAccessor\Exception\AccessorException;
10
use Bdf\Serializer\Type\Type;
11
use Doctrine\Instantiator\Exception\ExceptionInterface;
12
use Doctrine\Instantiator\Instantiator;
13
use Doctrine\Instantiator\InstantiatorInterface;
14
15
/**
16
 * PropertyNormalizer
17
 *
18
 * @author  Seb
19
 */
20
class PropertyNormalizer implements NormalizerInterface
21
{
22
    /**
23
     * The metadata factory
24
     *
25
     * @var MetadataFactoryInterface
26
     */
27
    private $metadataFactory;
28
29
    /**
30
     * The object instantiator
31
     *
32
     * @var InstantiatorInterface
33
     */
34
    private $instantiator;
35
36
    /**
37
     * PropertyNormalizer constructor.
38
     *
39
     * @param MetadataFactoryInterface $metadataFactory
40
     * @param InstantiatorInterface    $instantiator        The instanciator provider. Should returns InstantiatorInterface.
41
     */
42 69
    public function __construct(MetadataFactoryInterface $metadataFactory, InstantiatorInterface $instantiator = null)
43
    {
44 69
        $this->metadataFactory = $metadataFactory;
45 69
        $this->instantiator = $instantiator;
46 69
    }
47
48
    /**
49
     * {@inheritdoc}
50
     */
51 39
    public function normalize($object, NormalizationContext $context)
52
    {
53 39
        $hash = $context->assertNoCircularReference($object);
54
55 39
        $normalized = [];
56 39
        $metadata = $this->metadataFactory->getMetadata($object);
57
58
        // TODO Optimize the loop with the options
59 39
        foreach ($metadata->properties as $property) {
60 39
            $propertyContext = $context->duplicate($property->normalizationOptions);
61
62 39
            if ($propertyContext->skipProperty($property)) {
63 8
                continue;
64
            }
65
66
            try {
67 39
                $value = $propertyContext->root()->normalize($property->accessor->read($object), $propertyContext);
68 1
            } catch (AccessorException $exception) {
69
                if ($propertyContext->throwsOnAccessorError()) {
70
                    throw $exception;
71
                }
72
73
                continue;
74
            }
75
76 38
            if ($propertyContext->skipPropertyValue($property, $value)) {
77 3
                continue;
78
            }
79
80 38
            if ($property->inline && is_array($value) && !$context->includeMetaType()) {
81 1
                $normalized += $value;
82
            } else {
83 38
                $normalized[$property->alias] = $value;
84
            }
85
        }
86
87 38
        $context->releaseReference($hash);
88
89 38
        return $normalized;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95 24
    public function denormalize($data, Type $type, DenormalizationContext $context)
96
    {
97 24
        $object = $this->instantiate($type);
98 24
        $metadata = $this->metadataFactory->getMetadata($object);
99
100 24
        foreach ((array)$data as $name => $propertyData) {
101 24
            if (($property = $metadata->property($name)) === null) {
102 1
                continue;
103
            }
104
105 23
            $propertyContext = $context->duplicate($property->denormalizationOptions);
106
107 23
            if ($propertyContext->skipProperty($property)) {
108 1
                continue;
109
            }
110
111
            // If type is an object we should try to inject
112
            // the new value into the object of the owner object
113 22
            if (!$property->type->isBuildin()) {
114
                try {
115 8
                    $current = $property->accessor->read($object);
116
117
                    // if current is an object we put it on the queue of targets
118 8
                    if (is_object($current)) {
119 8
                        $property->type->setTarget($current);
120
                    }
121
                } catch (AccessorException $exception) {
122
                    // Silent mode: if value is undefined we let the next denormalize create the object
123
                }
124
            }
125
126
            try {
127 22
                $property->accessor->write(
128 22
                    $object,
129 22
                    $propertyContext->root()->denormalize($propertyData, $property->type, $propertyContext)
130
                );
131
            } catch (AccessorException $exception) {
132
                if ($propertyContext->throwsOnAccessorError()) {
133
                    throw $exception;
134
                }
135
136
                continue;
137 22
            } finally {
138
                // memory leaks
139 22
                $property->type->setTarget(null);
140
            }
141
        }
142
143 24
        $metadata->postDenormalization($object);
144
145 24
        return $object;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151 60
    public function supports(string $className): bool
152
    {
153 60
        return class_exists($className);
154
    }
155
156
    /**
157
     * Instanciate an object
158
     *
159
     * @param Type $type
160
     *
161
     * @return object
162
     *
163
     * @throws UnexpectedValueException  If instanciate could not instanciate type
164
     */
165 24
    private function instantiate($type)
166
    {
167 24
        if ($type->target()) {
168 3
            return $type->target();
169
        }
170
171 21
        if ($this->instantiator === null) {
172 21
            $this->instantiator = new Instantiator();
173
        }
174
175
        try {
176 21
            return $this->instantiator->instantiate($type->name());
177
        } catch (ExceptionInterface $e) {
178
            throw new UnexpectedValueException("Could not instantiate object '".$type->name()."'", 0, $e);
179
        }
180
    }
181
}
182