Completed
Push — master ( 7665c8...9af7b9 )
by Robbert
61:21 queued 52:46
created

sql_compiler::parse_group_expr()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 28
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 11.5536

Importance

Changes 0
Metric Value
cc 5
eloc 23
nc 6
nop 1
dl 0
loc 28
rs 8.439
c 0
b 0
f 0
ccs 9
cts 25
cp 0.36
crap 11.5536
1
<?php
2
3
abstract class sql_compiler {
4
	protected $skipDefaultOrderBy;
5
	protected $store;
6
	public  $error;
7
	protected $join_target_properties;
8
	protected $offset;
9
	protected $limit;
10
	protected $cache;
11
	protected $path;
12
	protected $_SCAN_WS        = array(" " => true, "\t" => true, "\n" => true ,"\r" => true);
13
	protected $_SCAN_AZ        = array("a" => true, "A" => true, "b" => true, "B" => true, "c" => true, "C" => true, "d" => true, "D" => true, "e" => true, "E" => true, "f" => true, "F" => true, "g" => true, "G" => true, "h" => true, "H" => true, "i" => true, "I" => true, "j" => true, "J" => true, "k" => true, "K" => true, "l" => true, "L" => true, "m" => true, "M" => true, "n" => true, "N" => true, "o" => true, "O" => true, "p" => true, "P" => true, "q" => true, "Q" => true, "r" => true, "R" => true, "s" => true, "S" => true, "t" => true, "T" => true, "u" => true, "U" => true, "v" => true, "V" => true, "w" => true, "W" => true, "x" => true, "X" => true, "y" => true, "Y" => true, "z" => true, "Z" => true);
14
	protected $_SCAN_AZ_09     = array("a" => true, "A" => true, "b" => true, "B" => true, "c" => true, "C" => true, "d" => true, "D" => true, "e" => true, "E" => true, "f" => true, "F" => true, "g" => true, "G" => true, "h" => true, "H" => true, "i" => true, "I" => true, "j" => true, "J" => true, "k" => true, "K" => true, "l" => true, "L" => true, "m" => true, "M" => true, "n" => true, "N" => true, "o" => true, "O" => true, "p" => true, "P" => true, "q" => true, "Q" => true, "r" => true, "R" => true, "s" => true, "S" => true, "t" => true, "T" => true, "u" => true, "U" => true, "v" => true, "V" => true, "w" => true, "W" => true, "x" => true, "X" => true, "y" => true, "Y" => true, "z" => true, "Z" => true, "_" => true, "0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true);
15
	protected $_SCAN_NUM       = array("0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true);
16
	protected $_SCAN_NUM_START = array("0" => true, "1" => true, "2" => true, "3" => true, "4" => true, "5" => true, "6" => true, "7" => true, "8" => true, "9" => true, "-" => true);
17
	protected $_SCAN_CMP       = array("~" => array("=" => array("FIN" => true)), "=" => array("=" => array("FIN" => true), "FIN" => true, "~" => array("FIN" => true, "~" => array("FIN" => true)), "*" => array("FIN" => true, "*" => array("FIN" => true)), "/" => array("FIN" => true)), "!" => array("=" => array("FIN" => true), "~" => array("FIN" => true, "~" => array("FIN" => true)), "*" => array("FIN" => true, "*" => array("FIN" => true)), "/" => array("FIN" => true, "/" => array("FIN" => true))), "<" => array("=" => array("FIN" => true), "FIN" => true), ">" => array("=" => array("FIN" => true), "FIN" => true), "/" => array("=" => array("=" => array("FIN" => true))));
18
19
20 192
	protected function parse_const(&$YYBUFFER) {
21 192
		$YYCURSOR = 0;
22 192
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
23 192
			$YYCURSOR++;
24 144
		}
25 192
		$value = '';
26 192
		$yych = $YYBUFFER[$YYCURSOR];
27
		switch (true) {
28 192
			case '"' === $yych:
29 192
			case "'" === $yych:
30 190
				$quote = $yych;
31 190
				$yych = $YYBUFFER[++$YYCURSOR];
32 190
				while ($yych !== "\0" && $yych !== $quote) {
33 190
					if ($yych === "\\") {
34 49
						$yych = $YYBUFFER[++$YYCURSOR];
35 3
						if ($yych !== $quote && $yych != "\\") {
36
							$value .= "\\";
37
						}
38 48
					}
39 190
					$value .= $yych;
40 190
					$yych = $YYBUFFER[++$YYCURSOR];
41 142
				}
42 190
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1);
43 190
				$node["id"] = "string";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
44 190
				$node["type"] = ($quote === '"') ? "double" : "single";
45 190
				$node["value"] = stripslashes($value);
46 190
				return $node;
47
			break;
48 2
			case $this->_SCAN_NUM_START[$yych]:
49 2
				$value = $yych;
50 2
				$yych = $YYBUFFER[++$YYCURSOR];
51 2
				while (isset($this->_SCAN_NUM[$yych])) {
52
					$value .= $yych;
53 1
					$yych = $YYBUFFER[++$YYCURSOR];
54
				}
55 2
				if ($yych === '.') {
56
					$value .= $yych;
57
					$yych = $YYBUFFER[++$YYCURSOR];
58
					while (isset($this->_SCAN_NUM[$yych])) {
59
						$value .= $yych;
60
						$yych = $YYBUFFER[++$YYCURSOR];
61
					}
62
					$node["id"]="float";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
63
					$node["value"]=(float)$value;
64
				} else {
65 2
					$node["id"]="int";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
66 2
					$node["value"]=(int)$value;;
67
				}
68 2
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
69 2
				return $node;
70
			break;
71
		}
72
	}
73
74 197
	protected function parse_ident(&$YYBUFFER) {
75
		/* parse identifier regs 1,2 and 3
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
76
77
			reg[1]: tablename
78
			reg[2]: property name
79
			reg[3]: only used with 'my' properties
80
		*/
81 197
		$reg_id='^[[:space:]]*(([a-z_][a-z0-9_]*)(:[a-z]+)?([.][a-z_][a-z0-9_]*)?([.][a-z_][a-z0-9_]*)?)';
82 197
		$reg_id.='[[:space:]]*';
83
84 197
		$YYCURSOR = 0;
85 197
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
86 186
			$YYCURSOR++;
87 140
		}
88 197
		$value = '';
89 197
		$yych = $YYBUFFER[$YYCURSOR];
90
91 197
		if ($this->_SCAN_AZ[$yych]) {
92 196
			$value .= $yych;
93 196
			$yych = $YYBUFFER[++$YYCURSOR];
94 196
			while (isset($this->_SCAN_AZ_09[$yych])) {
95 196
				$value .= $yych;
96 196
				$yych = $YYBUFFER[++$YYCURSOR];
97 148
			}
98 196
			$match_1 = $value; $value = '';
99 196
			if ($yych === ':') {
100
				$yych = $YYBUFFER[++$YYCURSOR];
101
				while (isset($this->_SCAN_AZ[$yych])) {
102
					$value .= $yych;
103
					$yych = $YYBUFFER[++$YYCURSOR];
104
				}
105
				$record_id = $value; $value = '';
106
			}
107 196 View Code Duplication
			if ($yych === '.') {
108 193
				$yych = $YYBUFFER[++$YYCURSOR];
109 193
				if ($this->_SCAN_AZ[$yych]) {
110 193
					$value .= $yych;
111 193
					$yych = $YYBUFFER[++$YYCURSOR];
112 193
					while (isset($this->_SCAN_AZ_09[$yych])) {
113 193
						$value .= $yych;
114 193
						$yych = $YYBUFFER[++$YYCURSOR];
115 145
					}
116 145
				}
117 193
				$match_2 = $value; $value = '';
118 145
			}
119 196 View Code Duplication
			if ($yych === '.') {
120
				$yych = $YYBUFFER[++$YYCURSOR];
121
				if ($this->_SCAN_AZ[$yych]) {
122
					$value .= $yych;
123
					$yych = $YYBUFFER[++$YYCURSOR];
124
					while (isset($this->_SCAN_AZ_09[$yych])) {
125
						$value .= $yych;
126
						$yych = $YYBUFFER[++$YYCURSOR];
127
					}
128
				}
129
				$match_3 = $value; $value = '';
0 ignored issues
show
Unused Code introduced by
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
130
			}
131
132 148
		}
133
134
135 197
		if($match_1) {
136 196
			if (!$match_2) {
0 ignored issues
show
Bug introduced by
The variable $match_2 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
137
				/* default table is 'object' */
138 51
				$match_2 = $match_1;
0 ignored issues
show
Bug introduced by
The variable $match_1 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
139 51
				$match_1 = "object";
140 39
			}
141 196
			$node["id"]="ident";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
142
143 196
			$table=$match_1;
144 196
			$field=$match_2;
145 196
			if ($table=="object") {
146
				switch ($field) {
147 189
					case "implements":
148 184
						$node["id"]="implements";
149 184
					break;
150 53
					case "path":
151 53
					case "parent":
152 53
					case "priority":
153 1
						$node["table"]="nodes";
154 1
						$node["field"]=$field;
155 1
					break;
156 41
					default:
157 53
						$node["table"]="objects";
158 87
						$node["field"]=$field;
159 41
				}
160 143
			} else
161 191
			if ($table === "my") {
162
				$node["id"] = "custom";
163
				if ($match_3) {
164
					$node["nls"] = $field;
165
					$field = $match_3;
0 ignored issues
show
Bug introduced by
The variable $match_3 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
166
				}
167
				$node["field"] = $field;
168
				$node["record_id"] = $record_id;
0 ignored issues
show
Bug introduced by
The variable $record_id does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
169
			} else {
170 191
				$node["id"]="property";
171 191
				if ($match_3) {
172
					$node["nls"] = $field;
173
					$field = $match_3;
174
				}
175 191
				$node["table"]="prop_".$table;
176 191
				$node["field"]="AR_".$field;
177 191
				$node["record_id"] = $record_id;
178
			}
179 148
		}
180 197
		$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
181 197
		return $node;
0 ignored issues
show
Bug introduced by
The variable $node does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
182
	}
