IntoKeyword::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
c 0
b 0
f 0
nc 1
nop 6
dl 0
loc 14
rs 10
ccs 7
cts 7
cp 1
crap 1
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\Parsers\Expressions;
10
use PhpMyAdmin\SqlParser\Parsers\OptionsArrays;
11
use PhpMyAdmin\SqlParser\TokensList;
12
13
use function implode;
14
use function trim;
15
16
/**
17
 * `INTO` keyword parser.
18
 */
19
final class IntoKeyword implements Component
20
{
21
    /**
22
     * FIELDS/COLUMNS Options for `SELECT...INTO` statements.
23
     */
24
    private const STATEMENT_FIELDS_OPTIONS = [
25
        'TERMINATED BY' => [
26
            1,
27
            'expr',
28
        ],
29
        'OPTIONALLY' => 2,
30
        'ENCLOSED BY' => [
31
            3,
32
            'expr',
33
        ],
34
        'ESCAPED BY' => [
35
            4,
36
            'expr',
37
        ],
38
    ];
39
40
    /**
41
     * LINES Options for `SELECT...INTO` statements.
42
     */
43
    private const STATEMENT_LINES_OPTIONS = [
44
        'STARTING BY' => [
45
            1,
46
            'expr',
47
        ],
48
        'TERMINATED BY' => [
49
            2,
50
            'expr',
51
        ],
52
    ];
53
54
    /**
55
     * Type of target (OUTFILE or SYMBOL).
56
     */
57
    public string|null $type = null;
58
59
    /**
60
     * The destination, which can be a table or a file.
61
     */
62
    public string|Expression|null $dest = null;
63
64
    /**
65
     * The name of the columns.
66
     *
67
     * @var string[]|null
68
     */
69
    public array|null $columns = null;
70
71
    /**
72
     * The values to be selected into (SELECT .. INTO @var1).
73
     *
74
     * @var Expression[]|null
75
     */
76
    public array|null $values = null;
77
78
    /**
79
     * Options for FIELDS/COLUMNS keyword.
80
     *
81
     * @see IntoKeyword::STATEMENT_FIELDS_OPTIONS
82
     */
83
    public OptionsArray|null $fieldsOptions = null;
84
85
    /**
86
     * Whether to use `FIELDS` or `COLUMNS` while building.
87
     */
88
    public bool|null $fieldsKeyword = null;
89
90
    /**
91
     * Options for OPTIONS keyword.
92
     *
93
     * @see IntoKeyword::STATEMENT_LINES_OPTIONS
94
     */
95
    public OptionsArray|null $linesOptions = null;
96
97
    /**
98
     * @param string|null            $type          type of destination (may be OUTFILE)
99
     * @param string|Expression|null $dest          actual destination
100
     * @param string[]|null          $columns       column list of destination
101
     * @param Expression[]|null      $values        selected fields
102
     * @param OptionsArray|null      $fieldsOptions options for FIELDS/COLUMNS keyword
103
     * @param bool|null              $fieldsKeyword options for OPTIONS keyword
104
     */
105 106
    public function __construct(
106
        string|null $type = null,
107
        string|Expression|null $dest = null,
108
        array|null $columns = null,
109
        array|null $values = null,
110
        OptionsArray|null $fieldsOptions = null,
111
        bool|null $fieldsKeyword = null,
112
    ) {
113 106
        $this->type = $type;
114 106
        $this->dest = $dest;
115 106
        $this->columns = $columns;
116 106
        $this->values = $values;
117 106
        $this->fieldsOptions = $fieldsOptions;
118 106
        $this->fieldsKeyword = $fieldsKeyword;
119
    }
120
121
    /**
122
     * @param Parser     $parser  The parser
123
     * @param TokensList $list    A token list
124
     * @param string     $keyword The keyword
125
     */
126 10
    public function parseFileOptions(Parser $parser, TokensList $list, string $keyword = 'FIELDS'): void
127
    {
128 10
        ++$list->idx;
129
130 10
        if ($keyword === 'FIELDS' || $keyword === 'COLUMNS') {
131
            // parse field options
132 10
            $this->fieldsOptions = OptionsArrays::parse($parser, $list, self::STATEMENT_FIELDS_OPTIONS);
133
134 10
            $this->fieldsKeyword = ($keyword === 'FIELDS');
135
        } else {
136
            // parse line options
137 6
            $this->linesOptions = OptionsArrays::parse($parser, $list, self::STATEMENT_LINES_OPTIONS);
138
        }
139
    }
140
141 18
    public function build(): string
142
    {
143 18
        if ($this->dest instanceof Expression) {
144 10
            $columns = ! empty($this->columns) ? '(`' . implode('`, `', $this->columns) . '`)' : '';
145
146 10
            return $this->dest . $columns;
147
        }
148
149 8
        if (isset($this->values)) {
150 4
            return Expressions::buildAll($this->values);
0 ignored issues
show
Bug introduced by
It seems like $this->values can also be of type null; however, parameter $component of PhpMyAdmin\SqlParser\Par...Expressions::buildAll() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

150
            return Expressions::buildAll(/** @scrutinizer ignore-type */ $this->values);
Loading history...
151
        }
152
153 4
        $ret = 'OUTFILE "' . $this->dest . '"';
154
155 4
        $fieldsOptionsString = $this->fieldsOptions?->build() ?? '';
156 4
        if (trim($fieldsOptionsString) !== '') {
157 2
            $ret .= $this->fieldsKeyword ? ' FIELDS' : ' COLUMNS';
158 2
            $ret .= ' ' . $fieldsOptionsString;
159
        }
160
161 4
        $linesOptionsString = $this->linesOptions?->build() ?? '';
162 4
        if (trim($linesOptionsString) !== '') {
163 2
            $ret .= ' LINES ' . $linesOptionsString;
164
        }
165
166 4
        return $ret;
167
    }
168
169 10
    public function __toString(): string
170
    {
171 10
        return $this->build();
172
    }
173
}
174