Test Failed
Pull Request — master (#32)
by Sergei
02:19
created

Json::htmlEncode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
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 get_object_vars;
15
use function json_decode;
16
use function json_encode;
17
use function is_array;
18
use function is_object;
19
use function iterator_to_array;
20
21
/**
22
 * Json is a helper class providing JSON data encoding and decoding.
23
 * It enhances the PHP built-in functions `json_encode()` and `json_decode()`
24
 * by throwing exceptions when decoding fails.
25
 */
26
final class Json
27
{
28
    /**
29
     * Encodes the given value into a JSON string.
30
     *
31
     * Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification.
32
     * You must ensure strings passed to this method have proper encoding before passing them.
33
     *
34
     * @param mixed $value The data to be encoded.
35
     * @param int $options The encoding options. For more details please refer to
36
     * {@see http://www.php.net/manual/en/function.json-encode.php}.
37
     * Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR`.
38
     * @param int $depth The maximum depth.
39
     *
40
     * @psalm-param int<1, 2147483647> $depth
41
     *
42
     * @throws JsonException if there is any encoding error.
43
     *
44
     * @return string The encoding result.
45
     */
46 25
    public static function encode(
47
        $value,
48
        int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR,
49
        int $depth = 512
50
    ): string {
51 25
        if (is_array($value)) {
52 5
            $value = self::processArray($value);
53 21
        } elseif (is_object($value)) {
54
            /** @psalm-var mixed $value */
55 17
            $value = self::processObject($value);
0 ignored issues
show
Bug introduced by
The method processObject() does not exist on Yiisoft\Json\Json. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
            /** @scrutinizer ignore-call */ 
56
            $value = self::processObject($value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
56
        }
57
58 25
        return json_encode($value, JSON_THROW_ON_ERROR | $options, $depth);
59
    }
60
61
    /**
62
     * Encodes the given value into a JSON string HTML-escaping entities so it is safe to be embedded in HTML code.
63
     *
64
     * Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification.
65
     * You must ensure strings passed to this method have proper encoding before passing them.
66
     *
67
     * @param mixed $value The data to be encoded.
68
     *
69
     * @throws JsonException If there is any encoding error.
70
     *
71
     * @return string The encoding result.
72
     */
73 6
    public static function htmlEncode($value): string
74
    {
75 6
        return self::encode(
76 6
            $value,
77 6
            JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_THROW_ON_ERROR
78 6
        );
79
    }
80
81
    /**
82
     * Decodes the given JSON string into a PHP data structure.
83
     *
84
     * @param string $json The JSON string to be decoded.
85
     * @param bool $asArray Whether to return objects in terms of associative arrays.
86
     * @param int $depth The recursion depth.
87
     * @param int $options The decode options.
88
     *
89
     * @psalm-param int<1, 2147483647> $depth
90
     *
91
     * @throws JsonException If there is any decoding error.
92
     *
93
     * @return mixed The PHP data.
94
     */
95 6
    public static function decode(
96
        string $json,
97
        bool $asArray = true,
98
        int $depth = 512,
99
        int $options = JSON_THROW_ON_ERROR
100
    ) {
101 6
        if ($json === '') {
102 1
            return null;
103
        }
104 5
        return json_decode($json, $asArray, $depth, JSON_THROW_ON_ERROR | $options);
105
    }
106
107
    /**
108
     * Pre-processes the array before sending it to `json_encode()`.
109
     *
110
     * @param array $data The array to be processed.
111
     *
112
     * @return array The processed array.
113
     */
114 15
    private static function processArray(array $data): array
115
    {
116
        /** @psalm-var mixed $value */
117 15
        foreach ($data as $key => $value) {
118 10
            if (is_array($value)) {
119 2
                $data[$key] = self::processArray($value);
120 10
            } elseif (is_object($value)) {
121
                /** @psalm-var mixed */
122 2
                $data[$key] = self::processObject($value);
123
            }
124
        }
125
126 15
        return $data;
127
    }
128
129
    /**
130
     * Pre-processes the object before sending it to `json_encode()`.
131
     *
132
     * @param object $data The object to be processed.
133
     *
134
     * @return mixed The processed data.
135
     */
136 18
    private static function processData($data)
0 ignored issues
show
Unused Code introduced by
The method processData() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
137
    {
138 18
        if ($data instanceof JsonSerializable) {
139
            /** @psalm-var mixed $data */
140 6
            $data = $data->jsonSerialize();
141
142 6
            if (is_array($data)) {
143 4
                return self::processArray($data);
144
            }
145
146 2
            if (is_object($data)) {
147 1
                return self::processObject($data);
148
            }
149
150 1
            return $data;
151
        }
152
153 14
        if ($data instanceof DateTimeInterface) {
154 2
            return $data;
155
        }
156
157 12
        if ($data instanceof SimpleXMLElement) {
158 4
            return (array)$data ?: new stdClass();
159
        }
160
161 8
        if ($data instanceof Traversable) {
162 1
            return self::processArray(iterator_to_array($data)) ?: new stdClass();
163
        }
164
165 7
        return self::processArray(get_object_vars($data)) ?: new stdClass();
166
    }
167
}
168