GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 4a67f9...fffa0d )
by Chris
8s
created

JsonSerializer::serializeData()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 27
rs 4.8196
cc 10
eloc 16
nc 7
nop 1

How to fix   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
namespace Zumba\JsonSerializer;
4
5
use ReflectionClass;
6
use ReflectionException;
7
use SplObjectStorage;
8
use Zumba\JsonSerializer\Exception\JsonSerializerException;
9
use SuperClosure\SerializerInterface as ClosureSerializerInterface;
10
11
class JsonSerializer
12
{
13
14
    const CLASS_IDENTIFIER_KEY = '@type';
15
    const CLOSURE_IDENTIFIER_KEY = '@closure';
16
    const FLOAT_ADAPTER = 'JsonSerializerFloatAdapter';
17
18
    /**
19
     * Storage for object
20
     *
21
     * Used for recursion
22
     *
23
     * @var SplObjectStorage
24
     */
25
    protected $objectStorage;
26
27
    /**
28
     * Object mapping for recursion
29
     *
30
     * @var array
31
     */
32
    protected $objectMapping = array();
33
34
    /**
35
     * Object mapping index
36
     *
37
     * @var integer
38
     */
39
    protected $objectMappingIndex = 0;
40
41
    /**
42
     * Support PRESERVE_ZERO_FRACTION json option
43
     *
44
     * @var boolean
45
     */
46
    protected $preserveZeroFractionSupport;
47
48
    /**
49
     * Closure serializer instance
50
     *
51
     * @var SuperClosure\SerializerInterface
52
     */
53
    protected $closureSerializer;
54
55
    /**
56
     * Constructor.
57
     *
58
     * @param SuperClosure\SerializerInterface $closureSerializer
59
     */
60
    public function __construct(ClosureSerializerInterface $closureSerializer = null)
61
    {
62
        $this->preserveZeroFractionSupport = defined('JSON_PRESERVE_ZERO_FRACTION');
63
        $this->closureSerializer = $closureSerializer;
0 ignored issues
show
Documentation Bug introduced by
It seems like $closureSerializer can also be of type object<SuperClosure\SerializerInterface>. However, the property $closureSerializer is declared as type object<Zumba\JsonSeriali...re\SerializerInterface>. Maybe add an additional type 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 mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
64
    }
65
66
    /**
67
     * Serialize the value in JSON
68
     *
69
     * @param mixed $value
70
     * @return string JSON encoded
71
     * @throws Zumba\JsonSerializer\Exception\JsonSerializerException
72
     */
73
    public function serialize($value)
74
    {
75
        $this->reset();
76
        $encoded = json_encode($this->serializeData($value), $this->calculateEncodeOptions());
77
        return $this->processEncodedValue($encoded);
78
    }
79
80
    /**
81
     * Calculate encoding options
82
     *
83
     * @return integer
84
     */
85
    protected function calculateEncodeOptions()
86
    {
87
        $options = JSON_UNESCAPED_UNICODE;
88
        if ($this->preserveZeroFractionSupport) {
89
            $options |= JSON_PRESERVE_ZERO_FRACTION;
90
        }
91
        return $options;
92
    }
93
94
    /**
95
     * Execute post-encoding actions
96
     *
97
     * @param string $encoded
98
     * @return string
99
     */
100
    protected function processEncodedValue($encoded)
101
    {
102
        if (!$this->preserveZeroFractionSupport) {
103
            $encoded = preg_replace('/"' . static::FLOAT_ADAPTER . '\((.*?)\)"/', '\1', $encoded);
104
        }
105
        return $encoded;
106
    }
107
108
    /**
109
     * Unserialize the value from JSON
110
     *
111
     * @param string $value
112
     * @return mixed
113
     */
114
    public function unserialize($value)
115
    {
116
        $this->reset();
117
        $data = json_decode($value, true);
118
        if ($data === null && json_last_error() != JSON_ERROR_NONE) {
119
            throw new JsonSerializerException('Invalid JSON to unserialize.');
120
        }
121
        return $this->unserializeData($data);
122
    }
123
124
    /**
125
     * Parse the data to be json encoded
126
     *
127
     * @param mixed $value
128
     * @return mixed
129
     * @throws Zumba\JsonSerializer\Exception\JsonSerializerException
130
     */
131
    protected function serializeData($value)
132
    {
133
        if (is_scalar($value) || $value === null) {
134
            if (!$this->preserveZeroFractionSupport && is_float($value) && ctype_digit((string)$value)) {
135
                // Because the PHP bug #50224, the float numbers with no
136
                // precision numbers are converted to integers when encoded
137
                $value = static::FLOAT_ADAPTER . '(' . $value . '.0)';
138
            }
139
            return $value;
140
        }
141
        if (is_resource($value)) {
142
            throw new JsonSerializerException('Resource is not supported in JsonSerializer');
143
        }
144
        if (is_array($value)) {
145
            return array_map(array($this, __FUNCTION__), $value);
146
        }
147
        if ($value instanceof \Closure) {
148
            if (!$this->closureSerializer) {
149
                throw new JsonSerializerException('Closure serializer not given. Unable to serialize closure.');
150
            }
151
            return array(
152
                static::CLOSURE_IDENTIFIER_KEY => true,
153
                'value' => $this->closureSerializer->serialize($value)
154
            );
155
        }
156
        return $this->serializeObject($value);
157
    }
158
159
    /**
160
     * Extract the data from an object
161
     *
162
     * @param object $value
163
     * @return array
164
     */
165
    protected function serializeObject($value)
166
    {
167
        $ref = new ReflectionClass($value);
168
169
        if ($this->objectStorage->contains($value)) {
170
            return array(static::CLASS_IDENTIFIER_KEY => '@' . $this->objectStorage[$value]);
171
        }
172
        $this->objectStorage->attach($value, $this->objectMappingIndex++);
173
174
        $paramsToSerialize = $this->getObjectProperties($ref, $value);
175
        $data = array(static::CLASS_IDENTIFIER_KEY => $ref->getName());
176
        $data += array_map(array($this, 'serializeData'), $this->extractObjectData($value, $ref, $paramsToSerialize));
177
        return $data;
178
    }
179
180
    /**
181
     * Return the list of properties to be serialized
182
     *
183
     * @param ReflectionClass $ref
184
     * @param object $value
185
     * @return array
186
     */
187
    protected function getObjectProperties($ref, $value)
188
    {
189
        if (method_exists($value, '__sleep')) {
190
            return $value->__sleep();
191
        }
192
193
        $props = array();
194
        foreach ($ref->getProperties() as $prop) {
195
            $props[] = $prop->getName();
196
        }
197
        return array_unique(array_merge($props, array_keys(get_object_vars($value))));
198
    }
199
200
    /**
201
     * Extract the object data
202
     *
203
     * @param object $value
204
     * @param ReflectionClass $ref
205
     * @param array $properties
206
     * @return array
207
     */
208
    protected function extractObjectData($value, $ref, $properties)
209
    {
210
        $data = array();
211
        foreach ($properties as $property) {
212
            try {
213
                $propRef = $ref->getProperty($property);
214
                $propRef->setAccessible(true);
215
                $data[$property] = $propRef->getValue($value);
216
            } catch (ReflectionException $e) {
217
                $data[$property] = $value->$property;
218
            }
219
        }
220
        return $data;
221
    }
222
223
    /**
224
     * Parse the json decode to convert to objects again
225
     *
226
     * @param mixed $value
227
     * @return mixed
228
     */
229
    protected function unserializeData($value)
230
    {
231
        if (is_scalar($value) || $value === null) {
232
            return $value;
233
        }
234
235
        if (isset($value[static::CLASS_IDENTIFIER_KEY])) {
236
            return $this->unserializeObject($value);
0 ignored issues
show
Documentation introduced by
$value is of type object|array, but the function expects a object<Zumba\JsonSerializer\aray>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
237
        }
238
239
        if (!empty($value[static::CLOSURE_IDENTIFIER_KEY])) {
240
            if (!$this->closureSerializer) {
241
                throw new JsonSerializerException('Closure serializer not provided to unserialize closure');
242
            }
243
            return $this->closureSerializer->unserialize($value['value']);
244
        }
245
246
        return array_map(array($this, __FUNCTION__), $value);
247
    }
248
249
    /**
250
     * Convert the serialized array into an object
251
     *
252
     * @param aray $value
253
     * @return object
254
     * @throws Zumba\JsonSerializer\Exception\JsonSerializerException
255
     */
256
    protected function unserializeObject($value)
257
    {
258
        $className = $value[static::CLASS_IDENTIFIER_KEY];
259
        unset($value[static::CLASS_IDENTIFIER_KEY]);
260
261
        if ($className[0] === '@') {
262
            $index = substr($className, 1);
263
            return $this->objectMapping[$index];
264
        }
265
266
        if (!class_exists($className)) {
267
            throw new JsonSerializerException('Unable to find class ' . $className);
268
        }
269
270
        if ($className === 'DateTime') {
271
            $obj = $this->restoreUsingUnserialize($className, $value);
272
            $this->objectMapping[$this->objectMappingIndex++] = $obj;
273
            return $obj;
274
        }
275
276
        $ref = new ReflectionClass($className);
277
        $obj = $ref->newInstanceWithoutConstructor();
278
        $this->objectMapping[$this->objectMappingIndex++] = $obj;
279
        foreach ($value as $property => $propertyValue) {
280
            try {
281
                $propRef = $ref->getProperty($property);
282
                $propRef->setAccessible(true);
283
                $propRef->setValue($obj, $this->unserializeData($propertyValue));
284
            } catch (ReflectionException $e) {
285
                $obj->$property = $this->unserializeData($propertyValue);
286
            }
287
        }
288
        if (method_exists($obj, '__wakeup')) {
289
            $obj->__wakeup();
290
        }
291
        return $obj;
292
    }
293
294
    protected function restoreUsingUnserialize($className, $attributes)
295
    {
296
        $obj = (object)$attributes;
297
        $serialized = preg_replace('|^O:\d+:"\w+":|', 'O:' . strlen($className) . ':"' . $className . '":', serialize($obj));
298
        return unserialize($serialized);
299
    }
300
301
    /**
302
     * Reset variables
303
     *
304
     * @return void
305
     */
306
    protected function reset()
307
    {
308
        $this->objectStorage = new SplObjectStorage();
309
        $this->objectMapping = array();
310
        $this->objectMappingIndex = 0;
311
    }
312
}
313