Passed
Pull Request — master (#41)
by Sergei
02:08
created

Json::processData()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 39
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 11

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 11
eloc 19
c 2
b 0
f 0
nc 10
nop 1
dl 0
loc 39
ccs 19
cts 19
cp 1
crap 11
rs 7.3166

1 Method

Rating   Name   Duplication   Size   Complexity  
A Json::processArray() 0 13 4

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
declare(strict_types=1);
4
5
namespace Yiisoft\Json;
6
7
use DateTimeInterface;
8
use JsonException;
9
use JsonSerializable;
10
use SimpleXMLElement;
11
use stdClass;
12
use Traversable;
13
14
use function json_decode;
15
use function json_encode;
16
use function is_array;
17
use function is_object;
18
use function iterator_to_array;
19
20
/**
21
 * Json is a helper class providing JSON data encoding and decoding.
22
 * It enhances the PHP built-in functions `json_encode()` and `json_decode()`
23
 * by throwing exceptions when decoding fails.
24
 */
25
final class Json
26
{
27
    /**
28
     * Encodes the given value into a JSON string.
29
     *
30
     * Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification.
31
     * You must ensure strings passed to this method have proper encoding before passing them.
32
     *
33
     * @param mixed $value The data to be encoded.
34
     * @param int $options The encoding options. For more details please refer to
35
     * {@see http://www.php.net/manual/en/function.json-encode.php}.
36
     * Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR`.
37
     * @param int $depth The maximum depth.
38
     *
39
     * @psalm-param int<1, 2147483647> $depth
40
     *
41
     * @throws JsonException if there is any encoding error.
42
     *
43
     * @return string The encoding result.
44
     */
45 23
    public static function encode(
46
        $value,
47
        int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
48
        int $depth = 512
49
    ): string {
50 23
        if (is_array($value)) {
51 5
            $value = self::processArray($value);
52 19
        } elseif (is_object($value)) {
53
            /** @psalm-var mixed $value */
54 15
            $value = self::processObject($value);
55
        }
56
57 23
        return json_encode($value, JSON_THROW_ON_ERROR | $options, $depth);
58
    }
59
60
    /**
61
     * Encodes the given value into a JSON string HTML-escaping entities so it is safe to be embedded in HTML code.
62
     *
63
     * Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification.
64
     * You must ensure strings passed to this method have proper encoding before passing them.
65
     *
66
     * @param mixed $value The data to be encoded.
67
     *
68
     * @throws JsonException If there is any encoding error.
69
     *
70
     * @return string The encoding result.
71
     */
72 6
    public static function htmlEncode($value): string
73
    {
74 6
        return self::encode(
75 6
            $value,
76 6
            JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_THROW_ON_ERROR
77 6
        );
78
    }
79
80
    /**
81
     * Decodes the given JSON string into a PHP data structure.
82
     *
83
     * @param string $json The JSON string to be decoded.
84
     * @param bool $asArray Whether to return objects in terms of associative arrays.
85
     * @param int $depth The recursion depth.
86
     * @param int $options The decode options.
87
     *
88
     * @psalm-param int<1, 2147483647> $depth
89
     *
90
     * @throws JsonException If there is any decoding error.
91
     *
92
     * @return mixed The PHP data.
93
     */
94 6
    public static function decode(
95
        string $json,
96
        bool $asArray = true,
97
        int $depth = 512,
98
        int $options = JSON_THROW_ON_ERROR
99
    ) {
100 6
        if ($json === '') {
101 1
            return null;
102
        }
103 5
        return json_decode($json, $asArray, $depth, JSON_THROW_ON_ERROR | $options);
104
    }
105
106
    /**
107
     * Pre-processes the array before sending it to `json_encode()`.
108
     *
109
     * @param array $data The array to be processed.
110
     *
111
     * @return array The processed array.
112
     */
113 14
    private static function processArray(array $data): array
114
    {
115
        /** @psalm-var mixed $value */
116 14
        foreach ($data as $key => $value) {
117 9
            if (is_array($value)) {
118 2
                $data[$key] = self::processArray($value);
119 9
            } elseif (is_object($value)) {
120
                /** @psalm-var mixed */
121 2
                $data[$key] = self::processObject($value);
122
            }
123
        }
124
125 14
        return $data;
126
    }
127
128
    /**
129
     * Pre-processes the object before sending it to `json_encode()`.
130
     *
131
     * @param object $data The object to be processed.
132
     *
133
     * @return mixed The processed data.
134
     */
135 16
    private static function processObject(object $data)
136
    {
137 16
        if ($data instanceof JsonSerializable) {
138
            /** @psalm-var mixed $data */
139 5
            $data = $data->jsonSerialize();
140
141 5
            if (is_array($data)) {
142 4
                return self::processArray($data);
143
            }
144
145 1
            if (is_object($data)) {
146 1
                return self::processObject($data);
147
            }
148
149
            return $data;
150
        }
151
152 13
        if ($data instanceof DateTimeInterface) {
153 2
            return $data;
154
        }
155
156 11
        if ($data instanceof SimpleXMLElement) {
157 4
            return (array)$data ?: new stdClass();
158
        }
159
160 7
        if ($data instanceof Traversable) {
161 1
            return self::processArray(iterator_to_array($data)) ?: new stdClass();
162
        }
163
164 6
        return self::processArray((array)$data) ?: new stdClass();
165
    }
166
}
167