SRFExhibit::determineNamespace()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 0
cts 15
cp 0
rs 9.7
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 20
1
<?php
2
/**
3
 * Use Exhibit to print query results.
4
 *
5
 * @author Fabian Howahl
6
 * @file
7
 * @ingroup SMWQuery
8
 */
9
10
use MediaWiki\MediaWikiServices;
11
12
/**
13
 * Result printer using Exhibit to display query results
14
 *
15
 * @ingroup SMWQuery
16
 */
17
class SRFExhibit extends SMWResultPrinter {
18
19
	// /mapping between SMW's and Exhibit's the data types
20
	protected $m_types = [ "_wpg" => "text", "_num" => "number", "_dat" => "date", "_geo" => "text", "_uri" => "url" ];
21
22
	protected static $exhibitRunningNumber = 0; // not sufficient since there might be multiple pages rendered within one PHP run; but good enough now
23
24
	// /overwrite function to allow execution of result printer even if no results are available (in case remote query yields no results in local wiki)
25
	public function getResult( $results, $params, $outputmode ) {
26
		$this->readParameters( $params, $outputmode );
27
		$result = $this->getResultText( $results, $outputmode );
28
		return $result;
29
	}
30
31
	// /function aligns the format of SMW's property names to Exhibit's format
32
	protected function encodePropertyName( $property ) {
33
		return strtolower( str_replace( " ", "_", trim( $property ) ) );
34
	}
35
36
	// /Tries to determine the namespace in the event it got lost
37
	protected function determineNamespace( $res ) {
38
		$row = $res->getNext();
39
		if ( $row != null ) {
40
			$tmp = clone $row[0];
41
			$object = $tmp->getNextDataValue();
42
43
			if ( $object instanceof SMWWikiPageValue ) {
44
				$value = $object->getPrefixedText();
45
				if ( strpos( $value, ':' ) ) {
46
					$value = explode( ':', $value, 2 );
47
					return $value[0] . ':';
48
				}
49
			}
50
		}
51
52
		return "";
53
	}
54
55
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
56
57
		global $smwgIQRunningNumber, $wgScriptPath, $wgGoogleMapsKey, $srfgScriptPath;
58
59
		if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
60
			SMWOutputs::requireHeadItem( 'exhibit-compat', Html::linkedScript( "$wgScriptPath/common/wikibits.js" ) );
61
		}
62
63
		// //////////////////////////////
64
		// ///////REMOTE STUFF///////////
65
		// //////////////////////////////
66
67
		$remote = false;
68
69
		// in case the remote parameter is set, a link to the JSON export of the remote wiki is included in the header as data source for Exhibit
70
		// this section creates the link
71
		if ( array_key_exists( 'remote', $this->params ) && srfgExhibitRemote == true ) {
72
73
			$remote = true;
74
75
			// fetch interwiki link
76
			$dbr = &wfGetDB( DB_REPLICA );
77
			$cl = $dbr->tableName( 'interwiki' );
78
			$dbres = $dbr->select( $cl, 'iw_url', "iw_prefix='" . $this->params['remote'] . "'", __METHOD__, [] );
79
			$row = $dbr->fetchRow( $dbres );
80
			$extlinkpattern = $row[iw_url];
81
			$dbr->freeResult( $dbres );
82
83
			$newheader = '<link rel="exhibit/data" type="application/jsonp" href="';
84
			$link = $res->getQueryLink( 'JSON Link' );
85
			$link->setParameter( 'json', 'format' );
86
87
			if ( array_key_exists(
88
				'callback',
89
				$this->params
90
			) ) { // check if a special name for the callback function is set, if not stick with 'callback'
91
				$callbackfunc = $this->params['callback'];
92
			} else {
93
				$callbackfunc = 'callback';
94
			}
95
96
			if ( array_key_exists( 'limit', $this->params ) ) {
97
				$link->setParameter( $this->params['limit'], 'limit' );
98
			}
99
100
			$link->setParameter( $callbackfunc, 'callback' );
101
			$link = $link->getText( 2, $this->mLinker );
102
103
			list( $link, $trash ) = explode( '|', $link );
0 ignored issues
show
Unused Code introduced by Jeroen De Dauw
The assignment to $trash is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
104
			$link = str_replace( '[[:', '', $link );
105
106
			$newheader .= str_replace( '$1', $link, $extlinkpattern );
107
			$newheader .= '" ex:jsonp-callback="' . $callbackfunc . '"';
108
			$newheader .= '/>';
109
110
			SMWOutputs::requireHeadItem( 'REMOTE', $newheader );
111
		}