183
184 195
	protected function parse_cmp_expr(&$YYBUFFER) {
185 195
		$result=$this->parse_ident($YYBUFFER);
186 195
		if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array<string,string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
187 194
			$YYCURSOR = 0;
188 194
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
189 193
				$YYCURSOR++;
190 145
			}
191 194
			$yych = $YYBUFFER[$YYCURSOR];
192 194
			$YYCURSOR_START = $YYCURSOR;
193 194
			$RULES = &$this->_SCAN_CMP;
194 194
			while (isset($RULES[$yych])) {
195 192
				$RULES = &$RULES[$yych];
196 192
				if (isset($RULES['FIN'])) {
197 192
					$YYMATCH = $YYCURSOR;
198 144
				}
199 192
				$yych = $YYBUFFER[++$YYCURSOR];
200 144
			}
201 194
			if (isset($YYMATCH)) {
202 192
					$node["id"]="cmp";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
203 192
					$node["operator"]=substr($YYBUFFER, $YYCURSOR_START, ($YYMATCH + 1) - $YYCURSOR_START);
204 192
					$node["left"]=$result;
205 192
					$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
206 192
					$result=$this->parse_const($YYBUFFER);
207 192
					if ($result) {
208 192
						$node["right"]=$result;
209 144
					}
210 192
					$result=$node;
211 144
			} else {
212 2
				$this->error="unknow compare-operator near '$YYBUFFER'";
213
			}
