Passed
Push — master ( 6c3f09...c54108 )
by William
03:43
created

OrderKeyword::build()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
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 class OrderKeyword implements Component
19
{
20
    /**
21
     * The expression that is used for ordering.
22
     *
23
     * @var Expression
24
     */
25
    public $expr;
26
27
    /**
28
     * The order type.
29
     *
30
     * @var string
31
     */
32
    public $type;
33
34
    /**
35
     * @param Expression $expr the expression that we are sorting by
36
     * @param string     $type the sorting type
37
     */
38 58
    public function __construct($expr = null, $type = 'ASC')
39
    {
40 58
        $this->expr = $expr;
41 58
        $this->type = $type;
42
    }
43
44
    /**
45
     * @param Parser               $parser  the parser that serves as context
46
     * @param TokensList           $list    the list of tokens that are being parsed
47
     * @param array<string, mixed> $options parameters for parsing
48
     *
49
     * @return OrderKeyword[]
50
     */
51 56
    public static function parse(Parser $parser, TokensList $list, array $options = [])
52
    {
53 56
        $ret = [];
54
55 56
        $expr = new static();
56
57
        /**
58
         * The state of the parser.
59
         *
60
         * Below are the states of the parser.
61
         *
62
         *      0 --------------------[ expression ]-------------------> 1
63
         *
64
         *      1 ------------------------[ , ]------------------------> 0
65
         *      1 -------------------[ ASC / DESC ]--------------------> 1
66
         *
67
         * @var int
68
         */
69 56
        $state = 0;
70
71 56
        for (; $list->idx < $list->count; ++$list->idx) {
72
            /**
73
             * Token parsed at this moment.
74
             */
75 56
            $token = $list->tokens[$list->idx];
76
77
            // End of statement.
78 56
            if ($token->type === Token::TYPE_DELIMITER) {
79 24
                break;
80
            }
81
82
            // Skipping whitespaces and comments.
83 56
            if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
84 56
                continue;
85
            }
86
87 56
            if ($state === 0) {
88 56
                $expr->expr = Expression::parse($parser, $list);
89 56
                $state = 1;
90 44
            } elseif ($state === 1) {
91
                if (
92 44
                    ($token->type === Token::TYPE_KEYWORD)
93 44
                    && (($token->keyword === 'ASC') || ($token->keyword === 'DESC'))
94
                ) {
95 34
                    $expr->type = $token->keyword;
96 36
                } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
97 10
                    if (! empty($expr->expr)) {
98 10
                        $ret[] = $expr;
99
                    }
100
101 10
                    $expr = new static();
102 10
                    $state = 0;
103
                } else {
104 34
                    break;
105
                }
106
            }
107
        }
108
109
        // Last iteration was not processed.
110 56
        if (! empty($expr->expr)) {
111 56
            $ret[] = $expr;
112
        }
113
114 56
        --$list->idx;
115
116 56
        return $ret;
117
    }
118
119
    /**
120
     * @param OrderKeyword|OrderKeyword[] $component the component to be built
121
     * @param array<string, mixed>        $options   parameters for building
122
     */
123 20
    public static function build($component, array $options = []): string
124
    {
125 20
        if (is_array($component)) {
126 18
            return implode(', ', $component);
127
        }
128
129 20
        return $component->expr . ' ' . $component->type;
130
    }
131
132 18
    public function __toString(): string
133
    {
134 18
        return static::build($this);
135
    }
136
}
137