112
113
		// the following variables indicate the use of special views
114
		// the variable's values define the way Exhibit is called
115
		$timeline = false;
116
		$map = false;
117
118
		/*The javascript file adopted from Wibbit uses a bunch of javascript variables in the header to store information about the Exhibit markup.
119
		 The following code sequence creates these variables*/
120
121
		// prepare sources (the sources holds information about the table which contains the information)
122
		$colstack = [];
123
		foreach ( $res->getPrintRequests() as $pr ) {
124
			$colstack[] = $this->encodePropertyName( $pr->getLabel() ) . ':' . ( array_key_exists(
125
					$pr->getTypeID(),
126
					$this->m_types
127
				) ? $this->m_types[$pr->getTypeID()] : 'text' );
128
		}
129
		array_shift( $colstack );
130
		array_unshift( $colstack, 'label' );
131
132
		if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
133
			$sourcesrc = "var ex_sources = { source" . ( $smwgIQRunningNumber - 1 ) . ": { id:  'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
134
					',',
135
					$colstack
136
				) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' } };";
137
		} else {
138
			$sourcesrc = "sources.source" . $smwgIQRunningNumber . " =  { id:  'querytable" . $smwgIQRunningNumber . "' , columns: '" . implode(
139
					',',
140
					$colstack
141
				) . "'.split(','), hideTable: '1', type: 'Item', label: 'Item', pluralLabel: 'Items' };";
142
		}
143
		$sourcesrc = "<script type=\"text/javascript\">" . $sourcesrc . "</script>";
144
145
		// prepare facets
146
		$facetcounter = 0;
147
		if ( array_key_exists( 'facets', $this->params ) ) {
148
			$facets = explode( ',', $this->params['facets'] );
149
			$facetstack = [];
150
			$params = [ 'height' ];
151
			$facparams = [];
152
			foreach ( $params as $param ) {
153
				if ( array_key_exists( $param, $this->params ) ) {
154
					$facparams[] = 'ex:' . $param . '="' . $this->encodePropertyName( $this->params[$param] ) . '" ';
155
				}
156
			}
157
			foreach ( $facets as $facet ) {
158
				$facet = trim( $facet );
159
				if ( strtolower( $facet ) == "search" ) { // special facet (text search)
160
					$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:facetClass="TextSearch" ex:facetLabel="' . $facet . '"\'}';
161
				} else { // usual facet
162
					foreach ( $res->getPrintRequests() as $pr ) {
163
						if ( $this->encodePropertyName( $pr->getLabel() ) == $this->encodePropertyName( $facet ) ) {
164
							switch ( $pr->getTypeID() ) {
165
								case '_num':
166
									$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ex:expression=".' . $this->encodePropertyName(
167
											$facet
168
										) . '" ex:facetLabel="' . $facet . '" ex:facetClass="Slider"\'}';
169
									break;
170
								default:
171
									$facetstack[] = ' facet' . $facetcounter++ . ': { position : "right", innerHTML: \'ex:role="facet" ex:showMissing="false" ' . implode(
172
											" ",
173
											$facparams
174
										) . ' ex:expression=".' . $this->encodePropertyName(
175
											$facet
176
										) . '" ex:facetLabel="' . $facet . '"\'}';
177
							}
178
						}
179
180
					}
181
				}
182
			}
183
			$facetstring = implode( ',', $facetstack );
184
		} else {
185
			$facetstring = '';
186
		}
187
		$facetsrc = "var ex_facets = {" . $facetstring . " };";
188
189
		// prepare views
190
		$stylesrc = '';