214 146
		}
215 195
		return $result;
216
	}
217
218 195
	protected function parse_group_expr(&$YYBUFFER) {
219 195
		$YYCURSOR = 0;
220 195
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
221 186
			$YYCURSOR++;
222 140
		}
223 195
		$yych = $YYBUFFER[$YYCURSOR++];
224 195
		if ($yych === '(') {
225
			$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
226
			$result = $this->parse_or_expr($YYBUFFER);
227
			$YYCURSOR = 0;
228
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
229
				$YYCURSOR++;
230
			}
231
			$yych = $YYBUFFER[$YYCURSOR++];
232
			if ($yych === ')') {
233
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
234
				$node["id"]="group";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
235
				$node["left"]=$result;
236
				$result=$node;
237
			} else {
238
				unset($result);
239
				$this->error = "missing closing group sign near '$YYBUFFER'";
240
			}
241
		} else {
242 195
			$result = $this->parse_cmp_expr($YYBUFFER);
243
		}
244 195
		return $result;
245
	}
246
247 195 View Code Duplication
	protected function parse_and_expr(&$YYBUFFER) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
248 195
		$result=$this->parse_group_expr($YYBUFFER);
249 195
		while (is_array($result)) {
250 194
			$YYCURSOR = 0;
251 194
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
252 185
				$YYCURSOR++;
253 139
			}
254 194
			$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 3));
255 194
			if ($ident === 'and' && !isset($this->_SCAN_AZ_09[$YYBUFFER[$YYCURSOR + 3]]) ) {
256 184
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 3);
257 184
				$right = $this->parse_group_expr($YYBUFFER);
258 184
				if (is_array($right)) {
259
					$result = array(
260 184
						'id' => $ident,
261 184
						'left' => $result,
262 46
						'right' => $right
263 138
					);
264 138
				} else {
265 46
					unset($result);
266
				}
267 138
			} else {
268 194
				break;
269
			}
270 138
		}
271 195
		return $result;
272
	}
273
274 195 View Code Duplication
	protected function parse_or_expr(&$YYBUFFER) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
