Passed
Pull Request — master (#483)
by
unknown
03:28
created

ArrayObj::build()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Components;
6
7
use PhpMyAdmin\SqlParser\Component;
8
use PhpMyAdmin\SqlParser\Parser;
9
use PhpMyAdmin\SqlParser\Token;
10
use PhpMyAdmin\SqlParser\TokensList;
11
12
use function implode;
13
use function strlen;
14
use function trim;
15
16
/**
17
 * Parses an array.
18
 */
19
final class ArrayObj implements Component
20
{
21
    /**
22
     * The array that contains the unprocessed value of each token.
23
     *
24
     * @var string[]
25
     */
26
    public array $raw = [];
27
28
    /**
29
     * The array that contains the processed value of each token.
30
     *
31
     * @var string[]
32
     */
33
    public array $values = [];
34
35
    /**
36
     * @param string[] $raw    the unprocessed values
37
     * @param string[] $values the processed values
38
     */
39 260
    public function __construct(array $raw = [], array $values = [])
40
    {
41 260
        $this->raw = $raw;
42 260
        $this->values = $values;
43
    }
44
45
    /**
46
     * @param Parser               $parser  the parser that serves as context
47
     * @param TokensList           $list    the list of tokens that are being parsed
48
     * @param array<string, mixed> $options parameters for parsing
49
     *
50
     * @return ArrayObj|Component[]
51
     */
52 264
    public static function parse(Parser $parser, TokensList $list, array $options = [])
53
    {
54 264
        $ret = empty($options['type']) ? new static() : [];
55
56
        /**
57
         * The last raw expression.
58
         *
59
         * @var string
60
         */
61 264
        $lastRaw = '';
62
63
        /**
64
         * The last value.
65
         *
66
         * @var string
67
         */
68 264
        $lastValue = '';
69
70
        /**
71
         * Counts brackets.
72
         *
73
         * @var int
74
         */
75 264
        $brackets = 0;
76
77
        /**
78
         * Last separator (bracket or comma).
79
         *
80
         * @var bool
81
         */
82 264
        $isCommaLast = false;
83
84 264
        for (; $list->idx < $list->count; ++$list->idx) {
85
            /**
86
             * Token parsed at this moment.
87
             */
88 264
            $token = $list->tokens[$list->idx];
89
90
            // End of statement.
91 264
            if ($token->type === Token::TYPE_DELIMITER) {
92 2
                break;
93
            }
94
95
            // Skipping whitespaces and comments.
96 264
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
97 104
                $lastRaw .= $token->token;
98 104
                $lastValue = trim($lastValue) . ' ';
99 104
                continue;
100
            }
101
102 264
            if (($brackets === 0) && (($token->type !== Token::TYPE_OPERATOR) || ($token->value !== '('))) {
103 2
                $parser->error('An opening bracket was expected.', $token);
104 2
                break;
105
            }
106
107 262
            if ($token->type === Token::TYPE_OPERATOR) {
108 262
                if ($token->value === '(') {
109 262
                    if (++$brackets === 1) { // 1 is the base level.
110 262
                        continue;
111
                    }
112 262
                } elseif ($token->value === ')') {
113 260
                    if (--$brackets === 0) { // Array ended.
114 260
                        break;
115
                    }
116 116
                } elseif ($token->value === ',') {
117 116
                    if ($brackets === 1) {
118 114
                        $isCommaLast = true;
119 114
                        if (empty($options['type'])) {
120 92
                            $ret->raw[] = trim($lastRaw);
121 92
                            $ret->values[] = trim($lastValue);
122 92
                            $lastRaw = $lastValue = '';
123
                        }
124
125 114
                        continue;
126
                    }
127
                }
128
            }
129
130 250
            if (empty($options['type'])) {
131 238
                $lastRaw .= $token->token;
132 238
                $lastValue .= $token->value;
133
            } else {
134 22
                $ret[] = $options['type']::parse(
135 22
                    $parser,
136 22
                    $list,
137 22
                    empty($options['typeOptions']) ? [] : $options['typeOptions']
138 22
                );
139
            }
140
        }
141
142
        // Handling last element.
143
        //
144
        // This is treated differently to treat the following cases:
145
        //
146
        //           => []
147
        //      [,]  => ['', '']
148
        //      []   => []
149
        //      [a,] => ['a', '']
150
        //      [a]  => ['a']
151 264
        $lastRaw = trim($lastRaw);
152 264
        if (empty($options['type']) && ((strlen($lastRaw) > 0) || ($isCommaLast))) {
153 238
            $ret->raw[] = $lastRaw;
154 238
            $ret->values[] = trim($lastValue);
155
        }
156
157 264
        return $ret;
158
    }
159
160
    /**
161
     * @param ArrayObj $component the component to be built
162
     */
163 22
    public static function build($component): string
164
    {
165 22
        if ($component->raw !== []) {
166 20
            return '(' . implode(', ', $component->raw) . ')';
167
        }
168
169 2
        return '(' . implode(', ', $component->values) . ')';
170
    }
171
172
    /**
173
     * @param ArrayObj[] $component the component to be built
174
     */
175 12
    public static function buildAll(array $component): string
176
    {
177 12
        return implode(', ', $component);
178
    }
179
180 18
    public function __toString(): string
181
    {
182 18
        return static::build($this);
183
    }
184
}
185