HalJsonFormat::encode()   F
last analyzed

Complexity

Conditions 16
Paths 320

Size

Total Lines 71
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 272

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 16
eloc 37
c 2
b 0
f 0
nc 320
nop 2
dl 0
loc 71
ccs 0
cts 38
cp 0
crap 272
rs 3.2333

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
namespace Aoe\Restler\System\Restler\Format;
4
5
use Luracast\Restler\Data\Obj;
6
use Luracast\Restler\Format\Format;
7
use Luracast\Restler\RestException;
8
9
/**
10
 * Javascript Object Notation Format
11
 *
12
 * @subpackage format
13
 * @copyright  2010 Luracast
14
 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
15
 * @link       http://luracast.com/products/restler/
16
 * @version    3.0.0rc6
17
 */
18
class HalJsonFormat extends Format
19
{
20
    /**
21
     * @var string
22
     */
23
    public const MIME = 'application/hal+json';
24
25
    /**
26
     * @var string
27
     */
28
    public const EXTENSION = 'json';
29
30
    /**
31
     * @var boolean|null  shim for json_encode option JSON_PRETTY_PRINT set
32
     * it to null to use smart defaults
33
     */
34
    public static ?bool $prettyPrint = null;
35
36
    /**
37
     * shim for json_encode option JSON_UNESCAPED_SLASHES
38
     * set it to null to use smart defaults
39
     */
40
    public static bool $unEscapedSlashes = false;
41
42
    /**
43
     * @var boolean|null  shim for json_encode JSON_UNESCAPED_UNICODE set it
44
     * to null to use smart defaults
45
     */
46
    public static ?bool $unEscapedUnicode = null;
47
48
    /**
49
     * @var boolean|null  shim for json_decode JSON_BIGINT_AS_STRING set it to
50
     * null to
51
     * use smart defaults
52
     */
53
    public static ?bool $bigIntAsString = null;
54
55
    /**
56
     * @var boolean|null  shim for json_decode JSON_NUMERIC_CHECK set it to
57
     * null to
58
     * use smart defaults
59
     */
60
    public static ?bool $numbersAsNumbers = null;
61
62
    public function encode($data, $humanReadable = false)
63
    {
64
        if (self::$prettyPrint !== null) {
65
            $humanReadable = self::$prettyPrint;
66
        }
67
68
        if (self::$unEscapedSlashes === null) {
0 ignored issues
show
introduced by
The condition self::unEscapedSlashes === null is always false.
Loading history...
69
            self::$unEscapedSlashes = $humanReadable;
70
        }
71
72
        if (self::$unEscapedUnicode === null) {
73
            self::$unEscapedUnicode = $this->charset == 'utf-8';
74
        }
75
76
        $options = 0;
77
78
        if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4
79
            || PHP_MAJOR_VERSION > 5 // PHP >= 6.0
80
        ) {
81
            if ($humanReadable) {
82
                $options |= JSON_PRETTY_PRINT;
83
            }
84
85
            if (self::$unEscapedSlashes) {
86
                $options |= JSON_UNESCAPED_SLASHES;
87
            }
88
89
            if (self::$bigIntAsString === true) {
90
                $options |= JSON_BIGINT_AS_STRING;
91
            }
92
93
            if (self::$unEscapedUnicode) {
94
                $options |= JSON_UNESCAPED_UNICODE;
95
            }
96
97
            if (self::$numbersAsNumbers === true) {
98
                $options |= JSON_NUMERIC_CHECK;
99
            }
100
101
            $result = json_encode(Obj::toArray($data, true), $options);
102
            $this->handleJsonError();
103
104
            return $result;
105
        }
106
107
        $result = json_encode(Obj::toArray($data, true), JSON_THROW_ON_ERROR);
108
        $this->handleJsonError();
109
110
        if ($humanReadable) {
111
            $result = $this->formatJson($result);
112
        }
113
114
        if (self::$unEscapedUnicode) {
115
            $result = preg_replace_callback(
116
                '/\\\u(\w\w\w\w)/',
117
                static function (array $matches) {
118
                    if (function_exists('mb_convert_encoding')) {
119
                        return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
120
                    }
121
122
                    return iconv('UTF-16BE', 'UTF-8', pack('H*', $matches[1]));
123
                },
124
                $result
125
            );
126
        }
127
128
        if (self::$unEscapedSlashes) {
129
            return str_replace('\/', '/', $result);
130
        }
131
132
        return $result;
133
    }
134
135
    public function decode($data): ?array
