PSQLQueryParser::parse()   F
last analyzed

Complexity

Conditions 31
Paths 131

Size

Total Lines 100
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 87
dl 0
loc 100
rs 3.9083
c 4
b 0
f 1
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 PSQLQueryParser {
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
        foreach( call_user_func($this->tokenizer, $query) as $token ) {
25
            $tokenType = key($token);
26
            list($tokenValue, $offset)=$token[$tokenType];
27
            if ( !preg_match("/^$expect$/",$tokenType) ) {
28
                throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$tokenType.': '
29
                    .(substr($query,0, $position)." --> ".substr($query,$position)) );
30
            }
31
            switch($tokenType) {
32
                case 'number':
33
                case 'string':
34
                    $sql[]  = $tokenValue;
35
                    $expect = 'operator|parenthesis_close';
36
                break;
37
                case 'name':
38
                    switch ($tokenValue) {
39
                        case 'nodes.path':
40
                        case 'nodes.parent':
41
                        case 'nodes.name':
42
                        case 'nodes.mtime':
43
                        case 'nodes.ctime':
44
                            $sql[] = $tokenValue;
45
                        break;
46
                        default:
47
                            $sql[] = "nodes.data #>> '{".str_replace('.',',',$tokenValue)."}'";
48
                        break;
49
                    }
50
                    $expect = 'compare';
51
                break;
52
                case 'compare':
53
                    switch( $tokenValue ) {
54
                        case '>':
55
                        case '>=':
56
                        case '<':
57
                        case '<=':
58
                        case '=':
59
                        case '<>':
60
                        case '!=':
61
                            $sql[] = $tokenValue;
62
                        break;
63
                        case '?':
64
                            $part  = $sql[count($sql)-1];
65
                            $part  = str_replace('#>>', '#>', $part);
66
                            $sql[count($sql)-1] = $part;
67
                            $sql[] = $tokenValue;                            
68
                        break;
69
                        case '~=':
70
                            $sql[] = 'like';
71
                        break;
72
                        case '!~':
73
                            $sql[] = 'not like';
74
                        break;
75
                    }
76
                    $expect = 'number|string';
77
                break;
78
                case 'not':
79
                    $sql[]  = $tokenValue;
80
                    $expect = 'name|parenthesis_open';
81
                break;
82
                case 'operator':
83
                    $sql[]  = $tokenValue;
84
                    $expect = 'name|parenthesis_open|not';
85
                break;
86
                case 'parenthesis_open':
87
                    $sql[]  = $tokenValue;
88
                    $indent++;
89
                    $expect = 'name|parenthesis_open|not';
90
                break;
91
                case 'parenthesis_close':
92
                    $sql[]  = $tokenValue;
93
                    $indent--;
94
                    if ( $indent>0 ) {
95
                        $expect = 'operator|parenthesis_close';
96
                    } else {
97
                        $expect = 'operator';
98
                    }
99
                break;
100
            }
101
            $position += $offset + strlen($tokenValue);
102
        }
103
        if ( $indent!=0 ) {
0 ignored issues
show
introduced by
The condition $indent != 0 is always false.
Loading history...
104
            throw new \LogicException('unbalanced parenthesis');
105
        }
106
        if ($position<strlen($query)) {
107
            throw new \LogicException('Parse error at '.$position.': unrecognized token: '
108
            .(substr($query,0, $position)." --> ".substr($query,$position)) );
109
        }
110
        foreach(['number','string','compare'] as $tokenType) {
111
            if (strpos($expect, $tokenType)!==false) {
112
                throw new \LogicException('Parse error at '.$position.': expected '.$expect.': '
113
                .(substr($query,0, $position)." --> ".substr($query,$position)) );
114
115
            }
116
        }
117
        return implode(' ',$sql);
118
    }
119
120
}
121