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
Pull Request — master (#30)
by
unknown
13:50
created

Parser::getFormat()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 20
ccs 14
cts 14
cp 1
rs 8.8571
cc 6
eloc 10
nc 8
nop 1
crap 6
1
<?php
2
3
namespace Nathanmac\Utilities\Parser;
4
5
use Nathanmac\Utilities\Parser\Formats\BSON;
6
use Nathanmac\Utilities\Parser\Formats\FormatInterface;
7
use Nathanmac\Utilities\Parser\Formats\JSON;
8
use Nathanmac\Utilities\Parser\Formats\MSGPack;
9
use Nathanmac\Utilities\Parser\Formats\QueryStr;
10
use Nathanmac\Utilities\Parser\Formats\Serialize;
11
use Nathanmac\Utilities\Parser\Formats\XML;
12
use Nathanmac\Utilities\Parser\Formats\YAML;
13
14
/**
15
 * Parser Library, designed to parse payload data from various formats to php array.
16
 *
17
 * @package    Nathanmac\Utilities\Parser
18
 * @author     Nathan Macnamara <[email protected]>
19
 * @license    https://github.com/nathanmac/Parser/blob/master/LICENSE.md  MIT
20
 */
21
class Parser
22
{
23
    /**
24
     * @var string
25
     */
26
    private $wildcards = '/^(\*|%|:first|:last|:(index|item)\[\d+\])$/';
27
28
    /**
29
     * @var array Supported Formats
30
     */
31
    private $supported_formats = [
32
      // XML
33
        'application/xml' => XML::class,
34
        'text/xml'        => XML::class,
35
        'xml'             => XML::class,
36
      // JSON
37
        'application/json'         => JSON::class,
38
        'application/x-javascript' => JSON::class,
39
        'text/javascript'          => JSON::class,
40
        'text/x-javascript'        => JSON::class,
41
        'text/x-json'              => JSON::class,
42
        'json'                     => JSON::class,
43
      // BSON
44
        'application/bson' => BSON::class,
45
        'bson'             => BSON::class,
46
      // YAML
47
        'text/yaml'          => YAML::class,
48
        'text/x-yaml'        => YAML::class,
49
        'application/yaml'   => YAML::class,
50
        'application/x-yaml' => YAML::class,
51
        'yaml'               => YAML::class,
52
      // MSGPACK
53
        'application/msgpack'   => MSGPack::class,
54
        'application/x-msgpack' => MSGPack::class,
55
        'msgpack'               => MSGPack::class,
56
      // MISC
57
        'application/vnd.php.serialized'    => Serialize::class,
58
        'serialize'                         => Serialize::class,
59
        'application/x-www-form-urlencoded' => QueryStr::class,
60
        'querystr'                          => QueryStr::class,
61
    ];
62
63
    /* ------------ Access Methods/Helpers ------------ */
64
65 9
    /**
66
     * Get a subset of the items from the payload data.
67 9
     *
68
     * @param  string|array $keys
69 9
     *
70 9
     * @return array
71 9
     */
72 6
    public function only($keys)
73
    {
74 9
        $keys = is_array($keys) ? $keys : func_get_args();
75
76
        $results = [];
77
        foreach ($keys as $key) {
78
            $results = array_merge_recursive($results, $this->buildArray(explode('.', $key), $this->get($key)));
79
        }
80
81
        return $results;
82
    }
83 6
84
    /**
85 6
     * Get all of the input except for a specified array of items.
86
     *
87 6
     * @param  string|array  $keys
88
     * @return array
89 6
     */
90 6
    public function except($keys)
91 4
    {
92 6
        $keys = is_array($keys) ? $keys : func_get_args();
93
94
        $results = $this->payload();
95
96
        foreach ($keys as $key) {
97
            $this->removeValue($results, $key);
98
        }
99
        return $results;
100
    }
101
102 21
    /**
103
     * Determine if the payload contains a non-empty value for a given key.
104 21
     *
105
     * @param  string|array $keys
106 21
     *
107
     * @return bool
108 21
     */
109
    public function has($keys)
110 21
    {
111 21
        $keys = is_array($keys) ? $keys : func_get_args();
112 14
113 21
        $results = $this->payload();
114
115
        foreach ($keys as $value) {
116
            if ($this->hasValueAtKey($value, $results) === false) {
117
                return false;
118
            }
119
        }
120
        return true;
121
    }
122
123
    /**
124 18
     * Retrieve an payload item from the payload data, return default item if item not found.
125
     *
126 18
     * @param string $key
127 18
     * @param string $default
128
     *
129 9
     * @return mixed|null
130
     */
131
    public function get($key = null, $default = null)
132
    {
133
        if ($this->has($key)) {
134
            return $this->getValueAtKey($key, $this->payload());
135
        }
136
        return $default;
137
    }
138
139 3
    /**
140
     * Mask input data with a given mapping.
141 3
     *
142 3
     * @param array $mask
143 3
     *
144 2
     * @return array
145
     */
146 3
    public function mask(array $mask)
147
    {
148
        $keys = [];
149 View Code Duplication
        foreach ($mask as $key => $value) {
150
            $keys[] = $key . (is_array($value) ? $this->processMask($value) : '');
151
        }
152
153
        return $this->only($keys);
154
    }
155
156 3
    /**
157
     * Recursive processor for processing user masks.
158 3
     *
159 3
     * @param array $mask
160
     *
161
     * @return string
162
     */
163
    private function processMask($mask)
164
    {
165 View Code Duplication
        foreach ($mask as $key => $value) {
166
            return '.' . $key . (is_array($value) ? $this->processMask($value) : '');
167
        }
168
    }
169
170
    /**
171 57
     * Parse the HTTP payload data, autodetect format and return all data in array.
172
     *  Override the format by providing a content type.
173 57
     *
174
     * @param string $format
175
     *
176
     * @return array
177
     */
178
    public function payload($format = '')
179
    {
180
        $class = $this->getFormatClass($format);
181 3
        return $this->parse($this->getPayload(), new $class);
182
    }
183 3
184
    /**
185
     * Alias to the payload function.
186
     *
187
     * @return array
188
     */
189
    public function all()
190
    {
191 63
        return $this->payload();
192
    }
193 63
194 9
    /**
195
     * Autodetect the payload data type using content-type value.
196
     *
197 54
     * @return string Return the short format code (xml, json, ...).
198 36
     */
199 15
    public function getFormatClass($format = '')
0 ignored issues
show
Coding Style introduced by
getFormatClass uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
200 15
    {
201 10
        if ( ! empty($format)) {
202
            return $this->processContentType($format);
203 54
        }
204 36
205 24
        if (isset($_SERVER['CONTENT_TYPE'])) {
206 24
            $type = $this->processContentType($_SERVER['CONTENT_TYPE']);
207 2
            if ($type !== false) {
208
                return $type;
209 33
            }
210
        }
211
212
        if (isset($_SERVER['HTTP_CONTENT_TYPE'])) {
213
            $type = $this->processContentType($_SERVER['HTTP_CONTENT_TYPE']);
214
            if ($type !== false) {
215
                return $type;
216
            }
217
        }
218
219 33
        return JSON::class;
220
    }
221 33
222 33
    /**
223 33
     * Process the content-type values
224 31
     *
225
     * @param string $contentType Content-Type raw string
226 10
     *
227
     * @return bool|string
228 15
     */
229
    private function processContentType($contentType)
230
    {
231
        foreach (explode(';', $contentType) as $type) {
232
            $type = strtolower(trim($type));
233
            if (isset($this->supported_formats[$type])) {
234
                return $this->supported_formats[$type];
235
            }
236
        }
237
238
        return false;
239
    }
240
241
    /**
242
     * Return the payload data from the HTTP post request.
243
     *
244
     * @codeCoverageIgnore
245
     *
246
     * @return string
247
     */
248
    protected function getPayload()
249
    {
250
        return file_get_contents('php://input');
251 111
    }
252
253 111
    /**
254
     * Parse payload string using given formatter.
255
     *
256
     * @param string $payload
257
     * @param FormatInterface $format
258
     *
259
     * @return array
260
     */
261
    public function parse($payload, FormatInterface $format)
262
    {
263
        return $format->parse($payload);
264
    }
265
266
    /* ------------ Format Registration Methods ------------ */
267 21
268
    /**
269 21
     * Register Format Class.
270
     *
271
     * @param $format
272
     * @param $class
273
     *
274
     * @throws InvalidArgumentException
275
     *
276
     * @return self
277
     */
278
    public function registerFormat($format, $class)
279
    {
280
        if ( ! class_exists($class)) {
281 42
            throw new \InvalidArgumentException("Parser formatter class {$class} not found.");
282
        }
283 42
        if ( ! is_a($class, 'Nathanmac\Utilities\Parser\Formats\FormatInterface', true)) {
284
            throw new \InvalidArgumentException('Parser formatters must implement the Nathanmac\Utilities\Parser\Formats\FormatInterface interface.');
285
        }
286
287
        $this->supported_formats[$format] = $class;
288
289
        return $this;
290
    }
291
292
    /* ------------ Helper Methods ------------ */
293
294
    /**
295 6
     * XML parser, helper function.
296
     *
297 6
     * @param $payload
298
     *
299
     * @throws Exceptions\ParserException
300
     *
301
     * @return array
302
     */
303
    public function xml($payload)
304
    {
305
        return $this->parse($payload, new XML());
306
    }
307
308
    /**
309 15
     * JSON parser, helper function.
310
     *
311 15
     * @param $payload
312
     *
313
     * @throws Exceptions\ParserException
314
     * @return array
315
     */
316
    public function json($payload)
317
    {
318
        return $this->parse($payload, new JSON());
319
    }
320
321 9
    /**
322
     * BSON parser, helper function.
323 9
     *
324
     * @param $payload
325
     *
326
     * @throws Exceptions\ParserException
327
     *
328
     * @return array
329
     */
330
    public function bson($payload)
331
    {
332
        return $this->parse($payload, new BSON());
333
    }
334
335 12
    /**
336
     * Serialized Data parser, helper function.
337 12
     *
338
     * @param $payload
339
     *
340
     * @throws Exceptions\ParserException
341
     *
342
     * @return array
343
     */
344
    public function serialize($payload)
345
    {
346
        return $this->parse($payload, new Serialize());
347
    }
348
349 6
    /**
350
     * Query String parser, helper function.
351 6
     *
352
     * @param $payload
353
     *
354
     * @return array
355
     */
356
    public function querystr($payload)
357
    {
358
        return $this->parse($payload, new QueryStr());
359
    }
360
361
    /**
362
     * YAML parser, helper function.
363 18
     *
364
     * @param $payload
365 18
     *
366
     * @throws Exceptions\ParserException
367 18
     *
368
     * @return array
369 12
     */
370
    public function yaml($payload)
371
    {
372 12
        return $this->parse($payload, new Yaml());
373
    }
374 3
375 3
    /**
376 3
     * MSGPack parser, helper function.
377 2
     *
378 3
     * @param $payload
379 2
     *
380 3
     * @throws Exceptions\ParserException
381 3
     *
382 2
     * @return array
383 3
     */
384
    public function msgpack($payload)
385 3
    {
386
        return $this->parse($payload, new MSGPack());
387 2
    }
388 12
389 8
    /* ------------ Construction Methods ------------ */
390
391 12
    /**
392
     * Return a value from the array identified from the key.
393 8
     *
394
     * @param $key
395
     * @param $data
396 18
     * @return mixed
397 18
     */
398 6
    private function getValueAtKey($key, $data)
399 6
    {
400 6
        $keys = explode('.', $key);
401 4
402 6
        while (count($keys) > 1) {
403 4
            $key = array_shift($keys);
404 6
405 6
            // Wildcard Key
406 6
            if (preg_match($this->wildcards, $key) && is_array($data) && ! empty($data)) {
407
                // Shift the first item of the array
408 6 View Code Duplication
                if (preg_match('/^:(index|item)\[\d+\]$/', $key)) {
409
                    for ($x = substr($key, 7, -1); $x >= 0; $x--) {
410 15
                        if (empty($data)) {
411
                            return false;
412
                        }
413
                        $item = array_shift($data);
414
                    }
415
                } elseif ($key == ':last') {
416
                    $item = array_pop($data);
417
                } else {
418
                    $item = array_shift($data);
419
                }
420 21
                $data =& $item;
421
            } else {
422 21
                if ( ! isset($data[$key]) || ! is_array($data[$key])) {
423
                    return false;
424 21
                }
425
426 21
                $data =& $data[$key];
427
            }
428
        }
429 21
430
        // Return value
431 6
        $key = array_shift($keys);
432 6
        if (preg_match($this->wildcards, $key)) {
433 6
            if (preg_match('/^:(index|item)\[\d+\]$/', $key)) {
434 5
                for ($x = substr($key, 7, -1); $x >= 0; $x--) {
435 6
                    if (empty($data)) {
436 4
                        return false;
437 6
                    }
438 6
                    $item = array_shift($data);
439 4
                }
440 6
                return $item;
441
            } elseif ($key == ':last') {
442 6
                return array_pop($data);
443
            }
444 4
            return array_shift($data); // First Found
445 21
        }
446 19
        return ($data[$key]);
447
    }
448 21
449 15
    /**
450
     * Array contains a value identified from the key, returns bool
451 21
     *
452 16
     * @param $key
453
     * @param $data
454 21
     * @return bool
455
     */
456 14
    private function hasValueAtKey($key, $data)
457 21
    {
458
        $keys = explode('.', $key);
459
460
        while (count($keys) > 0) {
461
            $key = array_shift($keys);
462
463
            // Wildcard Key
464
            if (preg_match($this->wildcards, $key) && is_array($data) && ! empty($data)) {
465
                // Shift the first item of the array
466 View Code Duplication
                if (preg_match('/^:(index|item)\[\d+\]$/', $key)) {
467 9
                    for ($x = substr($key, 7, -1); $x >= 0; $x--) {
468
                        if (empty($data)) {
469 9
                            return false;
470 9
                        }
471 9
                        $item = array_shift($data);
472 6
                    }
473 9
                } elseif ($key == ':last') {
474
                    $item = array_pop($data);
475 6
                } else {
476
                    $item = array_shift($data);
477
                }
478
                $data =& $item;
479
            } else {
480
                if ( ! isset($data[$key])) {
481
                    return false;
482
                }
483
484 6
                if (is_bool($data[$key])) {
485
                    return true;
486 6
                }
487
488 6
                if ($data[$key] === '') {
489
                    return false;
490 6
                }
491
492 6
                $data =& $data[$key];
493 4
            }
494 3
        }
495
        return true;
496
    }
497 3
498 2
    /**
499
     * Build the array structure for value.
500 6
     *
501 6
     * @param $route
502
     * @param null $data
503
     * @return array|null
504
     */
505
    private function buildArray($route, $data = null)
506
    {
507
        $key  = array_pop($route);
508
        $data = [$key => $data];
509
        if (count($route) == 0) {
510
            return $data;
511
        }
512
        return $this->buildArray($route, $data);
513
    }
514
515
    /**
516
     * Remove a value identified from the key
517
     *
518
     * @param $array
519
     * @param $key
520
     */
521
    private function removeValue(&$array, $key)
522
    {
523
        $keys = explode('.', $key);
524
525
        while (count($keys) > 1) {
526
            $key = array_shift($keys);
527
528
            if ( ! isset($array[$key]) || ! is_array($array[$key])) {
529
                return;
530
            }
531
532
            $array =& $array[$key];
533
        }
534
535
        unset($array[array_shift($keys)]);
536
    }
537
}
538