Passed
Pull Request — master (#417)
by
unknown
03:35 queued 29s
created

GroupKeyword::parse()   C

Complexity

Conditions 17
Paths 8

Size

Total Lines 75
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 17

Importance

Changes 0
Metric Value
cc 17
eloc 34
c 0
b 0
f 0
nc 8
nop 3
dl 0
loc 75
rs 5.2166
ccs 33
cts 33
cp 1
crap 17

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