275 195
		$result=$this->parse_and_expr($YYBUFFER);
276 195
		while (is_array($result)) {
277 194
			$YYCURSOR = 0;
278 194
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
279 49
				$YYCURSOR++;
280 37
			}
281 194
			$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 2));
282 194
			if ($ident === 'or' && !isset($this->_SCAN_AZ_09[$YYBUFFER[$YYCURSOR + 2]]) ) {
283
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 2);
284
				$right = $this->parse_and_expr($YYBUFFER);
285
				if (is_array($right)) {
286
					$result = array(
287
						'id' => $ident,
288
						'left' => $result,
289
						'right' => $right
290
					);
291
				} else {
292
					unset($result);
293
				}
294
			} else {
295 194
				break;
296
			}
297
		}
298 195
		return $result;
299
	}
300
301 122
	protected function parse_orderby(&$YYBUFFER) {
302 50
		$field = $this->parse_ident($YYBUFFER);
303
304 50
		$YYCURSOR = 0;
305 86
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
306 1
			$YYCURSOR++;
307 1
		}
308 50
		$value = '';
309 50
		$yych  = $YYBUFFER[$YYCURSOR];
310 50 View Code Duplication
		if ($this->_SCAN_AZ[$yych]) {
311 1
			$value .= $yych;
312 1
			$yych = $YYBUFFER[++$YYCURSOR];
313 1
			while (isset($this->_SCAN_AZ[$yych])) {
314 1
				$value .= $yych;
315 1
				$yych = $YYBUFFER[++$YYCURSOR];
316 1
			}
317 1
			$sort_type = strtoupper($value);
318 1
			if (!($sort_type == 'ASC' || $sort_type == 'DESC')) { // If sort type is anything else than ASC or DESC, it is not part of the order by.
319 1
				$sort_type = 'ASC';
320 1
				$YYCURSOR = $YYCURSOR - strlen($value);
321 49
				$value = '';
0 ignored issues
show
Unused Code introduced by
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
322 1
			}
323 1
		} else {
324 49
			$sort_type = 'ASC';
325
		}
326 50
		while (is_array($field)) {
327
			$result = array(
328 86
				'id' => 'orderbyfield',
329 50
				'type' => $sort_type,
330 50
				'right' => $field,
331 12
				'left' => $result
0 ignored issues
show
Bug introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
332 38
			);
333 50
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
334
				$YYCURSOR++;
335
			}
336 50
			$yych  = $YYBUFFER[$YYCURSOR];
337 50
			if ($yych !== ',') {
338 50
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
339 50
				unset($field);
340 38
			} else {
341 1
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1);
342 1
				$field = $this->parse_ident($YYBUFFER);
343 1
				$YYCURSOR = 0;
344 1
				while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
345 48
					$YYCURSOR++;
346
				}
347 1
				$value = '';
348 1
				$yych  = $YYBUFFER[$YYCURSOR];
349 49 View Code Duplication
				if ($this->_SCAN_AZ[$yych]) {
350
					$value .= $yych;
351
					$yych = $YYBUFFER[++$YYCURSOR];
352
					while (isset($this->_SCAN_AZ[$yych])) {
353
						$value .= $yych;
354
						$yych = $YYBUFFER[++$YYCURSOR];
355
					}
356
					$sort_type = strtoupper($value);
357
					if (!($sort_type == 'ASC' || $sort_type == 'DESC')) { // If sort type is anything else than ASC or DESC, it is not part of the order by.
358
						$sort_type = 'ASC';
359
						$YYCURSOR = $YYCURSOR - strlen($value);
360
						$value = '';
0 ignored issues
show
Unused Code introduced by
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
361
					}
362
				} else {
363 1
					$sort_type = 'ASC';
364
				}
365
			}
366 38
		}
367 50
		return $result;
368
	}
369
370
371
	protected function parse_join_target_properties(&$query) {
372
		do {
373
			if (!preg_match('/^([a-z_][a-z0-9_]*)(:[a-z]+)?/i', $query, $regs)) {
374
				$this->error = "expected property name at '$query'";
375
				return false;
376
			}
377
			$this->join_target_properties["prop_".$regs[1]][$regs[2]] = true;
378
			$query = substr($query, strlen($regs[0]));
379
380
			if (!preg_match('/^[[:space:]]*,[[:space:]]*/', $query, $regs)) {
381
				return true;
382
			}
383
			$query = substr($query, strlen($regs[0]));
384
		} while(1);
385
	}
386
387 197
	protected function parse_query(&$query) {
388
389 197
		if (!preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs)) {
390 195
			$result=$this->parse_or_expr($query);
391 147
		} else {
392 2
			$no_selection = true;
393
		}
