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 ( 0a00a9...96765b )
by Juan
01:43
created

JsonSerializer::serializeData()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 1 Features 2
Metric Value
c 8
b 1
f 2
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\Util;
4
5
use ReflectionClass;
6
use ReflectionException;
7
use SplObjectStorage;
8
use Zumba\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\Util\SuperC...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\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
        return $this->unserializeData(json_decode($value, true));
118
    }
119
120
    /**
121
     * Parse the data to be json encoded
122
     *
123
     * @param mixed $value
124
     * @return mixed
125
     * @throws Zumba\Exception\JsonSerializerException
126
     */
127
    protected function serializeData($value)
128
    {
129
        if (is_scalar($value) || $value === null) {
130
            if (!$this->preserveZeroFractionSupport && is_float($value) && strpos((string)$value, '.') === false) {
131
                // Because the PHP bug #50224, the float numbers with no
132
                // precision numbers are converted to integers when encoded
133
                $value = static::FLOAT_ADAPTER . '(' . $value . '.0)';
134
            }
135
            return $value;
136
        }
137
        if (is_resource($value)) {
138
            throw new JsonSerializerException('Resource is not supported in JsonSerializer');
139
        }
140
        if (is_array($value)) {
141
            return array_map(array($this, __FUNCTION__), $value);
142
        }
143
        if ($value instanceof \Closure) {
144
            if (!$this->closureSerializer) {
145
                throw new JsonSerializerException('Closure serializer not given. Unable to serialize closure.');
146
            }
147
            return array(
148
                static::CLOSURE_IDENTIFIER_KEY => true,
149
                'value' => $this->closureSerializer->serialize($value)
150
            );
151
        }
152
        return $this->serializeObject($value);
153
    }
154
155
    /**
156
     * Extract the data from an object
157
     *
158
     * @param object $value
159
     * @return array
160
     */
161
    protected function serializeObject($value)
162
    {
163
        $ref = new ReflectionClass($value);
164
165
        if ($this->objectStorage->contains($value)) {
166
            return array(static::CLASS_IDENTIFIER_KEY => '@' . $this->objectStorage[$value]);
167
        }
168
        $this->objectStorage->attach($value, $this->objectMappingIndex++);
169
170
        $paramsToSerialize = $this->getObjectProperties($ref, $value);
171
        $data = array(static::CLASS_IDENTIFIER_KEY => $ref->getName());
172
        $data += array_map(array($this, 'serializeData'), $this->extractObjectData($value, $ref, $paramsToSerialize));
173
        return $data;
174
    }
175
176
    /**
177
     * Return the list of properties to be serialized
178
     *
179
     * @param ReflectionClass $ref
180
     * @param object $value
181
     * @return array
182
     */
183
    protected function getObjectProperties($ref, $value)
184
    {
185
        if (method_exists($value, '__sleep')) {
186
            return $value->__sleep();
187
        }
188
189
        $props = array();
190
        foreach ($ref->getProperties() as $prop) {
191
            $props[] = $prop->getName();
192
        }
193
        return array_unique(array_merge($props, array_keys(get_object_vars($value))));
194
    }
195
196
    /**
197
     * Extract the object data
198
     *
199
     * @param object $value
200
     * @param ReflectionClass $ref
201
     * @param array $properties
202
     * @return array
203
     */
204
    protected function extractObjectData($value, $ref, $properties)
205
    {
206
        $data = array();
207
        foreach ($properties as $property) {
208
            try {
209
                $propRef = $ref->getProperty($property);
210
                $propRef->setAccessible(true);
211
                $data[$property] = $propRef->getValue($value);
212
            } catch (ReflectionException $e) {
213
                $data[$property] = $value->$property;
214
            }
215
        }
216
        return $data;
217
    }
218
219
    /**
220
     * Parse the json decode to convert to objects again
221
     *
222
     * @param mixed $value
223
     * @return mixed
224
     */
225
    protected function unserializeData($value)
226
    {
227
        if (is_scalar($value) || $value === null) {
228
            return $value;
229
        }
230
231
        if (isset($value[static::CLASS_IDENTIFIER_KEY])) {
232
            return $this->unserializeObject($value);
0 ignored issues
show
Documentation introduced by
$value is of type object|array, but the function expects a object<Zumba\Util\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...
233
        }
234
235
        if (!empty($value[static::CLOSURE_IDENTIFIER_KEY])) {
236
            if (!$this->closureSerializer) {
237
                throw new JsonSerializerException('Closure serializer not provided to unserialize closure');
238
            }
239
            return $this->closureSerializer->unserialize($value['value']);
240
        }
241
242
        return array_map(array($this, __FUNCTION__), $value);
243
    }
244
245
    /**
246
     * Convert the serialized array into an object
247
     *
248
     * @param aray $value
249
     * @return object
250
     * @throws Zumba\Exception\JsonSerializerException
251
     */
252
    protected function unserializeObject($value)
253
    {
254
        $className = $value[static::CLASS_IDENTIFIER_KEY];
255
        unset($value[static::CLASS_IDENTIFIER_KEY]);
256
257
        if ($className[0] === '@') {
258
            $index = substr($className, 1);
259
            return $this->objectMapping[$index];
260
        }
261
262
        if (!class_exists($className)) {
263
            throw new JsonSerializerException('Unable to find class ' . $className);
264
        }
265
266
        if ($className === 'DateTime') {
267
            $obj = $this->restoreUsingUnserialize($className, $value);
268
            $this->objectMapping[$this->objectMappingIndex++] = $obj;
269
            return $obj;
270
        }
271
272
        $ref = new ReflectionClass($className);
273
        $obj = $ref->newInstanceWithoutConstructor();
274
        $this->objectMapping[$this->objectMappingIndex++] = $obj;
275
        foreach ($value as $property => $propertyValue) {
276
            try {
277
                $propRef = $ref->getProperty($property);
278
                $propRef->setAccessible(true);
279
                $propRef->setValue($obj, $this->unserializeData($propertyValue));
280
            } catch (ReflectionException $e) {
281
                $obj->$property = $this->unserializeData($propertyValue);
282
            }
283
        }
284
        if (method_exists($obj, '__wakeup')) {
285
            $obj->__wakeup();
286
        }
287
        return $obj;
288
    }
289
290
    protected function restoreUsingUnserialize($className, $attributes)
291
    {
292
        $obj = (object)$attributes;
293
        $serialized = preg_replace('|^O:\d+:"\w+":|', 'O:' . strlen($className) . ':"' . $className . '":', serialize($obj));
294
        return unserialize($serialized);
295
    }
296
297
    /**
298
     * Reset variables
299
     *
300
     * @return void
301
     */
302
    protected function reset()
303
    {
304
        $this->objectStorage = new SplObjectStorage();
305
        $this->objectMapping = array();
306
        $this->objectMappingIndex = 0;
307
    }
308
}
309