Skip to content

Commit 578d3aa

Browse files
Merge pull request #540 from kamil-tekiela/Refactor-Parser
Refactor Parser and Statement
2 parents 6d8a7d7 + fbaf831 commit 578d3aa

File tree

11 files changed

+92
-138
lines changed

11 files changed

+92
-138
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -540,16 +540,6 @@ parameters:
540540
count: 1
541541
path: src/Statement.php
542542

543-
-
544-
message: "#^Offset 'class' does not exist on array\\{\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Array2d', field\\: 'values'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ArrayObj', field\\: 'partition'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Condition', field\\: 'having'\\|'where'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Expression', field\\: 'table', options\\: array\\{parseField\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'expr'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'fields'\\|'tables', options\\: array\\{parseField\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'from', options\\: array\\{field\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\FunctionCall', field\\: 'call'\\|'procedure'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\GroupKeyword', field\\: 'group'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\IndexHint', field\\: 'index_hints'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\IntoKeyword', field\\: 'into'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\JoinKeyword', field\\: 'join'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Limit', field\\: 'limit'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\OptionsArray', field\\: 'endOptions'\\|'groupOptions'\\|'options'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\OrderKeyword', field\\: 'order'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\RenameOperation', field\\: 'renames'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\SetOperation', field\\: 'set'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\UnionKeyword', field\\: 'union'\\}\\.$#"
545-
count: 1
546-
path: src/Statement.php
547-
548-
-
549-
message: "#^Offset 'field' does not exist on array\\{\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Array2d', field\\: 'values'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ArrayObj', field\\: 'partition'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Condition', field\\: 'having'\\|'where'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Expression', field\\: 'table', options\\: array\\{parseField\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'expr'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'fields'\\|'tables', options\\: array\\{parseField\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\ExpressionArray', field\\: 'from', options\\: array\\{field\\: 'table'\\}\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\FunctionCall', field\\: 'call'\\|'procedure'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\GroupKeyword', field\\: 'group'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\IndexHint', field\\: 'index_hints'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\IntoKeyword', field\\: 'into'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\JoinKeyword', field\\: 'join'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\Limit', field\\: 'limit'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\OptionsArray', field\\: 'endOptions'\\|'groupOptions'\\|'options'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\OrderKeyword', field\\: 'order'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\RenameOperation', field\\: 'renames'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\SetOperation', field\\: 'set'\\}\\|array\\{class\\: 'PhpMyAdmin\\\\\\\\SqlParser\\\\\\\\Components\\\\\\\\UnionKeyword', field\\: 'union'\\}\\.$#"
550-
count: 1
551-
path: src/Statement.php
552-
553543
-
554544
message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Statement\\:\\:\\$options \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\|null\\) does not accept mixed\\.$#"
555545
count: 1

psalm-baseline.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -797,12 +797,6 @@
797797
<MixedOperand>
798798
<code><![CDATA[$this->$field->build()]]></code>
799799
</MixedOperand>
800-
<PossiblyUndefinedArrayOffset>
801-
<code><![CDATA[Parser::KEYWORD_PARSERS[$name]['class']]]></code>
802-
<code><![CDATA[Parser::KEYWORD_PARSERS[$name]['field']]]></code>
803-
<code><![CDATA[Parser::KEYWORD_PARSERS[$tokenValue]['class']]]></code>
804-
<code><![CDATA[Parser::KEYWORD_PARSERS[$tokenValue]['field']]]></code>
805-
</PossiblyUndefinedArrayOffset>
806800
<PossiblyUnusedReturnValue>
807801
<code>bool</code>
808802
</PossiblyUnusedReturnValue>