136
    {
137
        if (empty($data)) {
138
            return null;
139
        }
140
141
        $options = 0;
142
        if (self::$bigIntAsString === true) {
143
            if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4) // PHP >= 5.4
144
                || PHP_MAJOR_VERSION > 5 // PHP >= 6.0
145
            ) {
146
                $options |= JSON_BIGINT_AS_STRING;
147
            } else {
148
                $data = preg_replace(
149
                    '/:\s*(\-?\d+(\.\d+)?([e|E][\-|\+]\d+)?)/',
150
                    ': "$1"',
151
                    $data
152
                );
153
            }
154
        }
155
156
        try {
157
            $decoded = json_decode($data, false, 512, $options);
158
            $this->handleJsonError();
159
        } catch (\RuntimeException $runtimeException) {
160
            throw new RestException('400', $runtimeException->getMessage());
161
        }
162
163
        if (strlen($data) && $decoded === null || $decoded === $data) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (strlen($data) && $decod...) || $decoded === $data, Probably Intended Meaning: strlen($data) && ($decod... || $decoded === $data)
Loading history...
164
            throw new RestException('400', 'Error parsing JSON');
165
        }
166
167
        return Obj::toArray($decoded);
168
    }
169
170
    /**
171
     * Throws an exception if an error occurred during the last JSON encoding/decoding
172
     */
173
    protected function handleJsonError(): void
174
    {
175
        if (function_exists('json_last_error_msg') && json_last_error() !== JSON_ERROR_NONE) {
176
            // PHP >= 5.5.0
177
            $message = json_last_error_msg();
178
        } elseif (function_exists('json_last_error')) {
179
            // PHP >= 5.3.0
180
            switch (json_last_error()) {
181
                case JSON_ERROR_NONE:
182
                    break;
183
                case JSON_ERROR_DEPTH:
184
                    $message = 'maximum stack depth exceeded';
185
                    break;
186
                case JSON_ERROR_STATE_MISMATCH:
187
                    $message = 'underflow or the modes mismatch';
188
                    break;
189
                case JSON_ERROR_CTRL_CHAR:
190
                    $message = 'unexpected control character found';
191
                    break;
192
                case JSON_ERROR_SYNTAX:
193
                    $message = 'malformed JSON';
194
                    break;
195
                case JSON_ERROR_UTF8:
196
                    $message = 'malformed UTF-8 characters, possibly incorrectly encoded';
197
                    break;
198
                default:
199
                    $message = 'unknown error';
200
                    break;
201
            }
202
        }
203
204
        if (isset($message)) {
205
            throw new \RuntimeException('Error encoding/decoding JSON: ' . $message);
206
        }
207
    }
208
209
    /**
210
     * Pretty print JSON string
211
     */
212
    private function formatJson(string $json): string
213
    {
214
        $tab = '  ';
215
        $newJson = '';
216
        $indentLevel = 0;
217
        $inString = false;
218
        $len = strlen($json);
219
        for ($c = 0; $c < $len; ++$c) {
220
            $char = $json[$c];
221
            switch ($char) {
222
                case '{':
223
                case '[':
224
                    if (!$inString) {
225
                        $newJson .= $char . "\n" .
226
                            str_repeat($tab, $indentLevel + 1);
227
                        ++$indentLevel;
228
                    } else {
229
                        $newJson .= $char;
230
                    }
231
232
                    break;
233
                case '}':
234
                case ']':
235
                    if (!$inString) {
236
                        --$indentLevel;
237
                        $newJson .= "\n" .
238
                            str_repeat($tab, $indentLevel) . $char;
239
                    } else {
240
                        $newJson .= $char;
241
                    }
242
243
                    break;
244
                case ',':
245
                    if (!$inString) {
246
                        $newJson .= ",\n" .
247
                            str_repeat($tab, $indentLevel);
248
                    } else {
249
                        $newJson .= $char;
250
                    }
251
252
                    break;
253
                case ':':
254
                    if (!$inString) {
255
                        $newJson .= ': ';
256
                    } else {
257
                        $newJson .= $char;
258
                    }
259
260
                    break;
261
                case '"':
262
                    if ($c == 0) {
263
                        $inString = true;
264
                    } elseif ($c > 0 && $json[$c - 1] !== '\\') {
265
                        $inString = !$inString;
0 ignored issues
show
introduced by
The condition $inString is always false.
Loading history...
266
                    }
267
                    // fall-through
268
                    // no break
269
                default:
270
                    $newJson .= $char;
271
                    break;
272
            }
273
        }
274
275
        return $newJson;
276
    }
277
}
278