Completed
Push — qp ( bd0b37 )
by Jeroen De
03:09
created

QueryHandler::setTitle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Maps\SemanticMW\ResultPrinters;
4
5
use Html;
6
use Maps\Elements\Location;
7
use Maps\MapsFunctions;
8
use SMWDataValue;
9
use SMWPrintRequest;
10
use SMWQueryResult;
11
use SMWResultArray;
12
use SMWWikiPageValue;
13
use Title;
14
15
/**
16
 * Class for handling geographical SMW queries.
17
 *
18
 * @licence GNU GPL v2+
19
 * @author Jeroen De Dauw < [email protected] >
20
 */
21
class QueryHandler {
22
23
	/**
24
	 * The global icon.
25
	 * @var string
26
	 */
27
	public $icon = '';
28
29
	/**
30
	 * The global text.
31
	 * @var string
32
	 */
33
	public $text = '';
34
35
	/**
36
	 * The global title.
37
	 * @var string
38
	 */
39
	public $title = '';
40
41
	/**
42
	 * Make a separate link to the title or not?
43
	 * @var boolean
44
	 */
45
	public $titleLinkSeparate = false;
46
47
	private $queryResult;
48
49
	private $outputMode;
50
51
	/**
52
	 * @var array
53
	 */
54
	private $geoShapes = [
55
		'lines' => [],
56
		'locations' => [],
57
		'polygons' => []
58
	];
59
60
	/**
61
	 * The template to use for the text, or false if there is none.
62
	 * @var string|boolean false
63
	 */
64
	private $template = false;
65
66
	/**
67
	 * Should link targets be made absolute (instead of relative)?
68
	 * @var boolean
69
	 */
70
	private $linkAbsolute;
71
72
	/**
73
	 * The text used for the link to the page (if it's created). $1 will be replaced by the page name.
74
	 * @var string
75
	 */
76
	private $pageLinkText = '$1';
77
78
	/**
79
	 * A separator to use between the subject and properties in the text field.
80
	 * @var string
81
	 */
82
	private $subjectSeparator = '<hr />';
83
84
	/**
85
	 * Show the subject in the text or not?
86
	 * @var boolean
87
	 */
88
	private $showSubject = true;
89
90
	/**
91
	 * Hide the namespace or not.
92
	 * @var boolean
93
	 */
94
	private $hideNamespace = false;
95
96
	/**
97
	 * Defines which article names in the result are hyperlinked, all normally is the default
98
	 * none, subject, all
99
	 */
100
	private $linkStyle = 'all';
101
102
	/*
103
	 * Show headers (with links), show headers (just text) or hide them. show is default
104
	 * show, plain, hide
105
	 */
106
	private $headerStyle = 'show';
107
108
	/**
109
	 * Marker icon to show when marker equals active page
110
	 * @var string|null
111
	 */
112
	private $activeIcon = null;
113
114
	/**
115
	 * @var string
116
	 */
117
	private $userParam = '';
118
119
	public function __construct( SMWQueryResult $queryResult, int $outputMode, bool $linkAbsolute = false ) {
120
		$this->queryResult = $queryResult;
121
		$this->outputMode = $outputMode;
122
		$this->linkAbsolute = $linkAbsolute;
123
	}
124
125
	public function setTemplate( string $template ) {
126
		$this->template = $template === '' ? false : $template;
127
	}
128
129
	public function setUserParam( string $userParam ) {
130
		$this->userParam = $userParam;
131
	}
132
133
	/**
134
	 * Sets the global icon.
135
	 */
136
	public function setIcon( string $icon ) {
137
		$this->icon = $icon;
138
	}
139
140
	/**
141
	 * Sets the global title.
142
	 */
143
	public function setTitle( string $title ) {
144
		$this->title = $title;
145
	}
146
147
	/**
148
	 * Sets the global text.
149
	 */
150
	public function setText( string $text ) {
151
		$this->text = $text;
152
	}
153
154
	public function setSubjectSeparator( string $subjectSeparator ) {
155
		$this->subjectSeparator = $subjectSeparator;
156
	}
157
158
	public function setShowSubject( bool $showSubject ) {
159
		$this->showSubject = $showSubject;
160
	}
161
162
	/**
163
	 * Sets the text for the link to the page when separate from the title.
164
	 */
165
	public function setPageLinkText( string $text ) {
166
		$this->pageLinkText = $text;
167
	}
168
169
	public function setLinkStyle( string $link ) {
170
		$this->linkStyle = $link;
171
	}
172
173
	public function setHeaderStyle( string $headers ) {
174
		$this->headerStyle = $headers;
175
	}
176
177
	/**
178
	 * @return array
179
	 */
180
	public function getShapes() {
181
		$this->findShapes();
182
		return $this->geoShapes;
183
	}
184
185
	/**
186
	 * @since 2.0
187
	 */
188
	private function findShapes() {
189
		while ( ( $row = $this->queryResult->getNext() ) !== false ) {
190
			$this->handleResultRow( $row );
191
		}
192
	}
193
194
	/**
195
	 * Returns the locations found in the provided result row.
196
	 *
197
	 * @param SMWResultArray[] $row
198
	 */
199
	private function handleResultRow( array $row ) {
200
		$locations = [];
201
		$properties = [];
202
203
		$title = '';
204
		$text = '';
205
206
		// Loop through all fields of the record.
207
		foreach ( $row as $i => $resultArray ) {
208
			$printRequest = $resultArray->getPrintRequest();
209
210
			// Loop through all the parts of the field value.
211
			while ( ( $dataValue = $resultArray->getNextDataValue() ) !== false ) {
212
				if ( $dataValue->getTypeID() == '_wpg' && $i == 0 ) {
213
					$title = $dataValue->getLongText( $this->outputMode, null );
214
					$text = $this->getResultSubjectText( $dataValue );
215
				} else {
216
					if ( $dataValue->getTypeID() == '_str' && $i == 0 ) {
217
						$title = $dataValue->getLongText( $this->outputMode, null );
218
						$text = $dataValue->getLongText( $this->outputMode, smwfGetLinker() );
219
					} else {
220
						if ( strpos( $dataValue->getTypeID(), '_rec' ) !== false ) {
221
							foreach ( $dataValue->getDataItems() as $dataItem ) {
222
								if ( $dataItem instanceof \SMWDIGeoCoord ) {
0 ignored issues
show
Bug introduced by
The class SMWDIGeoCoord does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
223
									$locations[] = Location::newFromLatLon(
224
										$dataItem->getLatitude(),
225
										$dataItem->getLongitude()
226
									);
227
								}
228
							}
229
						} else {
230
							if ( $dataValue->getTypeID() != '_geo' && $i != 0 && !$this->isHeadersHide() ) {
231
								$properties[] = $this->handleResultProperty( $dataValue, $printRequest );
232
							} else {
233
								if ( $printRequest->getMode(
234
									) == SMWPrintRequest::PRINT_PROP && $printRequest->getTypeID(
235
									) == '_geo' || $dataValue->getTypeID() == '_geo' ) {
236
									$dataItem = $dataValue->getDataItem();
237
238
									$locations[] = Location::newFromLatLon(
239
										$dataItem->getLatitude(),
240
										$dataItem->getLongitude()
241
									);
242
								}
243
							}
244
						}
245
					}
246
				}
247
			}
248
		}
249
250
		if ( $properties !== [] && $text !== '' ) {
251
			$text .= $this->subjectSeparator;
252
		}
253
254
		$icon = $this->getLocationIcon( $row );
255
256
		$this->geoShapes['locations'] = array_merge(
257
			$this->geoShapes['locations'],
258
			$this->buildLocationsList(
259
				$locations,
260
				$text,
261
				$icon,
262
				$properties,
263
				Title::newFromText( $title )
264
			)
265
		);
266
	}
267
268
	/**
269
	 * Handles a SMWWikiPageValue subject value.
270
	 * Gets the plain text title and creates the HTML text with headers and the like.
271
	 *
272
	 * @param SMWWikiPageValue $object
273
	 *
274
	 * @return string
275
	 */
276
	private function getResultSubjectText( SMWWikiPageValue $object ): string {
277
		if ( !$this->showSubject ) {
278
			return '';
279
		}
280
281
		if ( $this->showArticleLink() ) {
282
			if ( !$this->titleLinkSeparate && $this->linkAbsolute ) {
283
				$text = Html::element(
284
					'a',
285
					[ 'href' => $object->getTitle()->getFullUrl() ],
286
					$this->hideNamespace ? $object->getText() : $object->getTitle()->getFullText()
287
				);
288
			} else {
289
				if ( $this->hideNamespace ) {
290
					$text = $object->getShortHTMLText( smwfGetLinker() );
291
				} else {
292
					$text = $object->getLongHTMLText( smwfGetLinker() );
293
				}
294
			}
295
		} else {
296
			$text = $this->hideNamespace ? $object->getText() : $object->getTitle()->getFullText();
297
		}
298
299
		$text = '<b>' . $text . '</b>';
300
301
		if ( !$this->titleLinkSeparate ) {
302
			return $text;
303
		}
304
305
		$txt = $object->getTitle()->getText();
306
307
		if ( $this->pageLinkText !== '' ) {
308
			$txt = str_replace( '$1', $txt, $this->pageLinkText );
309
		}
310
311
		return $text . Html::element(
312
			'a',
313
			[ 'href' => $object->getTitle()->getFullUrl() ],
314
			$txt
315
		);
316
	}
317
318
	private function showArticleLink() {
319
		return $this->linkStyle !== 'none';
320
	}
321
322
	private function isHeadersHide() {
323
		return $this->headerStyle === 'hide';
324
	}
325
326
	/**
327
	 * Handles a single property (SMWPrintRequest) to be displayed for a record (SMWDataValue).
328
	 */
329
	private function handleResultProperty( SMWDataValue $object, SMWPrintRequest $printRequest ): string {
330
		if ( $this->hasTemplate() ) {
331
			if ( $object instanceof SMWWikiPageValue ) {
0 ignored issues
show
Bug introduced by
The class SMWWikiPageValue does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
332
				return $object->getTitle()->getPrefixedText();
333
			}
334
335
			return $object->getLongText( SMW_OUTPUT_WIKI, null );
336
		}
337
338
		$propertyName = $this->getPropertyName( $printRequest );
339
		return $propertyName . ( $propertyName === '' ? '' : ': ' ) . $this->getPropertyValue( $object );
340
	}
341
342
	private function getPropertyName( SMWPrintRequest $printRequest ): string {
343
		if ( $this->linkAbsolute ) {
344
			$titleText = $printRequest->getText( null );
345
			$t = Title::newFromText( $titleText, SMW_NS_PROPERTY );
346
347
			if ( $this->isHeadersShow() && $t instanceof Title && $t->exists() ) {
0 ignored issues
show
Bug introduced by
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
348
				return  Html::element(
349
					'a',
350
					[ 'href' => $t->getFullUrl() ],
351
					$printRequest->getHTMLText( null )
352
				);
353
			}
354
355
			return $titleText;
356
		}
357
358
		if ( $this->isHeadersShow() ) {
359
			return $printRequest->getHTMLText( smwfGetLinker() );
360
		}
361
362
		if ( $this->isHeadersPlain() ) {
363
			return $printRequest->getText( null );
364
		}
365
366
		return '';
367
	}
368
369
	private function getPropertyValue( SMWDataValue $object ): string {
370
		if ( $this->linkAbsolute ) {
371
			if ( $this->hasPage( $object ) ) {
372
				return Html::element(
373
					'a',
374
					[
375
						'href' => Title::newFromText(
376
							$object->getLongText( $this->outputMode, null ),
377
							NS_MAIN
378
						)->getFullUrl()
379
					],
380
					$object->getLongText( $this->outputMode, null )
381
				);
382
			}
383
384
			return $object->getLongText( $this->outputMode, null );
385
		}
386
387
		return $object->getLongText( $this->outputMode, smwfGetLinker() );;
388
	}
389
390
	private function hasPage( SMWDataValue $object ): bool {
391
		$hasPage = $object->getTypeID() == '_wpg';
392
393
		if ( $hasPage ) {
394
			$t = Title::newFromText( $object->getLongText( $this->outputMode, null ), NS_MAIN );
395
			$hasPage = $t !== null && $t->exists();
396
		}
397
398
		return $hasPage;
399
	}
400
401
	private function hasTemplate() {
402
		return is_string( $this->template );
403
	}
404
405
	private function isHeadersShow() {
406
		return $this->headerStyle === 'show';
407
	}
408
409
	private function isHeadersPlain() {
410
		return $this->headerStyle === 'plain';
411
	}
412
413
	/**
414
	 * Get the icon for a row.
415
	 *
416
	 * @param array $row
417
	 *
418
	 * @return string
419
	 */
420
	private function getLocationIcon( array $row ) {
421
		$icon = '';
422
		$legendLabels = [];
423
424
		//Check for activeicon parameter
425
426
		if ( $this->shouldGetActiveIconUrlFor( $row[0]->getResultSubject()->getTitle() ) ) {
427
			$icon = MapsFunctions::getFileUrl( $this->activeIcon );
0 ignored issues
show
Deprecated Code introduced by
The method Maps\MapsFunctions::getFileUrl() has been deprecated.

This method has been deprecated.

Loading history...
428
		}
429
430
		// Look for display_options field, which can be set by Semantic Compound Queries
431
		// the location of this field changed in SMW 1.5
432
		$display_location = method_exists( $row[0], 'getResultSubject' ) ? $row[0]->getResultSubject() : $row[0];
433
434
		if ( property_exists( $display_location, 'display_options' ) && is_array(
435
				$display_location->display_options
436
			) ) {
437
			$display_options = $display_location->display_options;
438
			if ( array_key_exists( 'icon', $display_options ) ) {
439
				$icon = $display_options['icon'];
440
441
				// This is somewhat of a hack - if a legend label has been set, we're getting it for every point, instead of just once per icon
442
				if ( array_key_exists( 'legend label', $display_options ) ) {
443
444
					$legend_label = $display_options['legend label'];
445
446
					if ( !array_key_exists( $icon, $legendLabels ) ) {
447
						$legendLabels[$icon] = $legend_label;
448
					}
449
				}
450
			}
451
		} // Icon can be set even for regular, non-compound queries If it is, though, we have to translate the name into a URL here
452
		elseif ( $this->icon !== '' ) {
453
			$icon = MapsFunctions::getFileUrl( $this->icon );
0 ignored issues
show
Deprecated Code introduced by
The method Maps\MapsFunctions::getFileUrl() has been deprecated.

This method has been deprecated.

Loading history...
454
		}
455
456
		return $icon;
457
	}
458
459
	private function shouldGetActiveIconUrlFor( Title $title ) {
460
		global $wgTitle;
461
462
		return isset( $this->activeIcon ) && is_object( $wgTitle )
463
			&& $wgTitle->equals( $title );
464
	}
465
466
	/**
467
	 * Builds a set of locations with the provided title, text and icon.
468
	 *
469
	 * @param Location[] $locations
470
	 * @param string $text
471
	 * @param string $icon
472
	 * @param array $properties
473
	 * @param Title|null $title
474
	 *
475
	 * @return Location[]
476
	 */
477
	private function buildLocationsList( array $locations, $text, $icon, array $properties, Title $title = null ) {
478
		if ( !$this->hasTemplate() ) {
479
			$text .= implode( '<br />', $properties );
480
		}
481
482
		$titleOutput = $this->getTitleOutput( $title );
483
484
		foreach ( $locations as &$location ) {
485
			if ( $this->hasTemplate() ) {
486
				$segments = array_merge(
487
					[
488
						$this->template,
489
						'title=' . $titleOutput,
490
						'latitude=' . $location->getCoordinates()->getLatitude(),
491
						'longitude=' . $location->getCoordinates()->getLongitude(),
492
						'userparam=' . $this->userParam
493
					],
494
					$properties
495
				);
496
497
				$text .= $this->getParser()->recursiveTagParseFully(
498
					'{{' . implode( '|', $segments ) . '}}'
499
				);
500
			}
501
502
			$location->setTitle( $titleOutput );
503
			$location->setText( $text );
504
			$location->setIcon( trim( $icon ) );
505
		}
506
507
		return $locations;
508
	}
509
510
	private function getTitleOutput( Title $title = null ) {
511
		if ( $title === null ) {
512
			return '';
513
		}
514
515
		return $this->hideNamespace ? $title->getText() : $title->getFullText();
516
	}
517
518
	/**
519
	 * @return \Parser
520
	 */
521
	private function getParser() {
522
		return $GLOBALS['wgParser'];
523
	}
524
525
	/**
526
	 * @return boolean
527
	 */
528
	public function getHideNamespace() {
529
		return $this->hideNamespace;
530
	}
531
532
	/**
533
	 * @param boolean $hideNamespace
534
	 */
535
	public function setHideNamespace( $hideNamespace ) {
536
		$this->hideNamespace = $hideNamespace;
537
	}
538
539
	/**
540
	 * @return string
541
	 */
542
	public function getActiveIcon() {
543
		return $this->activeIcon;
544
	}
545
546
	/**
547
	 * @param string $activeIcon
548
	 */
549
	public function setActiveIcon( $activeIcon ) {
550
		$this->activeIcon = $activeIcon;
551
	}
552
553
}
554