Completed
Push — master ( 264305...76f9d5 )
by Jeroen De
03:12 queued 03:06
created

MapsDisplayMapRenderer::getLocationJsonObject()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 0
cts 11
cp 0
rs 9.2
cc 4
eloc 10
nc 8
nop 5
crap 20
1
<?php
2
3
use Maps\Element;
4
use Maps\Elements\Location;
5
use ValueParsers\ParserOptions as ValueParserOptions;
6
7
/**
8
 * Class handling the #display_map rendering.
9
 *
10
 * @licence GNU GPL v2+
11
 * @author Jeroen De Dauw < [email protected] >
12
 * @author Kim Eik
13
 */
14
class MapsDisplayMapRenderer {
15
16
	private $service;
17
18
	public function __construct( MapsMappingService $service ) {
19
		$this->service = $service;
20
	}
21
22
	/**
23
	 * Handles the request from the parser hook by doing the work that's common for all
24
	 * mapping services, calling the specific methods and finally returning the resulting output.
25
	 *
26
	 * @param array $params
27
	 * @param Parser $parser
28
	 *
29
	 * @return string
30
	 */
31
	public final function renderMap( array $params, Parser $parser ) {
32
		$this->handleMarkerData( $params, $parser );
33
34
		$mapName = $this->service->getMapId();
35
36
		$output = $this->getMapHTML( $params, $mapName );
37
38
		$configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() );
39
40
		$this->service->addHtmlDependencies(
41
			self::getLayerDependencies( $params['mappingservice'], $params )
42
		);
43
44
		$this->service->addDependencies( $parser );
45
		$parser->getOutput()->addHeadItem( $configVars );
46
47
		return $output;
48
	}
49
50
	/**
51
	 * Returns the HTML to display the map.
52
	 *
53
	 * @param array $params
54
	 * @param string $mapName
55
	 *
56
	 * @return string
57
	 */
58
	protected function getMapHTML( array $params, $mapName ) {
59
		return Html::rawElement(
60
			'div',
61
			[
62
				'id' => $mapName,
63
				'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;",
64
				'class' => 'maps-map maps-' . $this->service->getName()
65
			],
66
			wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() .
67
			Html::element(
68
				'div',
69
				[ 'style' => 'display:none', 'class' => 'mapdata' ],
70
				FormatJson::encode( $params )
71
			)
72
		);
73
	}
74
75
	/**
76
	 * Converts the data in the coordinates parameter to JSON-ready objects.
77
	 * These get stored in the locations parameter, and the coordinates on gets deleted.
78
	 */
79
	private function handleMarkerData( array &$params, Parser $parser ) {
80
		if ( is_object( $params['centre'] ) ) {
81
			$params['centre'] = $params['centre']->getJSONObject();
82
		}
83
84
		$parserClone = clone $parser;
85
86
		if ( is_object( $params['wmsoverlay'] ) ) {
87
			$params['wmsoverlay'] = $params['wmsoverlay']->getJSONObject();
88
		}
89
90
		$params['locations'] = $this->getLocationJson( $params, $parserClone );
91
92
		unset( $params['coordinates'] );
93
94
		$this->handleShapeData( $params, $parserClone );
95
96
		if ( $params['mappingservice'] === 'openlayers' ) {
97
			$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...
98
		}
99
	}
100
101
	private function getLocationJson( array $params, $parserClone ) {
102
		$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...
103
		$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...
104
105
		$parser = new \Maps\LocationParser( new ValueParserOptions( [
106
			'geoService' => $params['geoservice']
107
		] ) );
108
109
		$locationJsonObjects = [];
110
111
		foreach ( $params['coordinates'] as $coordinatesOrAddress ) {
112
			try {
113
				$location = $parser->stringParse( $coordinatesOrAddress );
114
			}
115
			catch ( \Exception $ex ) {
116
				// TODO: somehow report this to the user
117
				continue;
118
			}
119
120
			$locationJsonObjects[] = $this->getLocationJsonObject( $location, $params, $iconUrl, $visitedIconUrl, $parserClone );
121
		}
122
123
		return $locationJsonObjects;
124
	}
125
126
	private function getLocationJsonObject( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parserClone ) {
127
		$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
128
129
		$jsonObj['title'] = $parserClone->parse( $jsonObj['title'], $parserClone->getTitle(), new ParserOptions() )->getText();
130
		$jsonObj['text'] = $parserClone->parse( $jsonObj['text'], $parserClone->getTitle(), new ParserOptions() )->getText();
131
132
		if ( isset( $jsonObj['inlineLabel'] ) ) {
133
			$jsonObj['inlineLabel'] = strip_tags($parserClone->parse( $jsonObj['inlineLabel'], $parserClone->getTitle(), new ParserOptions() )->getText(),'<a><img>');
134
		}
135
136
		$hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== '';
137
		$jsonObj['text'] = ( $hasTitleAndtext ? '<b>' . $jsonObj['title'] . '</b><hr />' : $jsonObj['title'] ) . $jsonObj['text'];
138
		$jsonObj['title'] = strip_tags( $jsonObj['title'] );
139
140
		return $jsonObj;
141
	}
