Passed
Push — master ( 6c3f09...c54108 )
by William
03:43
created

ArrayObj::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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