Completed
Pull Request — master (#85)
by Robbert
87:16 queued 75:50
created

postgresql_compiler   D

Complexity

Total Complexity 82

Size/Duplication

Total Lines 352
Duplicated Lines 43.47 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 41.95%
Metric Value
wmc 82
lcom 1
cbo 1
dl 153
loc 352
ccs 125
cts 298
cp 0.4195
rs 4.8718

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B test_for_lowercase() 0 13 5
D compile_tree() 148 248 63
F priv_sql_compile() 5 65 13

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 postgresql_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 postgresql_compiler, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 4 and the first side effect is on line 2.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
include($this->code."stores/modules/sql_compiler.php");
3
4
class postgresql_compiler extends sql_compiler {
5
	protected $tbl_prefix;
6
	protected $in_orderby;
7
	protected $nls_join;
8
	protected $select_tables;
9
	protected $used_tables;
10
	protected $custom_id;
11
	protected $custom_ref;
12
	protected $used_custom_fields;
13
	protected $where_s_ext;
14
	protected $where_s;
15
	protected $limit_s;
16
	protected $orderby_s;
17
	protected $select_list;
18
19 96
	function __construct(&$store, $tbl_prefix="") {
20 96
		debug("postgresql_compiler($tbl_prefix)", "store");
21 96
		$this->tbl_prefix=$tbl_prefix;
22 96
		$this->store=$store;
23 96
	}
24
25 96
	function test_for_lowercase(&$node){
26 96
		$ret = false;
27 96
		switch ((string)$node["id"]) {
28 96
			case 'ident':
29
				if ( $node["table"] == "nodes" ) {
30
					if ( $node["field"] == "path" or $node["field"] == "parent" ) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
31
						$ret = true;
32
					}
33
				}
34
				break;
35
		}
36 96
		return $ret;
37
	}
38
39 96
	function compile_tree(&$node) {
40 96
		switch ((string)$node["id"]) {
41 96
			case 'property':
42 96
				$table=$this->tbl_prefix.$node["table"];
43 96
				$field=$node["field"];
44 96
				$record_id=$node["record_id"];
45 96
				if (!$record_id) {
46 96
					if (!$this->in_orderby) {
47 96
						$result=" $table.object = ".$this->tbl_prefix."objects.id and $table.$field ";
48 96
						$this->used_tables[$table]=$table;
49 96 View Code Duplication
					} else {
50
						if ($this->in_orderby && $node["nls"]) {
51
							/*
52
								we do a left join so that we will also find non
53
								matching objects
54
							*/
55
							$objects_table = $this->tbl_prefix."objects";
56
							$this->nls_join[$table] = "left join $table as order_$table on $objects_table.id=order_$table.object and order_$table.AR_nls='".$node["nls"]."' ";
57
58
							$result = " order_$table.$field ";
59
							$this->select_list["order_".$table.".".$field] = "order_$table.$field";
60
61
						} else {
62
							/*
63
								if we are parsing 'orderby' properties we have
64
								to join our tables for the whole query
65
							*/
66
							$this->select_tables[$table]=$table;
67
							$this->used_tables[$table]=$table;
68
							$result=" $table.$field ";
69
						}
70
					}
71 96
				} else {
72
					$this->used_tables["$table as $table$record_id"] = $table.$record_id;
73
					if (!$this->in_orderby) {
74
						$result=" $table$record_id.object = ".$this->tbl_prefix."objects.id and $table$record_id.$field ";
75
					} else {
76
						$this->select_tables["$table as $table$record_id"] = $table.$record_id;
77
						$result=" $table$record_id.$field ";
78
					}
79
				}
80 96
			break;
81 96 View Code Duplication
			case 'ident':
82
				$table=$this->tbl_prefix.$node["table"];
83
				$field=$node["field"];
84
				$this->used_tables[$table]=$table;
85
				$result=" $table.$field ";
86
			break;
87 96 View Code Duplication
			case 'custom':
88
				$table = $this->tbl_prefix."prop_custom";
89
				$field = $node["field"];
90
				$nls = $node["nls"];
91
				$record_id = $node["record_id"];
92
				/*
93
					when we are compiling orderby properties we always want
94
					to assign it to a new table alias
95
				*/
96
				if ($this->in_orderby) {
97
					$this->custom_id++;
98
				}
99
				$this->custom_ref++;
100
				if (!$record_id) {
101
					$this->used_tables[$table." as $table".$this->custom_id] = $table.$this->custom_id;
102
					$this->select_tables[$table." as $table".$this->custom_id] = 1;
103
104
					$this->used_custom_fields[$field] = true;
105
					$result = " $table".$this->custom_id.".AR_name = '$field' ";
106
					if ($nls) {
107
						$result = " $result and $table".$this->custom_id.".AR_nls = '$nls' ";
108
					}
109
110
					if (!$this->in_orderby) {
111
						$result = " $result and $table".$this->custom_id.".AR_value ";
112
					} else {
113
						$this->where_s_ext = $result;
114
						$result = " $table".$this->custom_id.".AR_value ";
115
					}
116
				} else {
117
					$this->used_tables["$table as $table$record_id"] = $table.$record_id;
118
			//		$this->select_tables[$table." as $table$record_id"] = 1;
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...
119
120
					$result = " $table$record_id.AR_name = '$field' ";
121
					if (!$this->in_orderby ) {
122
						if ($this->join_target_properties["prop_my"][":$record_id"]) {
123
							$result=" $result and $table$record_id.object = target.object and $table$record_id.AR_value ";
124
						} else {
125
							$result=" $table$record_id.object = ".$this->tbl_prefix."objects.id and $table$record_id.AR_value ";
126
						}
127
					} else {
128
						if ($this->join_target_properties[$node["table"]]) {
129
							$this->join_target_properties["$table as $table$record_id"] = $table.$record_id;
130
						}
131
						$this->select_tables["$table as $table$record_id"] = $table.$record_id;
132
						$result=" $table$record_id.AR_value ";
133
					}
134
				}
135
			break;
136 96
			case 'string':
137 96
				$result=" '".pg_escape_string($node["value"])."' ";
138 96
			break;
139 96
			case 'float':
140 96
			case 'int':
141
				$result=" ".$node["value"]." ";
142
			break;
143 96 View Code Duplication
			case 'and':
144 92
				$cr = $this->custom_ref;
145 92
				$left=$this->compile_tree($node["left"]);
146 92
				if ($this->custom_ref > $cr) {
147
					$this->custom_id++;
148
				}
149
150 92
				$right=$this->compile_tree($node["right"]);
151 92
				$cr = $this->custom_ref;
152 92
				if ($this->custom_ref > $cr) {
153
					$this->custom_id++;
154
				}
155 92
				$result=" $left and $right ";
156 92
			break;
157 96 View Code Duplication
			case 'or':
158
				$left=$this->compile_tree($node["left"]);
159
				$right=$this->compile_tree($node["right"]);
160
				$result=" $left or $right ";
161
			break;
162 96
			case 'cmp':
163 96
				$not = '';
164 96
				switch ($node["operator"]) {
165 96
					case '=':
166 96
					case '==':
167 96
						$operator="=";
168 96
					break;
169
					case '!=':
170
					case '<=':
171
					case '>=':
172
					case '<':
173
					case '>':
174
						$operator=$node["operator"];
175
					break;
176
					case '!~':
177
					case '!~~':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
178
						$not="NOT ";
179
 					case '~=':
180
					case '=~':
181 View Code Duplication
					case '=~~':
182
						if (!strlen($node["operator"])==3) {
183
							$not.="I";
184
						}
185
						$operator=$not."LIKE";
186
					break;
187
					case '!/':
188
					case '!//':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
189
						$not="!";
190
					case '=/':
191 View Code Duplication
					case '=//':
192
						$operator=$not."~";
193
						if (strlen($node["operator"])==3) {
194
							$operator.="*";
195
						}
196
						break;
197 96
				}
198 96
				if ($node["left"]["id"]!=="implements") {
199 96
					$left=$this->compile_tree($node["left"]);
200 96
					$right=$this->compile_tree($node["right"]);
201 96
					if($this->test_for_lowercase($node["left"])){
202
						// lowercase compile
203
						$result=" lower($left) $operator lower($right) ";
0 ignored issues
show
Bug introduced by
The variable $operator 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...
204
					} else {
205
						// normal compile
206
						/* lastchanged == unixtimestamp -> lastchanged == 200201.. */
207 96
						if ($node["left"]["field"]=="lastchanged") {
208
							$right = "to_timestamp($right)";
209
						}
210 96
						$result=" $left $operator $right ";
211
					}
212 96
				} else {
213 92
					$table=$this->tbl_prefix."types";
214 92
					$type=$this->compile_tree($node["right"]);
215
					switch ($operator) {
216 92 View Code Duplication
						case '!=':
217
							$result=" (".$this->tbl_prefix."objects.type not in (select type from ".$this->tbl_prefix."types where implements = $type )) ";
218
						break;
219 92
						default:
220 92
							$this->used_tables[$table]=$table;
221 92
							$result=" (".$this->tbl_prefix."types.implements $operator $type and ".$this->tbl_prefix."objects.vtype = ".$this->tbl_prefix."types.type ) ";
222 92
						break;
223 92
					}
224
				}
225 96
			break;
226 96 View Code Duplication
			case 'group':
227
				$left=$this->compile_tree($node["left"]);
228
				if ($left) {
229
					$result=" ( $left ) ";
230
				}
231
			break;
232
233 96 View Code Duplication
			case 'orderby':
234 24
				$result=$this->compile_tree($node["left"]);
235 24
				$this->orderby_s=$this->compile_tree($node["right"]);
236 24
			break;
237
238 96
			case 'orderbyfield':
239 24
				$this->in_orderby = true;
240 24
				$left=$this->compile_tree($node["left"]);
241 24
				if ( $node["right"]["field"] != "none" ) {
242
					$right=$this->compile_tree($node["right"]);
243
					if ($left) {
244
						$result=" $left ,  $right ".$node["type"]." ";
245 View Code Duplication
						if($node["left"]['id'] == 'property' && !$node["right"]['nls']){
246
							$lefttablefield = $this->tbl_prefix.$node["left"]['table'].".".$node["left"]['field'];
247
							$this->select_list[$lefttablefield] = $lefttablefield;
248
						}
249
					} else {
250
						$result=" $right ".$node["type"]." ";
251
					}
252 View Code Duplication
					if($node["right"]['id'] == 'property' && !$node["right"]['nls']){
253
						$righttablefield = $this->tbl_prefix.$node["right"]['table'].".".$node["right"]['field'];
254
						$this->select_list[$righttablefield] = $righttablefield;
255
					}
256
				} else {
257 24
					$result = "";
258 24
					if ($left) {
259
						$result = " $left ";
260 View Code Duplication
						if($node["left"]['id'] == 'property' && !$node["right"]['nls']){
261
							$lefttablefield = $this->tbl_prefix.$node["left"]['table'].".".$node["left"]['field'];
262
							$this->select_list[$lefttablefield] = $lefttablefield;
263
						}
264
					}
265 24
					$this->skipDefaultOrderBy = true;
266
				}
267 24
			break;
268
269 96 View Code Duplication
			case 'limit':
270 96
				$this->where_s=$this->compile_tree($node["left"]);
271 96
				$this->limit_s="";
272 96
				if ($node["limit"]) {
273 96
					$this->limit_s=" offset ".(int)$node["offset"]." limit ".$node["limit"]." ";
274 96
				} else
275 24
				if ($node["offset"]) {
276
					$this->limit_s=" limit ".(int)$node["offset"]." ";
277
				} else {
278 24
					if ($this->limit) {
279
						$offset = (int)$this->offset;
280
						$this->limit_s=" offset $offset limit ".(int)$this->limit." ";
281
					}
282
				}
283 96
			break;
284
		}
285 96
		return $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...
286
	}
287
288
	// postgresql specific compiler function
289 96
	function priv_sql_compile($tree) {
290 96
		$this->custom_ref = 0;
291 96
		$this->custom_id = 0;
292 96
		$this->used_tables="";
293 96
		$this->compile_tree($tree);
294
295 96
		if ( $this->error ) {
296
			return null;
297
		}
298
299 96
		$nodes=$this->tbl_prefix."nodes";
300 96
		$objects=$this->tbl_prefix."objects";
301 96
		$this->used_tables[$nodes]=$nodes;
302 96
		$this->used_tables[$objects]=$objects;
303 96
		@reset($this->used_tables);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
304 96
		while (list($key, $val)=each($this->used_tables)) {
305 96
			if ($tables) {
306 96
				$tables.=", $key";
0 ignored issues
show
Bug introduced by
The variable $tables 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...
307 96
			} else {
308 96
				$tables="$key";
309
			}
310 96
			if ($this->select_tables[$key]) {
311
				$prop_dep.=" and $val.object=$objects.id ";
0 ignored issues
show
Bug introduced by
The variable $prop_dep 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...
312
			}
313 96
		}
314 96
		if (is_array($this->nls_join)) {
315
			$join = join($this->nls_join);
316
		}
317 96
		if(is_array($this->select_list)){
318
			$select = join(", ", $this->select_list);
319
		}
320
321 96
		$query ="where $nodes.object=$objects.id $prop_dep";
322 96
		$query.=" and $nodes.path like '".str_replace('_','\\_',pg_escape_string($this->path))."%' ";
323 96
		if ($this->where_s) {
324 96
			$query.=" and ( $this->where_s ) ";
325 96
		}
326 96
		if ($this->where_s_ext) {
327
			$query .= " and ($this->where_s_ext) ";
328
		}
329 96
		$order = '';
330 96
		if ($this->orderby_s) {
331 View Code Duplication
			if ($this->skipDefaultOrderBy) {
332
				$order .= "order by $this->orderby_s";
333
			} else {
334
				$order .= "order by $this->orderby_s, $nodes.parent ASC, $nodes.priority DESC, $nodes.path ASC ";
335
			}
336 96
		} else if (!$this->skipDefaultOrderBy) {
337 96
			$order .= "order by $nodes.parent ASC, $nodes.priority DESC, $nodes.path ASC ";
338 96
		}
339
340 96
		$order .= " $this->limit_s ";
341
342 96
		$select_query  = "select distinct($nodes.path), $nodes.parent, $nodes.priority, ";
343 96
		$select_query .= " $objects.id, $objects.type, $objects.object, date_part('epoch', $objects.lastchanged) as lastchanged, $objects.vtype ";
344
345 96
		if($select){
346
			$select_query .= ", " . $select;
0 ignored issues
show
Bug introduced by
The variable $select 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...
347
		}
348
349 96
		$select_query .= " from $tables $join $query $order";
0 ignored issues
show
Bug introduced by
The variable $join 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...
350 96
		$count_query = "select count(distinct($nodes.path)) as count from $tables ".$query;
351
352 96
		return Array("select_query" => $select_query, "count_query" => $count_query);
353
	}
354
355
  }
356