142
143
	private function handleShapeData( array &$params, Parser $parserClone ) {
144
		$textContainers = [
145
			&$params['lines'] ,
146
			&$params['polygons'] ,
147
			&$params['circles'] ,
148
			&$params['rectangles'],
149
			&$params['imageoverlays'], // FIXME: this is Google Maps specific!!
150
		];
151
152
		foreach ( $textContainers as &$textContainer ) {
153
			if ( is_array( $textContainer ) ) {
154
				foreach ( $textContainer as &$obj ) {
155
					if ( $obj instanceof Element ) {
156
						$obj = $obj->getArrayValue();
157
					}
158
159
					$obj['title'] = $parserClone->parse( $obj['title'] , $parserClone->getTitle() , new ParserOptions() )->getText();
160
					$obj['text'] = $parserClone->parse( $obj['text'] , $parserClone->getTitle() , new ParserOptions() )->getText();
161
162
					$hasTitleAndtext = $obj['title'] !== '' && $obj['text'] !== '';
163
					$obj['text'] = ( $hasTitleAndtext ? '<b>' . $obj['title'] . '</b><hr />' : $obj['title'] ) . $obj['text'];
164
					$obj['title'] = strip_tags( $obj['title'] );
165
				}
166
			}
167
		}
168
	}
169
170
	/**
171
	 * FIXME
172
	 *
173
	 * Temporary hack until the mapping service handling gets a proper refactor
174
	 * This kind of JS construction is also rather evil and should not be done at this point
175
	 *
176
	 * @since 3.0
177
	 * @deprecated
178
	 *
179
	 * @param string[] $layers
180
	 *
181
	 * @return string[]
182
	 */
183
	public static function evilOpenLayersHack( $layers ) {
184
		global $egMapsOLLayerGroups, $egMapsOLAvailableLayers;
185
186
		$layerDefs = [];
187
		$layerNames = [];
188
189
		foreach ( $layers as $layerOrGroup ) {
190
			$lcLayerOrGroup = strtolower( $layerOrGroup );
191
192
			// Layer groups. Loop over all items and add them if not present yet:
193
			if ( array_key_exists( $lcLayerOrGroup, $egMapsOLLayerGroups ) ) {
194
				foreach ( $egMapsOLLayerGroups[$lcLayerOrGroup] as $layerName ) {
195
					if ( !in_array( $layerName, $layerNames ) ) {
196
						if ( is_array( $egMapsOLAvailableLayers[$layerName] ) ) {
197
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName][0];
198
						}
199
						else {
200
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName];
201
						}
202
						$layerNames[] = $layerName;
203
					}
204
				}
205
			}
206
			// Single layers. Add them if not present yet:
207
			elseif ( array_key_exists( $lcLayerOrGroup, $egMapsOLAvailableLayers ) ) {
208
				if ( !in_array( $lcLayerOrGroup, $layerNames ) ) {
209
					if ( is_array( $egMapsOLAvailableLayers[$lcLayerOrGroup] ) ) {
210
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup][0];
211
					}
212
					else {
213
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup];
214
					}
215
216
					$layerNames[] = $lcLayerOrGroup;
217
				}
218
			}
219
		}
220
		return $layerDefs;
221
	}
222
223
	public static function getLayerDependencies( $service, $params ) {
224
		global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers,
225
			   $egMapsLeafletLayerDependencies, $egMapsLeafletAvailableLayers,
226
			   $egMapsLeafletLayersApiKeys;
227
228
		$layerDependencies = [];
229
230
		if ( $service === 'leaflet' ) {
231
			$layerName = $params['layer'];
232
			if ( array_key_exists( $layerName, $egMapsLeafletAvailableLayers )
233
					&& $egMapsLeafletAvailableLayers[$layerName]
234
					&& array_key_exists( $layerName, $egMapsLeafletLayersApiKeys )
235
					&& array_key_exists( $layerName, $egMapsLeafletLayerDependencies ) ) {
236
				$layerDependencies[] = '<script src="' . $egMapsLeafletLayerDependencies[$layerName] .
237
					$egMapsLeafletLayersApiKeys[$layerName] . '"></script>';
238
			}
239
		} else if ( $service === 'openlayers' ) {
240
			$layerNames = $params['layers'];
241
			foreach ( $layerNames as $layerName ) {
242
				if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php
243
						&& is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array...
244
						&& count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element...
245
						&& array_key_exists( $egMapsOLAvailableLayers[$layerName][1], $egMapsOLLayerDependencies ) ) { //...that is a dependency.
246
					$layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]];
247
				}
248
			}
249
250
		}
251
252
		return array_unique( $layerDependencies );
253
	}
254
255
}
256