191
		if ( array_key_exists( 'views', $this->params ) ) {
192
			$views = explode( ',', $this->params['views'] );
193
		} else {
194
			$views[] = 'tiles';
0 ignored issues
show
Coding Style Comprehensibility introduced by Jeroen De Dauw
$views was never initialized. Although not strictly required by PHP, it is generally a good practice to add $views = 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...
195
		}
196
197
		foreach ( $views as $view ) {
198
			switch ( trim( $view ) ) {
199
				case 'tabular':// table view (the columns are automatically defined by the selected properties)
200
					$thstack = [];
201
					foreach ( $res->getPrintRequests() as $pr ) {
202
						$thstack[] = "." . $this->encodePropertyName( $pr->getLabel() );
203
					}
204
					array_shift( $thstack );
205
					array_unshift( $thstack, '.label' );
206
					$stylesrc = 'var myStyler = function(table, database) {table.className=\'smwtable\';};'; // assign SMWtable CSS to Exhibit tabular view
207
					$viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Tabular\' ex:showSummary=\'false\' ex:sortAscending=\'true\' ex:tableStyler=\'myStyler\'  ex:label=\'Table\' ex:columns=\'' . implode(
0 ignored issues
show
Coding Style Comprehensibility introduced by Jeroen De Dauw
$viewstack was never initialized. Although not strictly required by PHP, it is generally a good practice to add $viewstack = 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...
208
							',',
209
							$thstack
210
						) . '\' ex:sortAscending=\'false\'';
211
					break;
212
				case 'timeline':// timeline view
213
					$timeline = true;
214
					$exparams = [
215
						'start',
216
						'end',
217
						'proxy',
218
						'colorkey' ]; // parameters expecting an Exhibit graph expression
219
					$usparams = [
220
						'timelineheight',
221
						'topbandheight',
222
						'bottombandheight',
223
						'bottombandunit',
224
						'topbandunit' ]; // parametes expecting a textual or numeric value
225
					$tlparams = [];
226
					foreach ( $exparams as $param ) {
227
						if ( array_key_exists( $param, $this->params ) ) {
228
							$tlparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
229
									$this->params[$param]
230
								) . '\' ';
231
						}
232
					}
233
					foreach ( $usparams as $param ) {
234
						if ( array_key_exists( $param, $this->params ) ) {
235
							$tlparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
236
									$this->params[$param]
237
								) . '\' ';
238
						}
239
					}
240
					if ( !array_key_exists(
241
						'start',
242
						$this->params
243
					) ) {// find out if a start and/or end date is specified
244
						$dates = [];
245
						foreach ( $res->getPrintRequests() as $pr ) {
246
							if ( $pr->getTypeID() == '_dat' ) {
247
								$dates[] = $pr;
248
								if ( sizeof( $dates ) > 2 ) {
249
									break;
250
								}
251
							}
252
						}
253
						if ( sizeof( $dates ) == 1 ) {
254
							$tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
255
						} elseif ( sizeof( $dates ) == 2 ) {
256
							$tlparams[] = 'ex:start=\'.' . $this->encodePropertyName( $dates[0]->getLabel() ) . '\' ';
257
							$tlparams[] = 'ex:end=\'.' . $this->encodePropertyName( $dates[1]->getLabel() ) . '\' ';
258
						}
259
					}
260
					$viewstack[] = 'ex:role=\'view\' ex:viewClass=\'Timeline\' ex:label=\'Timeline\' ex:showSummary=\'false\' ' . implode(
0 ignored issues
show
Bug introduced by Jeroen De Dauw
The variable $viewstack 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...
261
							" ",
262
							$tlparams
263
						);
264
					break;
265
				case 'map':// map view
