Completed
Push — master ( 76f9d5...d59f0b )
by Jeroen De
9s
created

SemanticMaps/src/queryprinters/SM_MapPrinter.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use Maps\Elements\Location;
4
use Maps\Element;
5
use Maps\Elements\BaseElement;
6
use ParamProcessor\ParamDefinition;
7
8
/**
9
 * Query printer for maps. Is invoked via SMMapper.
10
 * Can be overridden per service to have custom output.
11
 *
12
 * @ingroup SemanticMaps
13
 *
14
 * @licence GNU GPL v2+
15
 * @author Jeroen De Dauw < [email protected] >
16
 * @author Peter Grassberger < [email protected] >
17
 */
18
class SMMapPrinter extends SMW\ResultPrinter {
19
20
	private static $services = [];
21
22
	/**
23
	 * @since 3.4
24
	 * FIXME: this is a temporary hack that should be replaced when SMW allows for dependency
25
	 * injection in query printers.
26
	 *
27
	 * @param MapsMappingService $service
28
	 */
29
	public static function registerService( MapsMappingService $service ) {
30
		self::$services[$service->getName()] = $service;
31
	}
32
33
	public static function registerDefaultService( $serviceName ) {
34
		self::$services['map'] = self::$services[$serviceName];
35
	}
36
	
37
	/**
38
	 * @var MapsMappingService
39
	 */
40
	private $service;
41
	
42
	/**
43
	 * @var string|boolean
44
	 */
45
	private $fatalErrorMsg = false;
46
	
47
	/**
48
	 * @param string $format
49
	 * @param bool $inline
50
	 */
51
	public function __construct( $format, $inline = true ) {
52
		$this->service = self::$services[$format];
53
		
54
		parent::__construct( $format, $inline );
55
	}
56
57
	/**
58
	 * Returns an array containing the parameter info.
59
	 * 
60
	 * @return array
61
	 */
62
	private function getParameterInfo() {
63
		global $smgQPShowTitle, $smgQPTemplate, $smgQPHideNamespace;
64
		
65
		$params = ParamDefinition::getCleanDefinitions( MapsMapper::getCommonParameters() );
0 ignored issues
show
\MapsMapper::getCommonParameters() is of type array<string,array<strin...efault\":\"false\"}>"}>, but the function expects a array<integer,object<Par...ssor\IParamDefinition>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
66
67
		$this->service->addParameterInfo( $params );
68
69
		$params['staticlocations'] = [
70
			'type' => 'mapslocation',
71
			'aliases' => [ 'locations', 'points' ],
72
			'default' => [],
73
			'islist' => true,
74
			'delimiter' => ';',
75
			'message' => 'semanticmaps-par-staticlocations',
76
		];
77
78
		$params['showtitle'] = [
79
			'type' => 'boolean',
80
			'aliases' => 'show title',
81
			'default' => $smgQPShowTitle,
82
		];
83
84
		$params['hidenamespace'] = [
85
			'type' => 'boolean',
86
			'aliases' => 'hide namespace',
87
			'default' => $smgQPHideNamespace,
88
		];
89
90
		$params['template'] = [
91
			'default' => $smgQPTemplate,
92
		];
93
94
		$params['userparam'] = [
95
			'default' => '',
96
		];
97
98
		$params['activeicon'] =  [
99
			'type' => 'string',
100
			'default' => '',
101
		];
102
103
		$params['pagelabel'] =  [
104
			'type' => 'boolean',
105
			'default' => false,
106
		];
107
108
		$params['ajaxcoordproperty'] = array(
109
			'default' => '',
110
		);
111
112
		$params['ajaxquery'] = array(
113
			'default' => '',
114
			'type' => 'string'
115
		);
116
117
		// Messages:
118
		// semanticmaps-par-staticlocations, semanticmaps-par-showtitle, semanticmaps-par-hidenamespace,
119
		// semanticmaps-par-template, semanticmaps-par-userparam, semanticmaps-par-activeicon,
120
		// semanticmaps-par-pagelabel, semanticmaps-par-ajaxcoordproperty semanticmaps-par-ajaxquery
121
		foreach ( $params as $name => &$data ) {
122
			if ( is_array( $data ) && !array_key_exists( 'message', $data ) ) {
123
				$data['message'] = 'semanticmaps-par-' . $name;
124
			}
125
		}
126
127
		return $params;
128
	}
129
	
130
	/**
131
	 * Builds up and returns the HTML for the map, with the queried coordinate data on it.
132
	 *
133
	 * @param SMWQueryResult $res
134
	 * @param $outputmode
135
	 * 
136
	 * @return array or string
137
	 */
