Completed
Push — php7.2-travis ( 4ad508...e16e79 )
by
unknown
12:11
created

sql_compiler   D

Complexity

Total Complexity 90

Size/Duplication

Total Lines 496
Duplicated Lines 21.77 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 51.25%

Importance

Changes 0
Metric Value
dl 108
loc 496
ccs 203
cts 396
cp 0.5125
rs 4.8717
c 0
b 0
f 0
wmc 90
lcom 1
cbo 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
priv_sql_compile() 0 1 ?
B parse_and_expr() 26 26 6
B parse_or_expr() 26 26 6
A parse_join_target_properties() 0 15 4
F parse_ident() 24 109 22
C parse_cmp_expr() 0 33 7
B parse_group_expr() 0 28 5
C parse_query() 0 80 8
B compile() 0 25 4
C parse_const() 0 53 14
C parse_orderby() 32 68 14

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like sql_compiler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use sql_compiler, and based on these observations, apply Extract Interface, too.

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 13
	protected function parse_const(&$YYBUFFER) {
21 13
		$YYCURSOR = 0;
22 13
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
23 1
			$YYCURSOR++;
24 1
		}
25 13
		$value = '';
26 13
		$yych = $YYBUFFER[$YYCURSOR];
27
		switch (true) {
28 13
			case '"' === $yych:
29 13
			case "'" === $yych:
30 12
				$quote = $yych;
31 12
				$yych = $YYBUFFER[++$YYCURSOR];
32 12
				while ($yych !== "\0" && $yych !== $quote) {
33 12
					if ($yych === "\\") {
34 12
						$yych = $YYBUFFER[++$YYCURSOR];
35
						if ($yych !== $quote && $yych != "\\") {
36
							$value .= "\\";
37
						}
38 12
					}
39 12
					$value .= $yych;
40 12
					$yych = $YYBUFFER[++$YYCURSOR];
41 12
				}
42 12
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1);
43 12
				$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 12
				$node["type"] = ($quote === '"') ? "double" : "single";
45 12
				$node["value"] = stripslashes($value);
46 12
				return $node;
47
			break;
48 1
			case $this->_SCAN_NUM_START[$yych]:
49 1
				$value = $yych;
50 1
				$yych = $YYBUFFER[++$YYCURSOR];
51 1
				while (isset($this->_SCAN_NUM[$yych])) {
52
					$value .= $yych;
53 1
					$yych = $YYBUFFER[++$YYCURSOR];
54
				}
55 1
				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 1
					$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 1
					$node["value"]=(int)$value;;
67
				}
68 1
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
69 1
				return $node;
70
			break;
71
		}
72
	}
73
74 13
	protected function parse_ident(&$YYBUFFER) {
75
		/* parse identifier regs 1,2 and 3
76
77
			reg[1]: tablename
78
			reg[2]: property name
79
			reg[3]: only used with 'my' properties
80
		*/
81 13
		$reg_id='^[[:space:]]*(([a-z_][a-z0-9_]*)(:[a-z]+)?([.][a-z_][a-z0-9_]*)?([.][a-z_][a-z0-9_]*)?)';
82 13
		$reg_id.='[[:space:]]*';
83
84 13
		$YYCURSOR = 0;
85 13
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
86
			$YYCURSOR++;
87
		}
88 13
		$value = '';
89 13
		$yych = $YYBUFFER[$YYCURSOR];
90
91 13
		if ($this->_SCAN_AZ[$yych]) {
92 13
			$value .= $yych;
93 13
			$yych = $YYBUFFER[++$YYCURSOR];
94 13
			while (isset($this->_SCAN_AZ_09[$yych])) {
95 13
				$value .= $yych;
96 13
				$yych = $YYBUFFER[++$YYCURSOR];
97 13
			}
98 13
			$match_1 = $value; $value = '';
99 13
			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 13 View Code Duplication
			if ($yych === '.') {
108 13
				$yych = $YYBUFFER[++$YYCURSOR];
109 13
				if ($this->_SCAN_AZ[$yych]) {
110 13
					$value .= $yych;
111 13
					$yych = $YYBUFFER[++$YYCURSOR];
112 13
					while (isset($this->_SCAN_AZ_09[$yych])) {
113 13
						$value .= $yych;
114 13
						$yych = $YYBUFFER[++$YYCURSOR];
115 13
					}
116 13
				}
117 13
				$match_2 = $value; $value = '';
118 13
			}
119 13 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 13
		}