266
					if ( isset( $wgGoogleMapsKey ) ) {
267
						$map = true;
268
						$exparams = [ 'latlng', 'colorkey' ];
269
						$usparams = [
270
							'type',
271
							'center',
272
							'zoom',
273
							'size',
274
							'scalecontrol',
275
							'overviewcontrol',
276
							'mapheight' ];
277
						$mapparams = [];
278
						foreach ( $exparams as $param ) {
279
							if ( array_key_exists( $param, $this->params ) ) {
280
								$mapparams[] = 'ex:' . $param . '=\'.' . $this->encodePropertyName(
281
										$this->params[$param]
282
									) . '\' ';
283
							}
284
						}
285
						foreach ( $usparams as $param ) {
286
							if ( array_key_exists( $param, $this->params ) ) {
287
								$mapparams[] = 'ex:' . $param . '=\'' . $this->encodePropertyName(
288
										$this->params[$param]
289
									) . '\' ';
290
							}
291
						}
292
						if ( !array_key_exists( 'start', $this->params ) && !array_key_exists(
293
								'end',
294
								$this->params
295
							) ) { // find out if a geographic coordinate is available
296
							foreach ( $res->getPrintRequests() as $pr ) {
297
								if ( $pr->getTypeID() == '_geo' ) {
298
									$mapparams[] = 'ex:latlng=\'.' . $this->encodePropertyName(
299
											$pr->getLabel()
300
										) . '\' ';
301
									break;
302
								}
303
							}
304
						}
305
						$viewstack[] .= 'ex:role=\'view\' ex:viewClass=\'Map\' ex:showSummary=\'false\' ex:label=\'Map\' ' . implode(
306
								" ",
307
								$mapparams
308
							);
309
					}
310
					break;
311
				default:
312
				case 'tiles':// tile view
0 ignored issues
show
Unused Code introduced by Jeroen De Dauw
case 'tiles': $sorts...$sortstring; break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
313
					$sortstring = '';
314
					if ( array_key_exists( 'sort', $this->params ) ) {
315
						$sortfields = explode( ",", $this->params['sort'] );
316
						foreach ( $sortfields as $field ) {
317
							$sortkeys[] = "." . $this->encodePropertyName( trim( $field ) );
318
						}
319
						$sortstring = 'ex:orders=\'' . implode( ",", $sortkeys ) . '\' ';
320
						if ( array_key_exists( 'order', $this->params ) ) {
321
							$sortstring .= ' ex:directions=\'' . $this->encodePropertyName(
322
									$this->params['order']
323
								) . '\'';
324
						}
325
						if ( array_key_exists( 'grouped', $this->params ) ) {
326
							$sortstring .= ' ex:grouped=\'' . $this->encodePropertyName(
327
									$this->params['grouped']
328
								) . '\'';
329
						}
330
					}
331
					$viewstack[] = 'ex:role=\'view\' ex:showSummary=\'false\' ' . $sortstring;
332
					break;
333
			}
334
		}
335
336
		$viewsrc = 'var ex_views = "' . implode( "/", $viewstack ) . '".split(\'/\');;';
337
338
		// prepare automatic lenses
339
340
		$lenscounter = 0;
341
		$linkcounter = 0;
342
		$imagecounter = 0;
