Test Failed
Push — master ( a1e735...534e7d )
by Bálint
13:42 queued 13s
created

JsonWriter::endScope()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 13
c 0
b 0
f 0
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
namespace POData\Writers\Json;
4
5
6
use POData\Writers\Json\IndentedTextWriter;
7
8
/**
9
 * Class JsonWriter
10
 * @package POData\Writers\Json
11
 */
12
class JsonWriter
13
{
14
    /**
15
     * Json datetime format.
16
     *
17
     */
18
    private $_jsonDateTimeFormat = "\/Date(%s)\/";
0 ignored issues
show
introduced by
The private property $_jsonDateTimeFormat is not used, and could be removed.
Loading history...
19
20
21
    /**
22
     * Writer to write text into
23
     *
24
     */
25
    private $_writer;
26
27
    /**
28
     * scope of the json text - object, array, etc
29
     *
30
     */
31
    private $_scopes = array();
32
33
    /**
34
     * Various scope types for Json writer
35
     *
36
     */
37
    private $_scopeType = array('Array' => 0, 'Object' => 1);
38
39
    /**
40
     * Creates a new instance of Json writer
41
     *
42
     * @param string $writer writer to which text needs to be written
43
     */
44
    public function __construct($writer)
45
    {
46
        $this->_writer = new IndentedTextWriter($writer);
47
48
    }
49
50
    public function clear()
51
    {
52
        $this->_writer->clear();
53
    }
54
55
    /**
56
     * End the current scope
57
     *
58
     * @return JsonWriter
59
     */
60
    public function endScope()
61
    {
62
        $this->_writer
63
            ->writeLine()
64
            ->decreaseIndent();
65
66
        if (array_pop($this->_scopes)->type == $this->_scopeType['Array']) {
67
            $this->_writer->writeValue("]");
68
        } else {
69
            $this->_writer->writeValue("}");
70
        }
71
72
        return $this;
73
74
    }
75
76
    /**
77
     * Start the array scope
78
     *
79
     * @return JsonWriter
80
     */
81
    public function startArrayScope()
82
    {
83
        $this->_startScope($this->_scopeType['Array']);
84
        return $this;
85
    }
86
87
88
    /**
89
     * Write the "results" header for the data array
90
     *
91
     * @return JsonWriter
92
     */
93
    public function writeDataArrayName()
94
    {
95
        $this->writeName($this->dataArrayName);
0 ignored issues
show
Bug Best Practice introduced by
The property dataArrayName does not exist on POData\Writers\Json\JsonWriter. Did you maybe forget to declare it?
Loading history...
96
        return $this;
97
    }
98
99
    /**
100
     * Start the object scope
101
     *
102
     * @return JsonWriter
103
     */
104
    public function startObjectScope()
105
    {
106
        $this->_startScope($this->_scopeType['Object']);
107
        return $this;
108
    }
109
110
    /**
111
     * Write the name for the object property
112
     *
113
     * @param string $name name of the object property
114
     *
115
     * @return JsonWriter
116
     */
117
    public function writeName($name)
118
    {
119
        $currentScope = end($this->_scopes);
120
        if ($currentScope && $currentScope->type == $this->_scopeType['Object']) {
121
            if ($currentScope->objectCount != 0) {
122
                $this->_writer->writeTrimmed(", ");
123
            }
124
125
            $currentScope->objectCount++;
126
        }
127
128
        $this->_writeCore($name, true /*quotes*/);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $quotes of POData\Writers\Json\JsonWriter::_writeCore(). ( Ignorable by Annotation )

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

128
        $this->_writeCore($name, /** @scrutinizer ignore-type */ true /*quotes*/);
Loading history...
129
        $this->_writer->writeTrimmed(": ");
130
131
        return $this;
132
    }
133
134
    /**
135
     * JSON write a basic data type (string, number, boolean, null)
136
     *
137
     * @param mixed  $value value to be written
138
     * @param string $type  data type of the value
139
     *
140
     * @return JsonWriter
141
     */
142
    public function writeValue($value, $type = null)
143
    {
144
        switch ($type) {
145
            case 'Edm.Boolean':
146
            case 'Edm.Int16':
147
            case 'Edm.Int32':
148
            case 'Edm.Byte':
149
            case 'Edm.SByte':
150
                $this->_writeCore($value, /* quotes */ false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $quotes of POData\Writers\Json\JsonWriter::_writeCore(). ( Ignorable by Annotation )

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

150
                $this->_writeCore($value, /* quotes */ /** @scrutinizer ignore-type */ false);
Loading history...
151
                break;
152
153
154
            case 'Edm.Int64':
155
            case 'Edm.Guid':
156
            case 'Edm.Decimal':
157
            case 'Edm.Binary':
158
                $this->_writeCore($value, /* quotes */ true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $quotes of POData\Writers\Json\JsonWriter::_writeCore(). ( Ignorable by Annotation )

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

158
                $this->_writeCore($value, /* quotes */ /** @scrutinizer ignore-type */ true);
Loading history...
159
                break;
160
161
            case 'Edm.Single':
162
            case 'Edm.Double':
163
                if (is_infinite($value) || is_nan($value)) {
164
                    $this->_writeCore("null", /* quotes */ true);
165
                } else {
166
                    $this->_writeCore($value, /* quotes */ false);
167
                }
168
169
                break;
170
171
172
            case 'Edm.DateTime':
173
                $dateTime = new \DateTime($value, new \DateTimeZone('UTC'));
174
                $formattedDateTime = $dateTime->format('Y-m-d\TH:i:s');
175
                $this->_writeCore($formattedDateTime, /* quotes */ true);
176
                break;
177
178
179
            case 'Edm.String':
180
                if (is_null($value)) {
181
                    $this->_writeCore("null", /* quotes */ false);
182
                } else {
183
                    $jsonEncoded = json_encode($value);
184
                    //json_encode always escapes a solidus (forward slash, %x2F),
185
                    //this will be a problem when encoding urls
186
                    //JSON_UNESCAPED_SLASHES not available in earlier versions of php 5.3
187
                    //So removing escaping forward slashes manually
188
                    $jsonEncoded = str_replace('\\/', '/', $jsonEncoded);
189
                    //since json_encode is already appending chords
190
                    //there is no need to set it again
191
                    $this->_writeCore($jsonEncoded, /* quotes */ false);
192
                }
193
                break;
194
195
196
            default:
197
                $this->_writeCore($this->_quoteJScriptString($value), /* quotes */ true);
198
        }
199
200
        return $this;
201
    }
202
203
    /**
204
     * Returns the string value with special characters escaped
205
     *
206
     * @param string $string input string value
207
     *
208
     * Returns the string value with special characters escaped.
209
     *
210
     * @return string
211
     */
212
    private function _quoteJScriptString($string)
213
    {
214
        // Escape ( " \ / \n \r \t \b \f) characters with a backslash.
215
        $search  = array('\\', "\n", "\t", "\r", "\b", "\f", '"');
216
        $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"');
217
        $processedString = str_replace($search, $replace, $string);
218
        // Escape some ASCII characters(0x08, 0x0c)
219
        $processedString = str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $processedString);
220
        return $processedString;
221
    }
222
223
    /**
224
     * Write the string value with/without quotes
225
     *
226
     * @param string $text   value to be written
227
     * @param string $quotes put quotes around the value if this value is true
228
     *
229
     * @return void
230
     */
231
    private function _writeCore($text, $quotes)
232
    {
233
        if (count($this->_scopes) != 0) {
234
            $currentScope = end($this->_scopes);
235
            if ($currentScope->type == $this->_scopeType['Array']) {
236
                if ($currentScope->objectCount != 0) {
237
                    $this->_writer->writeTrimmed(", ");
238
                }
239
240
                $currentScope->objectCount++;
241
            }
242
        }
243
244
        if ($quotes && $text !== 'null') {
245
            $this->_writer->writeValue('"');
246
        }
247
248
        $this->_writer->writeValue($text);
249
        if ($quotes && $text !== 'null') {
250
            $this->_writer->writeValue('"');
251
        }
252
    }
253
254
    /**
255
     * Start the scope given the scope type
256
     *
257
     * @param int $type scope type
258
     *
259
     * @return void
260
     */
261
    private function _startScope($type)
262
    {
263
        if (count($this->_scopes) != 0) {
264
            $currentScope = end($this->_scopes);
265
            if (($currentScope->type == $this->_scopeType['Array'])
266
                && ($currentScope->objectCount != 0)
267
            ) {
268
                $this->_writer->writeTrimmed(", ");
269
            }
270
271
            $currentScope->objectCount++;
272
        }
273
274
        $scope = new Scope($type);
275
        array_push($this->_scopes, $scope);
276
277
        if ($type == $this->_scopeType['Array']) {
278
            $this->_writer->writeValue("[");
279
        } else {
280
            $this->_writer->writeValue("{");
281
        }
282
283
        $this->_writer
284
            ->increaseIndent()
285
            ->writeLine();
286
    }
287
288
    /**
289
     * return the indented result
290
     *
291
     * @return string
292
     */
293
    public function getJsonOutput()
294
    {
295
        return $this->_writer->getResult();
296
    }
297
}
298
299
300
301
/**
302
 * class representing scope information
303
*
304
 */
305
class Scope
306
{
307
    /**
308
     * keeps the count of the nested scopes
309
     *
310
     */
311
    public $objectCount;
312
313
    /**
314
     *  keeps the type of the scope
315
     *
316
     */
317
    public $type;
318
319
    /**
320
     * Creates a new instance of scope type
321
     *
322
     * @param int $type type of the scope
323
     */
324
    public function __construct($type)
325
    {
326
        $this->type = $type;
327
        $this->objectCount = 0;
328
    }
329
330
}
331