Passed
Pull Request — master (#398)
by
unknown
02:46
created

OrderKeyword::parse()   D

Complexity

Conditions 19
Paths 6

Size

Total Lines 80
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 19

Importance

Changes 0
Metric Value
cc 19
eloc 40
nc 6
nop 3
dl 0
loc 80
ccs 38
cts 38
cp 1
crap 19
rs 4.5166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
use function is_array;
14
15
/**
16
 * `ORDER BY` keyword parser.
17
 *
18
 * @final
19
 */
20
class OrderKeyword extends Component
21
{
22
    /**
23
     * The expression that is used for ordering.
24
     *
25
     * @var Expression
26
     */
27
    public $expr;
28
29
    /**
30
     * The order type.
31
     *
32
     * @var string
33
     */
34
    public $type;
35
36
    /**
37
     * The null options.
38
     *
39
     * @var string|null
40
     */
41
    public $nullOptions;
42
43
    /**
44
     * @param Expression $expr the expression that we are sorting by
45
     * @param string     $type the sorting type
46
     */
47 108
    public function __construct($expr = null, $type = 'ASC')
48
    {
49 108
        $this->expr = $expr;
50 108
        $this->type = $type;
51
    }
52
53
    /**
54
     * @param Parser               $parser  the parser that serves as context
55
     * @param TokensList           $list    the list of tokens that are being parsed
56
     * @param array<string, mixed> $options parameters for parsing
57
     *
58
     * @return OrderKeyword[]
59
     */
60 104
    public static function parse(Parser $parser, TokensList $list, array $options = [])
61
    {
62 104
        $ret = [];
63
64 104
        $expr = new static();
65
66
        /**
67
         * The state of the parser.
68
         *
69
         * Below are the states of the parser.
70
         *
71
         *      0 --------------------[ expression ]-------------------> 1
72
         *
73
         *      1 ------------------------[ , ]------------------------> 0
74
         *      1 -------------------[ ASC / DESC ]--------------------> 1
75
         *
76
         * @var int
77
         */
78 104
        $state = 0;
79
80 104
        for (; $list->idx < $list->count; ++$list->idx) {
81
            /**
82
             * Token parsed at this moment.
83
             */
84 104
            $token = $list->tokens[$list->idx];
85
86
            // End of statement.
87 104
            if ($token->type === Token::TYPE_DELIMITER) {
88 48
                break;
89
            }
90
91
            // Skipping whitespaces and comments.
92 104
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
93 104
                continue;
94
            }
95
96 104
            if ($state === 0) {
97 104
                $expr->expr = Expression::parse($parser, $list);
98 104
                $state = 1;
99 84
            } elseif ($state === 1) {
100 84
                $currId = $list->idx;
101 84
                $list->idx++; // Ignore the current token
102 84
                $nextToken = $list->getNext();
103 84
                $list->idx = $currId;
104
                if (
105 84
                    ($token->type === Token::TYPE_KEYWORD) &&
106 84
                    ($token->keyword === 'IS' && $nextToken !== null &&
107 8
                    ($nextToken->keyword === 'NOT NULL' ||
108 84
                    $nextToken->keyword === 'NULL')
109
                    )
110
                ) {
111 8
                    $expr->nullOptions = $token->keyword . ' ' . $nextToken->keyword;
112 8
                    $list->idx++; // Ignore the current token
113 8
                    $list->getNext(); // skip nextToken
114
                } elseif (
115 80
                    ($token->type === Token::TYPE_KEYWORD)
116 80
                    && (($token->keyword === 'ASC') || ($token->keyword === 'DESC'))
117
                ) {
118 60
                    $expr->type = $token->keyword;
119 64
                } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
120 20
                    if (! empty($expr->expr)) {
121 20
                        $ret[] = $expr;
122
                    }
123
124 20
                    $expr = new static();
125 20
                    $state = 0;
126
                } else {
127 60
                    break;
128
                }
129
            }
130
        }
131
132
        // Last iteration was not processed.
133 104
        if (! empty($expr->expr)) {
134 104
            $ret[] = $expr;
135
        }
136
137 104
        --$list->idx;
138
139 104
        return $ret;
140
    }
141
142
    /**
143
     * @param OrderKeyword|OrderKeyword[] $component the component to be built
144
     * @param array<string, mixed>        $options   parameters for building
145
     *
146
     * @return string
147
     */
148 36
    public static function build($component, array $options = [])
149
    {
150 36
        if (is_array($component)) {
151 32
            return implode(', ', $component);
152
        }
153
154 36
        $str = $component->expr . ' ';
155 36
        if (! empty($component->nullOptions)) {
156 4
            $str .= $component->nullOptions . ' ';
157
        }
158
159 36
        $str .= $component->type;
160
161 36
        return $str;
162
    }
163
}
164