343
344
		if ( array_key_exists(
345
			'lens',
346
			$this->params
347
		) ) {// a customized lens is specified via the lens parameter within the query
348
			$lenstitle = Title::newFromText( "Template:" . $this->params['lens'] );
349
			$lensarticle = new Article( $lenstitle );
350
			$lenswikitext = $lensarticle->getContent();
351
352
			if ( preg_match_all(
353
				"/[\[][\[][Ii][m][a][g][e][:][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
354
				$lenswikitext,
355
				$matches
356
			) ) {
357
				foreach ( $matches as $match ) {
358
					foreach ( $match as $value ) {
359
						$strippedvalue = trim( substr( $value, 8 ), "[[{}]]" );
360
						$lenswikitext = str_replace(
361
							$value,
362
							'<div class="inlines" id="imagecontent' . $imagecounter . '">' . $this->encodePropertyName(
363
								strtolower( str_replace( "\n", "", $strippedvalue ) )
364
							) . '</div>',
365
							$lenswikitext
366
						);
367
						$imagecounter++;
368
					}
369
				}
370
			}
371
372
			if ( preg_match_all(
373
				"/[\[][\[][{][{][{][1-9A-z\-[:space:]]*[}][}][}][\]][\]]/u",
374
				$lenswikitext,
375
				$matches
376
			) ) {
377
				foreach ( $matches as $match ) {
378
					foreach ( $match as $value ) {
379
						$strippedvalue = trim( $value, "[[{}]]" );
380
						$lenswikitext = str_replace(
381
							$value,
382
							'<div class="inlines" id="linkcontent' . $linkcounter . '">' . $this->encodePropertyName(
383
								strtolower( str_replace( "\n", "", $strippedvalue ) )
384
							) . '</div>',
385
							$lenswikitext
386
						);
387
						$linkcounter++;
388
					}
389
				}
390
			}
391
392
			if ( preg_match_all( "/[{][{][{][1-9A-z\:\|\/\=\-[:space:]]*[}][}][}]/u", $lenswikitext, $matches ) ) {
393
				foreach ( $matches as $match ) {
394
					foreach ( $match as $value ) {
395
						$strippedvalue = trim( $value, "{}" );
396
						$lenswikitext = str_replace(
397
							$value,
398
							'<div class="inlines" id="lenscontent' . $lenscounter . '">' . $this->encodePropertyName(
399
								strtolower( str_replace( "\n", "", $strippedvalue ) )
400
							) . '</div>',
401
							$lenswikitext
402
						);
403
						$lenscounter++;
404
					}
405
				}
406
			}
407
408
			$parser = MediaWikiServices::getInstance()->getParser();
409
			$lenshtml = $parser->internalParse(
410
				$lenswikitext
411
			);// $parser->parse($lenswikitext, $lenstitle, new ParserOptions(), true, true)->getText();
412
413
			$lenssrc = "var ex_lens = '" . str_replace(
414
					"\n",
415
					"",
416
					$lenshtml
417
				) . "';ex_lenscounter =" . $lenscounter . ";ex_linkcounter=" . $linkcounter . ";ex_imagecounter=" . $imagecounter . ";";
418
		} else {// generic lens (creates links to further content (property-pages, pages about values)
419
			foreach ( $res->getPrintRequests() as $pr ) {
420
				if ( $remote ) {
421
					$wikiurl = str_replace( "$1", "", $extlinkpattern );
0 ignored issues
show
Bug introduced by Jeroen De Dauw
The variable $extlinkpattern 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...
422
				} else {
423
					$wikiurl = $wgScriptPath . "/index.php?title=";
424
				}
425
				if ( $pr->getTypeID() == '_wpg' ) {
426
					$prefix = '';
427
					if ( $pr->getLabel() == 'Category' ) {
428
						$prefix = "Category:";
429
					}
430
					$lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
0 ignored issues
show
Coding Style Comprehensibility introduced by Jeroen De Dauw
$lensstack was never initialized. Although not strictly required by PHP, it is generally a good practice to add $lensstack = 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...
431
							$pr->getLabel()
432
						) . '"><td width="20%">' . $pr->getText(
433
							0,
434
							$this->mLinker
435
						) . '</td><td width="80%" ex:content=".' . $this->encodePropertyName(
436
							$pr->getLabel()
437
						) . '"><a ex:href-subcontent="' . $wikiurl . $prefix . '{{urlencval(value)}}"><div ex:content="value" class="name"></div></a></td></tr>';
438
				} else {
439
					$lensstack[] = '<tr ex:if-exists=".' . $this->encodePropertyName(
0 ignored issues
show
Bug introduced by Jeroen De Dauw
The variable $lensstack 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...
440
							$pr->getLabel()
441
						) . '"><td width="20%">' . $pr->getText(
442
							0,
443
							$this->mLinker
444
						) . '</td><td width="80%"><div ex:content=".' . $this->encodePropertyName(
445
							$pr->getLabel()
446
						) . '" class="name"></div></td></tr>';
447
				}
448
			}
449
			array_shift( $lensstack );
450
			$lenssrc = 'var ex_lens = \'<table width=100% cellpadding=3><tr><th class="head" align=left bgcolor="#DDDDDD"><a ex:href-subcontent="' . $wikiurl . $this->determineNamespace(
0 ignored issues
show
Bug introduced by Jeroen De Dauw
The variable $wikiurl 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...
451
					clone $res
452
				) . '{{urlenc(.label)}}" class="linkhead"><div ex:content=".label" class="name"></div></a></th></tr></table><table width="100%" cellpadding=3>' . implode(
453
					"",
454
					$lensstack
455
				) . '</table>\'; ex_lenscounter = 0; ex_linkcounter=0; ex_imagecounter=0;';