133
134
135 13
		if($match_1) {
136 13
			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 12
				$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 12
				$match_1 = "object";
140 12
			}
141 13
			$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 13
			$table=$match_1;
144 13
			$field=$match_2;
145 13
			if ($table=="object") {
146
				switch ($field) {
147 13
					case "implements":
148
						$node["id"]="implements";
149
					break;
150 13
					case "path":
151 13
					case "parent":
152 13
					case "priority":
153
						$node["table"]="nodes";
154
						$node["field"]=$field;
155
					break;
156 13
					default:
157 13
						$node["table"]="objects";
158 13
						$node["field"]=$field;
159 13
				}
160 13
			} else
161 12
			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 12
				$node["id"]="property";
171 12
				if ($match_3) {
172
					$node["nls"] = $field;
173
					$field = $match_3;
174
				}
175 12
				$node["table"]="prop_".$table;
176 12
				$node["field"]="AR_".$field;
177 12
				$node["record_id"] = $record_id;
178
			}
179 13
		}
180 13
		$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
181 13
		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 13
	protected function parse_cmp_expr(&$YYBUFFER) {
185 13
		$result=$this->parse_ident($YYBUFFER);
186 13
		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 13
			$YYCURSOR = 0;
188 13
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
189 1
				$YYCURSOR++;
190 1
			}
191 13
			$yych = $YYBUFFER[$YYCURSOR];
192 13
			$YYCURSOR_START = $YYCURSOR;
193 13
			$RULES = &$this->_SCAN_CMP;
194 13
			while (isset($RULES[$yych])) {
195 13
				$RULES = &$RULES[$yych];
196 13
				if (isset($RULES['FIN'])) {
197 13
					$YYMATCH = $YYCURSOR;
198 13
				}
199 13
				$yych = $YYBUFFER[++$YYCURSOR];
200 13
			}
201 13
			if (isset($YYMATCH)) {
202 13
					$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 13
					$node["operator"]=substr($YYBUFFER, $YYCURSOR_START, ($YYMATCH + 1) - $YYCURSOR_START);
204 13
					$node["left"]=$result;
205 13
					$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
206 13
					$result=$this->parse_const($YYBUFFER);
207 13
					if ($result) {
208 13
						$node["right"]=$result;
209 13
					}
210 13
					$result=$node;
211 13
			} else {
212
				$this->error="unknow compare-operator near '$YYBUFFER'";
213
			}
214 13
		}
215 13
		return $result;
216
	}
217
218 13
	protected function parse_group_expr(&$YYBUFFER) {
219 13
		$YYCURSOR = 0;
220 13
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
221
			$YYCURSOR++;
222
		}
223 13
		$yych = $YYBUFFER[$YYCURSOR++];
224 13
		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 13
			$result = $this->parse_cmp_expr($YYBUFFER);
243
		}
244 13
		return $result;
245
	}
246
247 13 View Code Duplication
	protected function parse_and_expr(&$YYBUFFER) {
248 13
		$result=$this->parse_group_expr($YYBUFFER);
249 13
		while (is_array($result)) {
250 13
			$YYCURSOR = 0;
251 13
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
252 12
				$YYCURSOR++;
253 12
			}
254 13
			$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 3));
255 13
			if ($ident === 'and' && !isset($this->_SCAN_AZ_09[$YYBUFFER[$YYCURSOR + 3]]) ) {
256
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 3);
257
				$right = $this->parse_group_expr($YYBUFFER);
258
				if (is_array($right)) {
259
					$result = array(
260
						'id' => $ident,
261
						'left' => $result,
262
						'right' => $right
263
					);
264
				} else {
265
					unset($result);
266
				}
267
			} else {
268 13
				break;
269
			}
270
		}
271 13
		return $result;
272
	}
273
274 13 View Code Duplication
	protected function parse_or_expr(&$YYBUFFER) {
275 13
		$result=$this->parse_and_expr($YYBUFFER);
276 13
		while (is_array($result)) {
277 13
			$YYCURSOR = 0;
278 13
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
279 12
				$YYCURSOR++;
280 12
			}
281 13
			$ident = strtolower(substr($YYBUFFER, $YYCURSOR, 2));
282 13
			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 13
				break;
296
			}
