Test Failed
Push — caching ( fd9061...49ea6a )
by Nate
02:41
created

ReflectionTypeAdapter::write()   D

Complexity

Conditions 18
Paths 4

Size

Total Lines 80
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 18.3238

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 32
dl 0
loc 80
ccs 27
cts 30
cp 0.9
rs 4.8666
c 2
b 0
f 0
cc 18
nc 4
nop 2
crap 18.3238

How to fix   Long Method    Complexity   

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
 * Copyright (c) Nate Brunette.
4
 * Distributed under the MIT License (http://opensource.org/licenses/MIT)
5
 */
6
7
declare(strict_types=1);
8
9
namespace Tebru\Gson\TypeAdapter;
10
11
use Tebru\Gson\Context\ReaderContext;
12
use Tebru\Gson\Context\WriterContext;
13
use Tebru\Gson\Internal\Data\Property;
14
use Tebru\Gson\Internal\DefaultClassMetadata;
15
use Tebru\Gson\Internal\ObjectConstructor;
16
use Tebru\Gson\Internal\ObjectConstructor\CreateFromInstance;
17
use Tebru\Gson\Internal\ObjectConstructorAware;
18
use Tebru\Gson\Internal\ObjectConstructorAwareTrait;
19
use Tebru\Gson\TypeAdapter;
20
use TypeError;
21
22
/**
23
 * Class ReflectionTypeAdapter
24
 *
25
 * Uses reflected class properties to read/write object
26
 *
27
 * @author Nate Brunette <[email protected]>
28
 */
29
class ReflectionTypeAdapter extends TypeAdapter implements ObjectConstructorAware
30
{
31
    use ObjectConstructorAwareTrait;
32
33
    /**
34
     * @var DefaultClassMetadata
35
     */
36
    protected $classMetadata;
37
38
    /**
39
     * @var Property[]
40
     */
41
    protected $properties;
42
43
    /**
44
     * @var null|string
45
     */
46
    protected $classVirtualProperty;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $skipSerialize;
52
53
    /**
54
     * @var bool
55
     */
56
    protected $skipDeserialize;
57
58
    /**
59
     * Constructor
60
     *
61
     * @param ObjectConstructor $objectConstructor
62
     * @param DefaultClassMetadata $classMetadata
63
     * @param null|string $classVirtualProperty
64
     */
65 19
    public function __construct(
66
        ObjectConstructor $objectConstructor,
67
        DefaultClassMetadata $classMetadata,
68
        ?string $classVirtualProperty
69
    ) {
70 19
        $this->objectConstructor = $objectConstructor;
71 19
        $this->classVirtualProperty = $classVirtualProperty;
72 19
        $this->classMetadata = $classMetadata;
73 19
        $this->properties = $classMetadata->properties->elements;
74 19
        $this->skipSerialize = $classMetadata->skipSerialize;
75 19
        $this->skipDeserialize = $classMetadata->skipDeserialize;
76 19
    }
77
78
    /**
79
     * Read the next value, convert it to its type and return it
80
     *
81
     * @param array $value
82
     * @param ReaderContext $context
83
     * @return object
84
     */
85 12
    public function read($value, ReaderContext $context)
86
    {
87 12
        if ($this->skipDeserialize || $value === null) {
88 3
            return null;
89
        }
90
91 9
        if ($this->classVirtualProperty !== null) {
92 1
            $value = array_shift($value);
93
        }
94
95 9
        $object = $this->objectConstructor->construct();
96 9
        $usesExisting = $context->usesExistingObject;
97 9
        $enableScalarAdapters = $context->enableScalarAdapters;
98 9
        $typeAdapterProvider = $context->typeAdapterProvider;
99 9
        $excluder = $context->getExcluder();
100 9
        $payload = $context->getPayload();
101
102 9
        if ($this->classMetadata->hasExclusions && $excluder->skipClassDeserializeByStrategy($this->classMetadata, $object, $payload)) {
103
            return null;
104
        }
105
106 9
        foreach ($value as $name => $item) {
107 9
            $property = $this->properties[$name] ?? null;
108
109 9
            if ($property === null || $property->skipDeserialize) {
110 9
                continue;
111
            }
112
113 7
            if ($property->hasExclusions && $excluder->skipPropertyDeserializeByStrategy($property, $object, $payload)) {
114
                continue;
115
            }
116
117 7
            $adapter = $property->adapter;
118
119 7
            if ($adapter === null) {
120
                // disabled scalar adapters
121
                if ($property->isScalar && !$enableScalarAdapters) {
122
                    $property->setterStrategy->set($object, $item);
123
                    continue;
124
                }
125
126
                $adapter = $property->adapter = $typeAdapterProvider->getAdapterFromProperty($property);
127
            }
128
129 7
            if ($usesExisting && $adapter instanceof ObjectConstructorAware) {
130
                try {
131 2
                    $nestedObject = $property->getterStrategy->get($object);
132 1
                } /** @noinspection BadExceptionsProcessingInspection */ catch (TypeError $error) {
133
                    // this may occur when attempting to get a nested object that doesn't exist and
134
                    // the method return is not nullable. The type error only occurs because we are
135
                    // may be calling the getter before data exists.
136 1
                    $nestedObject = null;
137
                }
138
139 2
                if ($nestedObject !== null) {
140 1
                    $adapter->setObjectConstructor(new CreateFromInstance($nestedObject));
141
                }
142
            }
143
144 7
            $property->setterStrategy->set($object, $adapter->read($item, $context));
145
        }
146
147 9
        return $object;
148
    }
149
150
    /**
151
     * Write the value to the writer for the type
152
     *
153
     * @param object $value
154
     * @param WriterContext $context
155
     * @return array|null
156
     */
157 7
    public function write($value, WriterContext $context): ?array
158
    {
159 7
        if ($this->skipSerialize || $value === null) {
160 3
            return null;
161
        }
162
163 4
        $result = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
164 4
        $serializeNull = $this->serializeNull ?? $this->serializeNull = $context->serializeNull();
0 ignored issues
show
Bug Best Practice introduced by
The property serializeNull does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
165 4
        $enableScalarAdapters = $this->enableScalarAdapters ?? $this->enableScalarAdapters = $context->enableScalarAdapters();
0 ignored issues
show
Bug Best Practice introduced by
The property enableScalarAdapters does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
166 4
        $typeAdapterProvider = $this->typeAdapterProvider ?? $this->typeAdapterProvider = $context->getTypeAdapterProvider();
0 ignored issues
show
Bug Best Practice introduced by
The property typeAdapterProvider does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
167 4
        $excluder = $this->excluder ?? $this->excluder = $context->getExcluder();
0 ignored issues
show
Bug Best Practice introduced by
The property excluder does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
168
        $extractor = $this->extractor ?? $this->extractor = \Closure::bind(function ($value, array $properties) use ($excluder, $enableScalarAdapters, $typeAdapterProvider, $serializeNull, $context) {
0 ignored issues
show
Bug Best Practice introduced by
The property extractor does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
169 4
170
            $values = [];
171
            foreach ($properties as $property) {
172
                if ($property->skipSerialize) {
173 4
                    continue;
174 4
                }
175 4
                if ($property->hasExclusions && $excluder->skipPropertySerializeByStrategy($property, $value)) {
176
                    continue;
177 4
                }
178
                $serializedName = $property->serializedName;
179
                $propertyValue = $property->getterStrategy ? $value->{$property->getterStrategy->methodName}() : $value->{$property->realName};
180
                $isNull = $propertyValue === null;
181 4
                $adapter = $property->adapter;
182 4
                if ($adapter === null && ($enableScalarAdapters || !$property->isScalar)) {
183 4
                    $adapter = $typeAdapterProvider->getAdapterFromProperty($property);
184 4
                }
185
                if (!$isNull && $adapter !== null) {
186 4
                    $propertyValue = $adapter->write($propertyValue, $context);
187
                }
188
189
                if ($serializeNull || !$isNull) {
190 4
                    $values[$serializedName] = $propertyValue;
191 4
                }
192
            }
193
194 4
            return $values;
195 4
            }, null, $this->classMetadata->name);
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 8 spaces, found 12
Loading history...
196
197
        if ($this->classMetadata->hasExclusions && $excluder->skipClassSerializeByStrategy($this->classMetadata, $value)) {
198
            return null;
199 4
        }
200 1
201
//        $propertys = [];
202
//        foreach ($this->properties as $property) {
203 4
//            if ($property->skipSerialize) {
204
//                continue;
205
//            }
206
//            if ($property->hasExclusions && $excluder->skipPropertySerializeByStrategy($property, $value)) {
207
//                continue;
208
//            }
209
//            $propertys[] = $property;
210
//            continue;
211 14
//
212
//            $serializedName = $property->serializedName;
213 14
//            $propertyValue = $value->{$property->getterStrategy->propertyName};
214
//            $isNull = $propertyValue === null;
215
//            $adapter = $property->adapter;
216
//
217
//            if ($adapter === null && ($enableScalarAdapters || !$property->isScalar)) {
218
//                $adapter = $typeAdapterProvider->getAdapterFromProperty($property);
219
//            }
220
//
221
//            if (!$isNull && $adapter !== null) {
222
//                $propertyValue = $adapter->write($propertyValue, $context);
223
//            }
224
//
225
//            if ($serializeNull || !$isNull) {
226
//                $result[$serializedName] = $propertyValue;
227
//            }
228
//        }
229
230
        $result = $extractor($value, $this->properties);
231
232
        if ($this->classVirtualProperty !== null) {
233
            $result = [$this->classVirtualProperty => $result];
234
        }
235
236
        return $result;
237
    }
238
239
    /**
240
     * Return true if object can be written to disk
241
     *
242
     * @return bool
243
     */
244
    public function canCache(): bool
245
    {
246
        return $this->objectConstructor->canCache();
247
    }
248
}
249