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

LockExpression::parse()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 54
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 21
nc 4
nop 3
dl 0
loc 54
rs 8.4444
c 0
b 0
f 0
ccs 21
cts 21
cp 1
crap 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
14
/**
15
 * Parses a reference to a LOCK expression.
16
 */
17
final class LockExpression implements Component
18
{
19
    /**
20
     * The table to be locked.
21
     *
22
     * @var Expression
23
     */
24
    public $table;
25
26
    /**
27
     * The type of lock to be applied.
28
     *
29
     * @var string
30
     */
31
    public $type;
32
33
    /**
34
     * @param Parser               $parser  the parser that serves as context
35
     * @param TokensList           $list    the list of tokens that are being parsed
36
     * @param array<string, mixed> $options parameters for parsing
37
     *
38
     * @return LockExpression
39
     */
40 40
    public static function parse(Parser $parser, TokensList $list, array $options = [])
41
    {
42 40
        $ret = new static();
43
44
        /**
45
         * The state of the parser.
46
         *
47
         * Below are the states of the parser.
48
         *
49
         *      0 ---------------- [ tbl_name ] -----------------> 1
50
         *      1 ---------------- [ lock_type ] ----------------> 2
51
         *      2 -------------------- [ , ] --------------------> break
52
         *
53
         * @var int
54
         */
55 40
        $state = 0;
56
57 40
        $prevToken = null;
58
59 40
        for (; $list->idx < $list->count; ++$list->idx) {
60
            /**
61
             * Token parsed at this moment.
62
             */
63 40
            $token = $list->tokens[$list->idx];
64
65
            // End of statement.
66
            if (
67 40
                $token->type === Token::TYPE_DELIMITER
68 40
                || ($token->type === Token::TYPE_OPERATOR
69 40
                && $token->value === ',')
70
            ) {
71 40
                break;
72
            }
73
74 40
            if ($state === 0) {
75 40
                $ret->table = Expression::parse($parser, $list, ['parseField' => 'table']);
76 40
                $state = 1;
77 34
            } elseif ($state === 1) {
78
                // parse lock type
79 34
                $ret->type = self::parseLockType($parser, $list);
80 34
                $state = 2;
81
            }
82
83 40
            $prevToken = $token;
84
        }
85
86
        // 2 is the only valid end state
87 40
        if ($state !== 2) {
88 6
            $parser->error('Unexpected end of LOCK expression.', $prevToken);
89
        }
90
91 40
        --$list->idx;
92
93 40
        return $ret;
94
    }
95
96
    /**
97
     * @param LockExpression $component the component to be built
98
     */
99 4
    public static function build($component): string
100
    {
101 4
        return $component->table . ' ' . $component->type;
102
    }
103
104
    /**
105
     * @param LockExpression[] $component the component to be built
106
     */
107 4
    public static function buildAll(array $component): string
108
    {
109 4
        return implode(', ', $component);
110
    }
111
112
    /**
113
     * @return string
114
     */
115 34
    private static function parseLockType(Parser $parser, TokensList $list)
116
    {
117 34
        $lockType = '';
118
119
        /**
120
         * The state of the parser while parsing for lock type.
121
         *
122
         * Below are the states of the parser.
123
         *
124
         *      0 ---------------- [ READ ] -----------------> 1
125
         *      0 ------------- [ LOW_PRIORITY ] ------------> 2
126
         *      0 ---------------- [ WRITE ] ----------------> 3
127
         *      1 ---------------- [ LOCAL ] ----------------> 3
128
         *      2 ---------------- [ WRITE ] ----------------> 3
129
         *
130
         * @var int
131
         */
132 34
        $state = 0;
133
134 34
        $prevToken = null;
135
136 34
        for (; $list->idx < $list->count; ++$list->idx) {
137
            /**
138
             * Token parsed at this moment.
139
             */
140 34
            $token = $list->tokens[$list->idx];
141
142
            // End of statement.
143
            if (
144 34
                $token->type === Token::TYPE_DELIMITER
145 34
                || ($token->type === Token::TYPE_OPERATOR
146 34
                && $token->value === ',')
147
            ) {
148 20
                --$list->idx;
149 20
                break;
150
            }
151
152
            // Skipping whitespaces and comments.
153 34
            if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) {
154 26
                continue;
155
            }
156
157
            // We only expect keywords
158 34
            if ($token->type !== Token::TYPE_KEYWORD) {
159 6
                $parser->error('Unexpected token.', $token);
160 6
                break;
161
            }
162
163 32
            if ($state === 0) {
164 32
                if ($token->keyword === 'READ') {
165 20
                    $state = 1;
166 18
                } elseif ($token->keyword === 'LOW_PRIORITY') {
167 12
                    $state = 2;
168 8
                } elseif ($token->keyword === 'WRITE') {
169 6
                    $state = 3;
170
                } else {
171 2
                    $parser->error('Unexpected keyword.', $token);
172 2
                    break;
173
                }
174
175 30
                $lockType .= $token->keyword;
176 24
            } elseif ($state === 1) {
177 16
                if ($token->keyword !== 'LOCAL') {
178 4
                    $parser->error('Unexpected keyword.', $token);
179 4
                    break;
180
                }
181
182 12
                $lockType .= ' ' . $token->keyword;
183 12
                $state = 3;
184 12
            } elseif ($state === 2) {
185 12
                if ($token->keyword !== 'WRITE') {
186 2
                    $parser->error('Unexpected keyword.', $token);
187 2
                    break;
188
                }
189
190 10
                $lockType .= ' ' . $token->keyword;
191 10
                $state = 3; // parsing over
192
            }
193
194 30
            $prevToken = $token;
195
        }
196
197
        // Only  two possible end states
198 34
        if ($state !== 1 && $state !== 3) {
0 ignored issues
show
introduced by
The condition $state !== 3 is always true.
Loading history...
199 6
            $parser->error('Unexpected end of LOCK expression.', $prevToken);
200
        }
201
202 34
        return $lockType;
203
    }
204
205 4
    public function __toString(): string
206
    {
207 4
        return static::build($this);
208
    }
209
}
210