394
395
/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
396
		$YYCURSOR = 0;
397
		while ($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]]) {
398
			$YYCURSOR++;
399
		}
400
401
		$yych  = $YYBUFFER[$YYCURSOR];
402
		if ($this->_SCAN_AZ[$yych]) {
403
			$value = $yych;
404
			$yych  = $YYBUFFER[++$YYCURSOR];
405
			while ($this->_SCAN_AZ[$yych]) {
406
				$value .= $yych;
407
				$yych = $YYBUFFER[++$YYCURSOR];
408
			}
409
			$value = strtolower($value);
410
			if ($value === 'order') {
411
				while ($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]]) {
412
					$YYCURSOR++;
413
				}
414
				$yych  = $YYBUFFER[$YYCURSOR];
415
				if ($this->_SCAN_AZ[$yych]) {
416
					$value = $yych;
417
					$yych  = $YYBUFFER[++$YYCURSOR];
418
					while ($this->_SCAN_AZ[$yych]) {
419
						$value .= $yych;
420
						$yych = $YYBUFFER[++$YYCURSOR];
421
					}
422
					$value = strtolower($value);
423
					if ($value === 'by') {
424
						$YYBUFFER = substr($YYBUFFER, $YYCURSOR;
425
						$result = $this->parse_or_expr($YYBUFFER);
426
						$YYCURSOR = 0;
427
						$value = '';
428
					} else {
429
						$this->error = "syntax error near: $YYBUFFER";
430
						return false;
431
					}
432
				}
433
			}
434
		}
435
436
*/
437
438 197
		if (preg_match('|^[[:space:]]*join[[:space:]]*target[[:space:]]*on[[:space:]]*|i', $query, $regs)) {
439
			$this->join_target_properties = array();
440
			$query = substr($query, strlen($regs[0]));
441
			$this->parse_join_target_properties($query);
442
		}
443
444 197
		$matching = preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs);
445 197
		if ( $matching || $no_selection ) {
0 ignored issues
show
Bug introduced by
The variable $no_selection does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
446 50
			$query=substr($query, strlen($regs[0]));
447 50
			$node["id"]="orderby";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$node was never initialized. Although not strictly required by PHP, it is generally a good practice to add $node = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
448 50
			$node["right"]=$this->parse_orderby($query);
449 50
			$node["left"]=$result;
0 ignored issues
show
Bug introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
450 50
			$result=$node;
451 38
		}
452 197
		if (preg_match('|^[[:space:]]*limit[[:space:]]+([0-9]+)[[:space:]]*([,][[:space:]]*([0-9]+))?|i', $query, $regs)) {
453 1
			$query=substr($query, strlen($regs[0]));
454 1
			$limit_s["id"]="limit";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$limit_s was never initialized. Although not strictly required by PHP, it is generally a good practice to add $limit_s = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
455 1
			$limit_s["offset"]=$regs[1];
456 1
			$limit_s["limit"]=$regs[3];
457 1
		} else {
458 196
			$limit_s["id"]="limit";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$limit_s was never initialized. Although not strictly required by PHP, it is generally a good practice to add $limit_s = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
459 196
			$limit_s["offset"]=($this->offset) ? $this->offset : 0;
460 196
			$limit_s["limit"]=($this->limit) ? $this->limit : 0;
461
		}
462 197
		$limit_s["left"]=$result;
463 197
		$result=$limit_s;
464
465 197
		return $result;
466
	}
467
468
	// virtual (&private) method. To be implemented in the sql specific compiler
469
	protected abstract function priv_sql_compile($node) ;
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
470
471 197
	public function compile($path, $query, $limit=100, $offset=0, $layers = array()) {
472 197
		debug("sql_compiler::compile ($path, $query, $limit, $offset)", "store");
473 197
		$this->error="";
474 197
		$this->path = $path;
475
476 197
		$this->limit=$limit;
477 197
		$this->offset=$offset;
478 197
		$this->layers=$layers;
0 ignored issues
show
Bug introduced by
The property layers does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
479
480 197
		$tree=$this->parse_query($query);
481
482 197
		if ( $this->error ) {
483 2
			return null;
484 195
		} else if ( trim($query) ) {
485
			// no error detected, but there is still a part of the query left
486
			$this->error="unkown operator near '$query'";
487
			return null;
488 195
		} else if ( $tree ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tree of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
489 195
			$compiled_query=$this->priv_sql_compile($tree);
490 195
			return $compiled_query;
491
		} else {
492
			return null;
493
		}
494
495
	}
496
497
498
  }
499