Passed
Pull Request — master (#19)
by Wilmer
12:28
created

ArrayParser::parse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 11
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Pgsql\Query;
6
7
/**
8
 * The class converts Postgres SQL array representation to PHP array
9
 */
10
class ArrayParser
11
{
12
    /**
13
     * @var string Character used in array
14
     */
15
    private string $delimiter = ',';
16
17
    /**
18
     * Convert array from PostgreSQL to PHP
19
     *
20
     * @param string $value string to be converted
21
     *
22
     * @return array|null
23
     */
24
    public function parse($value): ?array
25
    {
26
        if ($value === null) {
0 ignored issues
show
introduced by
The condition $value === null is always false.
Loading history...
27
            return null;
28
        }
29
30
        if ($value === '{}') {
31
            return [];
32
        }
33
34
        return $this->parseArray($value);
35
    }
36
37
    /**
38
     * Pares PgSQL array encoded in string
39
     *
40
     * @param string $value
41
     * @param int $i parse starting position
42
     *
43
     * @return array
44
     */
45
    private function parseArray($value, &$i = 0): array
46
    {
47
        $result = [];
48
        $len = \strlen($value);
49
50
        for (++$i; $i < $len; ++$i) {
51
            switch ($value[$i]) {
52
                case '{':
53
                    $result[] = $this->parseArray($value, $i);
54
                    break;
55
                case '}':
56
                    break 2;
57
                case $this->delimiter:
58
                    if (empty($result)) { // `{}` case
59
                        $result[] = null;
60
                    }
61
                    if (\in_array($value[$i + 1], [$this->delimiter, '}'], true)) { // `{,}` case
62
                        $result[] = null;
63
                    }
64
                    break;
65
                default:
66
                    $result[] = $this->parseString($value, $i);
67
            }
68
        }
69
70
        return $result;
71
    }
72
73
    /**
74
     * Parses PgSQL encoded string
75
     *
76
     * @param string $value
77
     * @param int $i parse starting position
78
     *
79
     * @return null|string
80
     */
81
    private function parseString($value, &$i): ?string
82
    {
83
        $isQuoted = $value[$i] === '"';
84
        $stringEndChars = $isQuoted ? ['"'] : [$this->delimiter, '}'];
85
        $result = '';
86
        $len = strlen($value);
87
88
        for ($i += $isQuoted ? 1 : 0; $i < $len; ++$i) {
89
            if (\in_array($value[$i], ['\\', '"'], true) && \in_array($value[$i + 1], [$value[$i], '"'], true)) {
90
                ++$i;
91
            } elseif (\in_array($value[$i], $stringEndChars, true)) {
92
                break;
93
            }
94
95
            $result .= $value[$i];
96
        }
97
98
        $i -= $isQuoted ? 0 : 1;
99
100
        if (!$isQuoted && $result === 'NULL') {
101
            $result = null;
102
        }
103
104
        return $result;
105
    }
106
}
107