MySQLQueryParser::parse()   F
last analyzed

Complexity

Conditions 31
Paths 131

Size

Total Lines 101
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 87
dl 0
loc 101
rs 3.9083
c 0
b 0
f 0
cc 31
nc 131
nop 1

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
namespace arc\store;
4
5
final class MySQLQueryParser {
6
7
    private $tokenizer;
8
9
	public function __construct($tokenizer) {
10
		$this->tokenizer = $tokenizer;
11
	}
12
13
    /**
14
     * @param string $query
15
     * @return string postgresql 'where' part of the sql query
16
     * @throws \LogicException when a parse error occurs
17
     */
18
    public function parse($query)
19
    {
20
        $indent   = 0;
21
        $sql      = [];
22
        $position = 0;
23
        $expect   = 'name|parenthesis_open|not';
24
        
25
        foreach( call_user_func($this->tokenizer, $query) as $token ) {
26
            $tokenType = key($token);
27
            list($tokenValue, $offset)=$token[$tokenType];
28
            if ( !preg_match("/^$expect$/",$tokenType) ) {
29
                throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$tokenType.': '
30
                    .(substr($query,0, $position)." --> ".substr($query,$position)) );
31
            }
32
            switch($tokenType) {
33
                case 'number':
34
                case 'string':
35
                    $sql[]  = $tokenValue;
36
                    $expect = 'operator|parenthesis_close';
37
                break;
38
                case 'name':
39
                    switch ($tokenValue) {
40
                        case 'nodes.path':
41
                        case 'nodes.parent':
42
                        case 'nodes.name':
43
                        case 'nodes.mtime':
44
                        case 'nodes.ctime':
45
                            $sql[] = $tokenValue;
46
                        break;
47
                        default:
48
                            $sql[] = "JSON_UNQUOTE(JSON_EXTRACT( nodes.data, '$.".$tokenValue."'))";
49
                        break;
50
                    }
51
                    $expect = 'compare';
52
                break;
53
                case 'compare':
54
                    switch( $tokenValue ) {
55
                        case '>':
56
                        case '>=':
57
                        case '<':
58
                        case '<=':
59
                        case '=':
60
                        case '<>':
61
                        case '!=':
62
                            $sql[] =$tokenValue;
63
                        break;
64
                        case '?':
65
                            $part  = $sql[count($sql)-1];
66
                            $part  = str_replace('->>', '->', $part);
67
                            $sql[count($sql)-1] = $part;
68
                            $sql[] = 'IS NOT NULL';
69
                        break;
70
                        case '~=':
71
                            $sql[] = 'like';
72
                        break;
73
                        case '!~':
74
                            $sql[] = 'not like';
75
                        break;
76
                    }
77
                    $expect = 'number|string';
78
                break;
79
                case 'not':
80
                    $sql[]  = $tokenValue;
81
                    $expect = 'name|parenthesis_open';
82
                break;
83
                case 'operator':
84
                    $sql[]  = $tokenValue;
85
                    $expect = 'name|parenthesis_open|not';
86
                break;
87
                case 'parenthesis_open':
88
                    $sql[]  = $tokenValue;
89
                    $indent++;
90
                    $expect = 'name|parenthesis_open|not';
91
                break;
92
                case 'parenthesis_close':
93
                    $sql[]  = $tokenValue;
94
                    $indent--;
95
                    if ( $indent>0 ) {
96
                        $expect = 'operator|parenthesis_close';
97
                    } else {
98
                        $expect = 'operator';
99
                    }
100
                break;
101
            }
102
            $position += $offset + strlen($tokenValue);
103
        }
104
        if ( $indent!=0 ) {
0 ignored issues
show
introduced by
The condition $indent != 0 is always false.
Loading history...
105
            throw new \LogicException('unbalanced parenthesis');
106
        } 
107
        if ($position<strlen($query)) {
108
            throw new \LogicException('Parse error at '.$position.': unrecognized token: '
109
            .(substr($query,0, $position)." --> ".substr($query,$position)) );
110
        }
111
        foreach(['number','string','compare'] as $tokenType) {
112
            if (strpos($expect, $tokenType)!==false) {
113
                throw new \LogicException('Parse error at '.$position.': expected '.$expect.': '
114
                .(substr($query,0, $position)." --> ".substr($query,$position)) );
115
116
            }
117
        }
118
        return implode(' ',$sql);
119
    }
120
121
}
122