138
	public final function getResultText( SMWQueryResult $res, $outputmode ) {
139
		if ( $this->fatalErrorMsg !== false ) {
140
			return $this->fatalErrorMsg;
141
		}
142
143
		/**
144
		 * @var Parser $wgParser
145
		 */
146
		global $wgParser;
147
148
		if ( $GLOBALS['egMapsEnableCategory'] && $wgParser->getOutput() !== null ) {
149
			$wgParser->addTrackingCategory( 'maps-tracking-category' );
150
		}
151
152
		$params = $this->params;
153
154
		$queryHandler = new SMQueryHandler( $res, $outputmode );
155
		$queryHandler->setLinkStyle($params['link']);
156
		$queryHandler->setHeaderStyle($params['headers']);
157
		$queryHandler->setShowSubject( $params['showtitle'] );
158
		$queryHandler->setTemplate( $params['template'] );
159
		$queryHandler->setUserParam( $params['userparam'] );
160
		$queryHandler->setHideNamespace( $params['hidenamespace'] );
161
		$queryHandler->setActiveIcon( $params['activeicon'] );
162
163
		$this->handleMarkerData( $params, $queryHandler );
164
		$locationAmount = count( $params['locations'] );
165
166
		$params['ajaxquery'] = urlencode( $params['ajaxquery'] );
167
168
		if ( $locationAmount > 0 ) {
169
			// We can only take care of the zoom defaulting here,
170
			// as not all locations are available in whats passed to Validator.
171
			if ( $this->fullParams['zoom']->wasSetToDefault() && $locationAmount > 1 ) {
172
				$params['zoom'] = false;
173
			}
174
175
			$mapName = $this->service->getMapId();
176
177
			SMWOutputs::requireHeadItem(
178
				$mapName,
179
				$this->service->getDependencyHtml() .
180
				$configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() )
181
			);
182
183
			foreach ( $this->service->getResourceModules() as $resourceModule ) {
184
				SMWOutputs::requireResource( $resourceModule );
185
			}
186
187
			if ( array_key_exists( 'source', $params ) ) {
188
				unset( $params['source'] );
189
			}
190
191
			return $this->getMapHTML( $params, $wgParser, $mapName );
192
		}
193
		else {
194
			return $params['default'];
195
		}
196
	}
197
198
	/**
199
	 * Returns the HTML to display the map.
200
	 *
201
	 * @param array $params
202
	 * @param Parser $parser
203
	 * @param string $mapName
204
	 *
205
	 * @return string
206
	 */
207
	private function getMapHTML( array $params, Parser $parser, $mapName ) {
208
		return Html::rawElement(
209
			'div',
210
			[
211
				'id' => $mapName,
212
				'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;",
213
				'class' => 'maps-map maps-' . $this->service->getName()
214
			],
215
			wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() .
216
				Html::element(
217
					'div',
218
					[ 'style' => 'display:none', 'class' => 'mapdata' ],
219
					FormatJson::encode( $this->getJSONObject( $params, $parser ) )
220
				)
221
		);
222
	}
223
224
	/**
225
	 * Returns a PHP object to encode to JSON with the map data.
226
	 *
227
	 * @param array $params
228
	 * @param Parser $parser
229
	 *
230
	 * @return mixed
231
	 */
232
	private function getJSONObject( array $params, Parser $parser ) {
233
		return $params;
234
	}
235
	
236
	/**
237
	 * Converts the data in the coordinates parameter to JSON-ready objects.
238
	 * These get stored in the locations parameter, and the coordinates on gets deleted.
239
	 * 
240
	 * @param array &$params
241
	 * @param SMQueryHandler $queryHandler
242
	 */
243
	private function handleMarkerData( array &$params, SMQueryHandler $queryHandler ) {
244
		if ( is_object( $params['centre'] ) ) {
245
			$params['centre'] = $params['centre']->getJSONObject();
246
		}
247
248
		$iconUrl = MapsMapper::getFileUrl( $params['icon'] );
249
		$visitedIconUrl = MapsMapper::getFileUrl( $params['visitedicon'] );
250
251
		$params['locations'] = $this->getJsonForStaticLocations(
252
			$params['staticlocations'],
253
			$params,
254
			$iconUrl,
255
			$visitedIconUrl
256
		);
257
258
		unset( $params['staticlocations'] );
259
260
		$this->addShapeData( $queryHandler->getShapes(), $params, $iconUrl, $visitedIconUrl );
261
262
		if ( $params['format'] === 'openlayers' ) {
263
			$params['layers'] = MapsDisplayMapRenderer::evilOpenLayersHack( $params['layers'] );
264
		}
265
	}
