Completed
Push — master ( 8491da...d644dd )
by Jeroen De
9s
created

MapsDisplayMapRenderer::getLocationJson()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 0
cts 11
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 2
crap 12
1
<?php
2
3
use Maps\Element;
4
use Maps\Elements\Location;
5
use Maps\LocationParser;
6
use ValueParsers\ParserOptions as ValueParserOptions;
7
8
/**
9
 * Class handling the #display_map rendering.
10
 *
11
 * @licence GNU GPL v2+
12
 * @author Jeroen De Dauw < [email protected] >
13
 * @author Kim Eik
14
 */
15
class MapsDisplayMapRenderer {
16
17
	private $service;
18
19
	/**
20
	 * @var LocationParser
21
	 */
22
	private $locationParser;
23
24
	public function __construct( MapsMappingService $service ) {
25
		$this->service = $service;
26
	}
27
28
	/**
29
	 * Handles the request from the parser hook by doing the work that's common for all
30
	 * mapping services, calling the specific methods and finally returning the resulting output.
31
	 *
32
	 * @param array $params
33
	 * @param Parser $parser
34
	 *
35
	 * @return string
36
	 */
37
	public final function renderMap( array $params, Parser $parser ) {
38
		$this->initializeLocationParser( $params );
39
40
		$this->handleMarkerData( $params, $parser );
41
42
		$mapName = $this->service->getMapId();
43
44
		$output = $this->getMapHTML( $params, $mapName );
45
46
		$configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() );
47
48
		$this->service->addHtmlDependencies(
49
			self::getLayerDependencies( $params['mappingservice'], $params )
50
		);
51
52
		$this->service->addDependencies( $parser );
53
		$parser->getOutput()->addHeadItem( $configVars );
54
55
		return $output;
56
	}
57
58
	private function initializeLocationParser( array $params ) {
59
		$this->locationParser = new LocationParser( new ValueParserOptions( [
60
			'geoService' => $params['geoservice']
61
		] ) );
62
	}
63
64
	/**
65
	 * Returns the HTML to display the map.
66
	 *
67
	 * @param array $params
68
	 * @param string $mapName
69
	 *
70
	 * @return string
71
	 */
72
	protected function getMapHTML( array $params, $mapName ) {
73
		return Html::rawElement(
74
			'div',
75
			[
76
				'id' => $mapName,
77
				'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;",
78
				'class' => 'maps-map maps-' . $this->service->getName()
79
			],
80
			wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() .
81
			Html::element(
82
				'div',
83
				[ 'style' => 'display:none', 'class' => 'mapdata' ],
84
				FormatJson::encode( $params )
85
			)
86
		);
87
	}
88
89
	/**
90
	 * Converts the data in the coordinates parameter to JSON-ready objects.
91
	 * These get stored in the locations parameter, and the coordinates on gets deleted.
92
	 */
93
	private function handleMarkerData( array &$params, Parser $parser ) {
94
		$params['centre'] = $this->getCenter( $params['centre'] );
95
96
		$parserClone = clone $parser;
97
98
		if ( is_object( $params['wmsoverlay'] ) ) {
99
			$params['wmsoverlay'] = $params['wmsoverlay']->getJSONObject();
100
		}
101
102
		$params['locations'] = $this->getLocationJson( $params, $parserClone );
103
104
		unset( $params['coordinates'] );
105
106
		$this->handleShapeData( $params, $parserClone );
107
108
		if ( $params['mappingservice'] === 'openlayers' ) {
109
			$params['layers'] = self::evilOpenLayersHack( $params['layers'] );
0 ignored issues
show
Deprecated Code introduced by
The method MapsDisplayMapRenderer::evilOpenLayersHack() has been deprecated.

This method has been deprecated.

Loading history...
110
		}
111
	}
112
113
	private function getCenter( $coordinatesOrAddress ) {
114
		if ( $coordinatesOrAddress === false ) {
115
			return false;
116
		}
117
118
		try {
119
			// FIXME: a Location makes no sense here, since the non-coordinate data is not used
120
			$location = $this->locationParser->stringParse( $coordinatesOrAddress );
121
		}
122
		catch ( \Exception $ex ) {
123
			// TODO: somehow report this to the user
124
			return false;
125
		}
126
127
		return $location->getJSONObject();
128
	}
129
130
	private function getLocationJson( array $params, $parserClone ) {
131
		$iconUrl = MapsMapper::getFileUrl( $params['icon'] );
0 ignored issues
show
Deprecated Code introduced by
The method MapsMapper::getFileUrl() has been deprecated.

This method has been deprecated.

Loading history...
132
		$visitedIconUrl = MapsMapper::getFileUrl( $params['visitedicon'] );
0 ignored issues
show
Deprecated Code introduced by
The method MapsMapper::getFileUrl() has been deprecated.

This method has been deprecated.

Loading history...
133
134
		$locationJsonObjects = [];
135
136
		foreach ( $params['coordinates'] as $coordinatesOrAddress ) {
137
			try {
138
				$location = $this->locationParser->stringParse( $coordinatesOrAddress );
139
			}
140
			catch ( \Exception $ex ) {
141
				// TODO: somehow report this to the user
142
				continue;
143
			}
144
145
			$locationJsonObjects[] = $this->getLocationJsonObject( $location, $params, $iconUrl, $visitedIconUrl, $parserClone );
146
		}
147
148
		return $locationJsonObjects;
149
	}