456
		}
457
458
		if ( $remote ) {
459
			$varremote = 'true';
460
		} else {
461
			$varremote = 'false';
462
		}
463
464
		// Handling special formats like date
465
		$formatssrc = 'var formats =\'\'';
466
		if ( array_key_exists( 'date', $this->params ) ) {
467
			$formatssrc = 'var formats = \'ex:formats="date { mode:' . $this->params['date'] . '; show:date }"\';';
468
		}
469
470
		// create a URL pointing to the corresponding JSON feed
471
		$label = '';
472
		$JSONlink = $res->getQueryLink( $label );
473
		if ( $this->getSearchLabel( SMW_OUTPUT_WIKI ) != '' ) { // used as a file name
474
			$link->setParameter( $this->getSearchLabel( SMW_OUTPUT_WIKI ), 'searchlabel' );
0 ignored issues
show
Bug introduced by Jeroen De Dauw
The variable $link 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...
475
		}
476
		if ( array_key_exists( 'limit', $this->params ) ) {
477
			$JSONlink->setParameter( htmlspecialchars( $this->params['limit'] ), 'limit' );
478
		}
479
		$JSONlink->setParameter( 'json', 'format' );
480
		$stringtoedit = explode( "|", $JSONlink->getText( $outputmode, $this->mLinker ) );
481
		$stringtoedit = substr( $stringtoedit[0], 3 );
482
		$JSONlinksrc = "var JSONlink = '" . $stringtoedit . "';";
483
484
		// create script header with variables containing the Exhibit markup
485
		$headervars = "<script type='text/javascript'>\n\t\t\t" . $facetsrc . "\n\t\t\t" . $viewsrc . "\n\t\t\t" . $lenssrc . "\n\t\t\t" . $stylesrc . "\n\t\t\t" . $formatssrc . "\n\t\t\t" . $JSONlinksrc . "\n\t\t\t var remote=" . $varremote . ";</script>";
486
487
		// To run Exhibit some links to the scripts of the API need to be included in the header
488
489
		$ExhibitScriptSrc1 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/exhibit/exhibit-api.js?autoCreate=false&safe=true&bundle=false';
490
		if ( $timeline ) {
491
			$ExhibitScriptSrc1 .= '&views=timeline';
492
		}
493
		if ( $map ) {
494
			$ExhibitScriptSrc1 .= '&gmapkey=' . $wgGoogleMapsKey;
495
		}
496
		$ExhibitScriptSrc1 .= '"></script>';
497
		$ExhibitScriptSrc2 = '<script type="text/javascript" src="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.js"></script>';
498
		$CSSSrc = '<link rel="stylesheet" type="text/css" href="' . $srfgScriptPath . '/Exhibit/SRF_Exhibit.css"></link>';
499
500
		SMWOutputs::requireHeadItem( 'CSS', $CSSSrc ); // include CSS
501
		SMWOutputs::requireHeadItem( 'EXHIBIT1', $ExhibitScriptSrc1 ); // include Exhibit API
502
		SMWOutputs::requireHeadItem(
503
			'EXHIBIT2',
504
			$ExhibitScriptSrc2
505
		); // includes javascript overwriting the Exhibit start-up functions
506
		SMWOutputs::requireHeadItem( 'SOURCES' . $smwgIQRunningNumber, $sourcesrc );// include sources variable
507
		SMWOutputs::requireHeadItem( 'VIEWSFACETS', $headervars );// include views and facets variable