266
267
	private function getJsonForStaticLocations( array $staticLocations, array $params, $iconUrl, $visitedIconUrl ) {
268
		/**
269
		 * @var Parser $wgParser
270
		 */
271
		global $wgParser;
272
273
		$parser = version_compare( $GLOBALS['wgVersion'], '1.18', '<' ) ? $wgParser : clone $wgParser;
274
275
		$locationsJson = [];
276
277
		foreach ( $staticLocations as $location ) {
278
			$locationsJson[] = $this->getJsonForStaticLocation(
279
				$location,
280
				$params,
281
				$iconUrl,
282
				$visitedIconUrl,
283
				$parser
284
			);
285
		}
286
287
		return $locationsJson;
288
	}
289
290
	private function getJsonForStaticLocation( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parser ) {
291
		$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
292
293
		$jsonObj['title'] = $parser->parse( $jsonObj['title'], $parser->getTitle(), new ParserOptions() )->getText();
294
		$jsonObj['text'] = $parser->parse( $jsonObj['text'], $parser->getTitle(), new ParserOptions() )->getText();
295
296
		$hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== '';
297
		$jsonObj['text'] = ( $hasTitleAndtext ? '<b>' . $jsonObj['title'] . '</b><hr />' : $jsonObj['title'] ) . $jsonObj['text'];
298
		$jsonObj['title'] = strip_tags( $jsonObj['title'] );
299
300
		if ( $params['pagelabel'] ) {
301
			$jsonObj['inlineLabel'] = Linker::link( Title::newFromText( $jsonObj['title'] ) );
302
		}
303
304
		return $jsonObj;
305
	}
306
307
	/**
308
	 * @param Element[] $queryShapes
309
	 * @param array $params
310
	 * @param string $iconUrl
311
	 * @param string $visitedIconUrl
312
	 */
313
	private function addShapeData( array $queryShapes, array &$params, $iconUrl, $visitedIconUrl ) {
314
		$params['locations'] = array_merge(
315
			$params['locations'],
316
			$this->getJsonForLocations(
317
				$queryShapes['locations'],
318
				$params,
319
				$iconUrl,
320
				$visitedIconUrl
321
			)
322
		);
323
324
		$params['lines'] = $this->getElementJsonArray( $queryShapes['lines'], $params );
325
		$params['polygons'] = $this->getElementJsonArray( $queryShapes['polygons'], $params );
326
	}
327
328
	/**
329
	 * @param Location[] $locations
330
	 * @param array $params
331
	 * @param string $iconUrl
332
	 * @param string $visitedIconUrl
333
	 *
334
	 * @return array
335
	 */
336
	private function getJsonForLocations( array $locations, array $params, $iconUrl, $visitedIconUrl ) {
337
		$locationsJson = [];
338
339
		foreach ( $locations as $location ) {
340
			$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
341
342
			$jsonObj['title'] = strip_tags( $jsonObj['title'] );
343
344
			$locationsJson[] = $jsonObj;
345
		}
346
347
		return $locationsJson;
348
	}
349
350
	/**
351
	 * @param BaseElement[] $elements
352
	 * @param array $params
353
	 *
354
	 * @return array
355
	 */
356
	private function getElementJsonArray( array $elements, array $params ) {
357
		$elementsJson = [];
358
359
		foreach ( $elements as $element ) {
360
			$jsonObj = $element->getJSONObject( $params['title'], $params['label'] );
361
			$elementsJson[] = $jsonObj;
362
		}
363
364
		return $elementsJson;
365
	}
366
367
	/**
368
	 * Returns the internationalized name of the mapping service.
369
	 * 
370
	 * @return string
371
	 */
372
	public final function getName() {
373
		return wfMessage( 'maps_' . $this->service->getName() )->text();
374
	}
375
	
376
	/**
377
	 * Returns a list of parameter information, for usage by Special:Ask and others.
378
	 * 
379
	 * @return array
380
	 */
381
    public function getParameters() {
382
        $params = parent::getParameters();
383
        $paramInfo = $this->getParameterInfo();
384
        
385
        // Do not display this as an option, as the format already determines it
386
        // TODO: this can probably be done cleaner with some changes in Maps
387
        unset( $paramInfo['mappingservice'] );
388
        
389
        $params = array_merge( $params, $paramInfo );
390
391
		return $params;
392
    }
393
}
394