150
151
	private function getLocationJsonObject( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parserClone ) {
152
		$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
153
154
		$jsonObj['title'] = $parserClone->parse( $jsonObj['title'], $parserClone->getTitle(), new ParserOptions() )->getText();
155
		$jsonObj['text'] = $parserClone->parse( $jsonObj['text'], $parserClone->getTitle(), new ParserOptions() )->getText();
156
157
		if ( isset( $jsonObj['inlineLabel'] ) ) {
158
			$jsonObj['inlineLabel'] = strip_tags($parserClone->parse( $jsonObj['inlineLabel'], $parserClone->getTitle(), new ParserOptions() )->getText(),'<a><img>');
159
		}
160
161
		$hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== '';
162
		$jsonObj['text'] = ( $hasTitleAndtext ? '<b>' . $jsonObj['title'] . '</b><hr />' : $jsonObj['title'] ) . $jsonObj['text'];
163
		$jsonObj['title'] = strip_tags( $jsonObj['title'] );
164
165
		return $jsonObj;
166
	}
167
168
	private function handleShapeData( array &$params, Parser $parserClone ) {
169
		$textContainers = [
170
			&$params['lines'] ,
171
			&$params['polygons'] ,
172
			&$params['circles'] ,
173
			&$params['rectangles'],
174
			&$params['imageoverlays'], // FIXME: this is Google Maps specific!!
175
		];
176
177
		foreach ( $textContainers as &$textContainer ) {
178
			if ( is_array( $textContainer ) ) {
179
				foreach ( $textContainer as &$obj ) {
180
					if ( $obj instanceof Element ) {
181
						$obj = $obj->getArrayValue();
182
					}
183
184
					$obj['title'] = $parserClone->parse( $obj['title'] , $parserClone->getTitle() , new ParserOptions() )->getText();
185
					$obj['text'] = $parserClone->parse( $obj['text'] , $parserClone->getTitle() , new ParserOptions() )->getText();
186
187
					$hasTitleAndtext = $obj['title'] !== '' && $obj['text'] !== '';
188
					$obj['text'] = ( $hasTitleAndtext ? '<b>' . $obj['title'] . '</b><hr />' : $obj['title'] ) . $obj['text'];
189
					$obj['title'] = strip_tags( $obj['title'] );
190
				}
191
			}
192
		}
193
	}
194
195
	/**
196
	 * FIXME
197
	 *
198
	 * Temporary hack until the mapping service handling gets a proper refactor
199
	 * This kind of JS construction is also rather evil and should not be done at this point
200
	 *
201
	 * @since 3.0
202
	 * @deprecated
203
	 *
204
	 * @param string[] $layers
205
	 *
206
	 * @return string[]
207
	 */
208
	public static function evilOpenLayersHack( $layers ) {
209
		global $egMapsOLLayerGroups, $egMapsOLAvailableLayers;
210
211
		$layerDefs = [];
212
		$layerNames = [];
213
214
		foreach ( $layers as $layerOrGroup ) {
215
			$lcLayerOrGroup = strtolower( $layerOrGroup );
216
217
			// Layer groups. Loop over all items and add them if not present yet:
218
			if ( array_key_exists( $lcLayerOrGroup, $egMapsOLLayerGroups ) ) {
219
				foreach ( $egMapsOLLayerGroups[$lcLayerOrGroup] as $layerName ) {
220
					if ( !in_array( $layerName, $layerNames ) ) {
221
						if ( is_array( $egMapsOLAvailableLayers[$layerName] ) ) {
222
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName][0];
223
						}
224
						else {
225
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName];
226
						}
227
						$layerNames[] = $layerName;
228
					}
229
				}
230
			}
231
			// Single layers. Add them if not present yet:
232
			elseif ( array_key_exists( $lcLayerOrGroup, $egMapsOLAvailableLayers ) ) {
233
				if ( !in_array( $lcLayerOrGroup, $layerNames ) ) {
234
					if ( is_array( $egMapsOLAvailableLayers[$lcLayerOrGroup] ) ) {
235
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup][0];
236
					}
237
					else {
238
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup];
239
					}
240
241
					$layerNames[] = $lcLayerOrGroup;
242
				}
243
			}
244
		}
245
		return $layerDefs;
246
	}
247
248
	public static function getLayerDependencies( $service, $params ) {
249
		global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers,
250
			   $egMapsLeafletLayerDependencies, $egMapsLeafletAvailableLayers,
251
			   $egMapsLeafletLayersApiKeys;
252
253
		$layerDependencies = [];
254
255
		if ( $service === 'leaflet' ) {
256
			$layerName = $params['layer'];
257
			if ( array_key_exists( $layerName, $egMapsLeafletAvailableLayers )
258
					&& $egMapsLeafletAvailableLayers[$layerName]
259
					&& array_key_exists( $layerName, $egMapsLeafletLayersApiKeys )
260
					&& array_key_exists( $layerName, $egMapsLeafletLayerDependencies ) ) {
261
				$layerDependencies[] = '<script src="' . $egMapsLeafletLayerDependencies[$layerName] .
262
					$egMapsLeafletLayersApiKeys[$layerName] . '"></script>';
263
			}
264
		} else if ( $service === 'openlayers' ) {
265
			$layerNames = $params['layers'];
266
			foreach ( $layerNames as $layerName ) {
267
				if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php
268
						&& is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array...
269
						&& count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element...
270
						&& array_key_exists( $egMapsOLAvailableLayers[$layerName][1], $egMapsOLLayerDependencies ) ) { //...that is a dependency.
271
					$layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]];
272
				}
273
			}
274
275
		}
276
277
		return array_unique( $layerDependencies );
278
	}
279
280
}
281