src/Parser.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,6 @@ class Parser
115115
* Array of classes that are used in parsing SQL components.
116116
*/
117117
public const KEYWORD_PARSERS = [
118-
// This is not a proper keyword and was added here to help the
119-
// formatter.
120-
'PARTITION BY' => [],
121-
'SUBPARTITION BY' => [],
122-
123118
// This is not a proper keyword and was added here to help the
124119
// builder.
125120
'_OPTIONS' => [

src/Statement.php

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,13 @@ abstract class Statement implements Stringable
4848
*/
4949
public static array $statementOptions = [];
5050

51+
protected const ADD_CLAUSE = 1;
52+
protected const ADD_KEYWORD = 2;
53+
5154
/**
5255
* The clauses of this statement, in order.
5356
*
54-
* The value attributed to each clause is used by the builder and it may
55-
* have one of the following values:
56-
*
57-
* - 1 = 01 - add the clause only
58-
* - 2 = 10 - add the keyword
59-
* - 3 = 11 - add both the keyword and the clause
60-
*
61-
* @var array<string, array<int, int|string>>
62-
* @psalm-var array<string, array{non-empty-string, (1|2|3)}>
57+
* @var array<string, array{non-empty-string, int-mask-of<self::ADD_*>}>
6358
*/
6459
public static array $clauses = [];
6560

@@ -115,29 +110,7 @@ public function build(): string
115110
*/
116111
$built = [];
117112

118-
/**
119-
* Statement's clauses.
120-
*/
121-
$clauses = $this->getClauses();
122-
123-
foreach ($clauses as $clause) {
124-
/**
125-
* The name of the clause.
126-
*/
127-
$name = $clause[0];
128-
129-
/**
130-
* The type of the clause.
131-
*
132-
* @see Statement::$clauses
133-
*/
134-
$type = $clause[1];
135-
136-
/**
137-
* The builder (parser) of this clause.
138-
*/
139-
$class = Parser::KEYWORD_PARSERS[$name]['class'];
140-
113+
foreach ($this->getClauses() as [$name, $type]) {
141114
/**
142115
* The name of the field that is used as source for the builder.
143116
* Same field is used to store the result of parsing.
@@ -150,7 +123,7 @@ public function build(): string
150123
}
151124

152125
// Checking if this field was already built.
153-
if ($type & 1) {
126+
if ($type & self::ADD_CLAUSE) {
154127
if (! empty($built[$field])) {
155128
continue;
156129
}
@@ -159,16 +132,17 @@ public function build(): string
159132
}
160133

161134
// Checking if the name of the clause should be added.
162-
if ($type & 2) {
135+
if ($type & self::ADD_KEYWORD) {
163136
$query = trim($query) . ' ' . $name;
164137
}
165138

166139
// Checking if the result of the builder should be added.
167-
if (! ($type & 1)) {
140+
if (! ($type & self::ADD_CLAUSE)) {
168141
continue;
169142
}
170143

171144
if (is_array($this->$field)) {
145+
$class = Parser::KEYWORD_PARSERS[$name]['class'];
172146
$query = trim($query) . ' ' . $class::buildAll($this->$field);
173147
} else {
174148
$query = trim($query) . ' ' . $this->$field->build();
@@ -286,7 +260,7 @@ public function parse(Parser $parser, TokensList $list): void
286260
$options = [];
287261

288262
// Looking for duplicated clauses.
289-
if (! empty(Parser::KEYWORD_PARSERS[$token->value]) || ! empty(Parser::STATEMENT_PARSERS[$token->value])) {
263+
if (isset(Parser::KEYWORD_PARSERS[$token->value]) || ! empty(Parser::STATEMENT_PARSERS[$token->value])) {
290264
if (! empty($parsedClauses[$token->value])) {
291265
$parser->error('This type of clause was previously parsed.', $token);
292266
break;
@@ -300,7 +274,7 @@ public function parse(Parser $parser, TokensList $list): void
300274
// but it might be the beginning of a statement of truncate,
301275
// so let the value use the keyword field for truncate type.
302276
$tokenValue = in_array($token->keyword, ['TRUNCATE']) ? $token->keyword : $token->value;
303-
if (! empty(Parser::KEYWORD_PARSERS[$tokenValue]) && $list->idx < $list->count) {
277+
if (isset(Parser::KEYWORD_PARSERS[$tokenValue]) && $list->idx < $list->count) {
304278
$class = Parser::KEYWORD_PARSERS[$tokenValue]['class'];
305279
$field = Parser::KEYWORD_PARSERS[$tokenValue]['field'];
306280
if (! empty(Parser::KEYWORD_PARSERS[$tokenValue]['options'])) {
@@ -419,8 +393,7 @@ public function after(Parser $parser, TokensList $list, Token $token): void
419393
/**
420394
* Gets the clauses of this statement.
421395
*
422-
* @return array<string, array<int, int|string>>
423-
* @psalm-return array<string, array{non-empty-string, (1|2|3)}>
396+
* @return array<string, array{non-empty-string, int-mask-of<Statement::ADD_*>}>
424397
*/
425398
public function getClauses(): array
426399
{

src/Statements/DeleteStatement.php

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,42 +62,41 @@ class DeleteStatement extends Statement
6262
*
6363
* @see Statement::$clauses
6464
*
65-
* @var array<string, array<int, int|string>>
66-
* @psalm-var array<string, array{non-empty-string, (1|2|3)}>
65+
* @var array<string, array{non-empty-string, int-mask-of<self::ADD_*>}>
6766
*/
6867
public static array $clauses = [
6968
'DELETE' => [
7069
'DELETE',
71-
2,
70+
Statement::ADD_KEYWORD,
7271
],
7372
// Used for options.
7473
'_OPTIONS' => [
7574
'_OPTIONS',
76-
1,
75+
Statement::ADD_CLAUSE,
7776
],
7877
'FROM' => [
7978
'FROM',
80-
3,
79+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
8180
],
8281
'PARTITION' => [
8382
'PARTITION',
84-
3,
83+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
8584
],
8685
'USING' => [
8786
'USING',
88-
3,
87+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
8988
],
9089
'WHERE' => [
9190
'WHERE',
92-
3,
91+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
9392
],
9493
'ORDER BY' => [
9594
'ORDER BY',
96-
3,
95+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
9796
],
9897
'LIMIT' => [
9998
'LIMIT',
100-
3,
99+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
101100
],
102101
];
103102

src/Statements/DropStatement.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,26 @@ class DropStatement extends Statement
4242
*
4343
* @see Statement::$clauses
4444
*
45-
* @var array<string, array<int, int|string>>
46-
* @psalm-var array<string, array{non-empty-string, (1|2|3)}>
45+
* @var array<string, array{non-empty-string, int-mask-of<self::ADD_*>}>
4746
*/
4847
public static array $clauses = [
4948
'DROP' => [
5049
'DROP',
51-
2,
50+
Statement::ADD_KEYWORD,
5251
],
5352
// Used for options.
5453
'_OPTIONS' => [
5554
'_OPTIONS',
56-
1,
55+
Statement::ADD_CLAUSE,
5756
],
5857
// Used for select expressions.
5958
'DROP_' => [
6059
'DROP',
61-
1,
60+
Statement::ADD_CLAUSE,
6261
],
6362
'ON' => [
6463
'ON',
65-
3,
64+
Statement::ADD_CLAUSE | Statement::ADD_KEYWORD,
6665
],
6766
];
6867

0 commit comments

Comments
 (0)