297
		}
298 13
		return $result;
299
	}
300
301 12
	protected function parse_orderby(&$YYBUFFER) {
302 12
		$field = $this->parse_ident($YYBUFFER);
303
304 12
		$YYCURSOR = 0;
305 12
		while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
306
			$YYCURSOR++;
307
		}
308 12
		$value = '';
309 12
		$yych  = $YYBUFFER[$YYCURSOR];
310 12 View Code Duplication
		if ($this->_SCAN_AZ[$yych]) {
311
			$value .= $yych;
312
			$yych = $YYBUFFER[++$YYCURSOR];
313
			while (isset($this->_SCAN_AZ[$yych])) {
314
				$value .= $yych;
315
				$yych = $YYBUFFER[++$YYCURSOR];
316
			}
317
			$sort_type = strtoupper($value);
318
			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
				$sort_type = 'ASC';
320
				$YYCURSOR = $YYCURSOR - strlen($value);
321
				$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
			}
323
		} else {
324 12
			$sort_type = 'ASC';
325
		}
326 12
		while (is_array($field)) {
327
			$result = array(
328 12
				'id' => 'orderbyfield',
329 12
				'type' => $sort_type,
330 12
				'right' => $field,
331
				'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 12
			);
333 12
			while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
334
				$YYCURSOR++;
335
			}
336 12
			$yych  = $YYBUFFER[$YYCURSOR];
337 12
			if ($yych !== ',') {
338 12
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR);
339 12
				unset($field);
340 12
			} else {
341
				$YYBUFFER = substr($YYBUFFER, $YYCURSOR + 1);
342
				$field = $this->parse_ident($YYBUFFER);
343
				$YYCURSOR = 0;
344
				while (isset($this->_SCAN_WS[$YYBUFFER[$YYCURSOR]])) {
345
					$YYCURSOR++;
346
				}
347
				$value = '';
348
				$yych  = $YYBUFFER[$YYCURSOR];
349 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
					$sort_type = 'ASC';
364
				}
365
			}
366 12
		}
367 12
		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 13
	protected function parse_query(&$query) {
388
389 13
		if (!preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs)) {
390 13
			$result=$this->parse_or_expr($query);
391 13
		} else {
392
			$no_selection = true;
393
		}
394
395
/*
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 13
		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 13
		$matching = preg_match('|^[[:space:]]*order[[:space:]]*by[[:space:]]+|i', $query, $regs);
445 13
		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 12
			$query=substr($query, strlen($regs[0]));
447 12
			$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 12
			$node["right"]=$this->parse_orderby($query);
449 12
			$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 12
			$result=$node;
451 12
		}
452 13
		if (preg_match('|^[[:space:]]*limit[[:space:]]+([0-9]+)[[:space:]]*([,][[:space:]]*([0-9]+))?|i', $query, $regs)) {
453
			$query=substr($query, strlen($regs[0]));
454
			$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
			$limit_s["offset"]=$regs[1];
456
			$limit_s["limit"]=$regs[3];
457
		} else {
458 13
			$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 13
			$limit_s["offset"]=($this->offset) ? $this->offset : 0;
460 13
			$limit_s["limit"]=($this->limit) ? $this->limit : 0;
461
		}
462 13
		$limit_s["left"]=$result;
463 13
		$result=$limit_s;
464
465 13
		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 13
	public function compile($path, $query, $limit=100, $offset=0, $layers = array()) {
472 13
		debug("sql_compiler::compile ($path, $query, $limit, $offset)", "store");
473 13
		$this->error="";
474 13
		$this->path = $path;
475
476 13
		$this->limit=$limit;
477 13
		$this->offset=$offset;
478 13
		$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 13
		$tree=$this->parse_query($query);
481
482 13
		if ( $this->error ) {
483
			return null;
484 13
		} 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 13
		} 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 13
			$compiled_query=$this->priv_sql_compile($tree);
490 13
			return $compiled_query;
491
		} else {
492
			return null;
493
		}
494
495
	}
496
497
498
  }
499