508
509
		if ( !$remote ) {
510
511
			// print input table
512
			// print header
513
			$result = "<table style=\"display:none\" class=\"smwtable\" id=\"querytable" . $smwgIQRunningNumber . "\">\n";
514
			if ( $this->mShowHeaders ) { // building headers
515
				$result .= "\t<tr>\n";
516
				foreach ( $res->getPrintRequests() as $pr ) {
517
					if ( $pr->getText( $outputmode, $this->getLinker( 0 ) ) == '' ) {
518
						$headerlabel = "Name";
519
					} else {
520
						$headerlabel = $pr->getText( $outputmode, $this->getLinker( 0 ) );
521
					}
522
					$result .= "\t\t<th>" . $headerlabel . "</th>\n";
523
				}
524
				$result .= "\t</tr>\n";
525
			}
526
527
			// print all result rows
528
			while ( $row = $res->getNext() ) {
529
				$result .= "\t<tr>\n";
530
				foreach ( $row as $field ) {
531
					$result .= "\t\t<td>";
532
					$textstack = [];
533
					while ( ( $object = $field->getNextDataValue() ) !== false ) {
534
						switch ( $object->getTypeID() ) {
535
							case '_wpg':
536
								$textstack[] = $object->getLongText( $outputmode, $this->getLinker( 0 ) );
537
								break;
538
							case '_geo':
539
								$c = $object->getDBKeys();
540
								$textstack[] = $c[0] . "," . $c[1];
541
								break;
542
							case '_num':
543
								if ( method_exists( $object, 'getValueKey' ) ) {
544
									$textstack[] = $object->getValueKey( $outputmode, $this->getLinker( 0 ) );
545
								} else {
546
									$textstack[] = $object->getNumericValue( $outputmode, $this->getLinker( 0 ) );
547
								}
548
								break;
549
							case '_dat':
550
								$textstack[] = $object->getYear() . "-" . str_pad(
551
										$object->getMonth(),
552
										2,
553
										'0',
554
										STR_PAD_LEFT
555
									) . "-" . str_pad(
556
										$object->getDay(),
557
										2,
558
										'0',
559
										STR_PAD_LEFT
560
									) . " " . $object->getTimeString();
561
								break;
562
							case '_ema':
563
								$textstack[] = $object->getShortWikiText( $this->getLinker( 0 ) );
564
								break;
565
							case '_tel':
566
							case '_anu':
567
							case '_uri':
568
								$textstack[] = $object->getWikiValue();
569
								break;
570
							case '__sin':
571
								$tmp = $object->getShortText( $outputmode, null );
572
								if ( strpos( $tmp, ":" ) ) {
573
									$tmp = explode( ":", $tmp, 2 );
574
									$tmp = $tmp[1];
575
								}
576
								$textstack[] = $tmp;
577
								break;
578
							case '_txt':
579
							case '_cod':
580
							case '_str':
581
								$textstack[] = $object->getWikiValue();
582
								break;
583
							default:
584
								$textstack[] = $object->getLongHTMLText( $this->getLinker( 0 ) );
585
						}
586
					}
587
588
					if ( $textstack != null ) {
589
						$result .= implode( ';', $textstack ) . "</td>\n";
590
					} else {
591
						$result .= "</td>\n";
592
					}
593
				}
594
				$result .= "\t</tr>\n";
595
			}
596
			$result .= "</table>\n";
597
		}
598
599
		if ( SRFExhibit::$exhibitRunningNumber == 0 ) {
600
			$result .= "<div id=\"exhibitLocation\"></div>";
0 ignored issues
show
Bug introduced by Jeroen De Dauw
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...
601
		} // print placeholder (just print it one time)
602
		$this->isHTML = ( $outputmode == SMW_OUTPUT_HTML ); // yes, our code can be viewed as HTML if requested, no more parsing needed
603
		SRFExhibit::$exhibitRunningNumber++;
604
		return $result;
605
	}
606
607
	/**
608
	 * @see SMWResultPrinter::getParamDefinitions
609
	 *
610
	 * @since 1.8
611
	 *
612
	 * @param $definitions array of IParamDefinition
613
	 *
614
	 * @return array of IParamDefinition|array
615
	 */
616
	public function getParamDefinitions( array $definitions ) {
617
		$params = parent::getParamDefinitions( $definitions );
618
619
		$params[] = [
620
			'name' => 'views',
621
			'message' => 'srf_paramdesc_views',
622
			'islist' => true,
623
			'values' => [ 'tiles', 'tabular', 'timeline', 'maps' ] ];
624
		$params[] = [ 'name' => 'facets', 'message' => 'srf_paramdesc_facets' ];
625
		$params[] = [ 'name' => 'lens', 'message' => 'srf_paramdesc_lens' ];
626
627
		return $params;
628
	}
629
630
}
631