Completed
Push — master ( e2ac37...21f028 )
by Jeroen De
03:38
created

DisplayMapRenderer::getLayerDependencies()   C

Complexity

Conditions 13
Paths 3

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 23.816

Importance

Changes 0
Metric Value
dl 0
loc 38
ccs 15
cts 25
cp 0.6
rs 6.6166
c 0
b 0
f 0
cc 13
nc 3
nop 2
crap 23.816

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Maps\MediaWiki\ParserHooks;
4
5
use FormatJson;
6
use Html;
7
use Maps\DataAccess\MediaWikiFileUrlFinder;
8
use Maps\Elements\Location;
9
use Maps\MappingService;
10
use Maps\Presentation\ElementJsonSerializer;
11
use Maps\Presentation\WikitextParser;
12
use Maps\Presentation\WikitextParsers\LocationParser;
13
use Parser;
14
15
/**
16
 * Class handling the #display_map rendering.
17
 *
18
 * @licence GNU GPL v2+
19
 * @author Jeroen De Dauw < [email protected] >
20
 * @author Kim Eik
21
 */
22
class DisplayMapRenderer {
23
24
	public $service;
25
26
	/**
27
	 * @var LocationParser
28
	 */
29
	private $locationParser;
30
31
	/**
32
	 * @var MediaWikiFileUrlFinder
33
	 */
34
	private $fileUrlFinder;
35
36
	/**
37
	 * @var WikitextParser
38
	 */
39
	private $wikitextParser;
40
	/**
41
	 * @var ElementJsonSerializer
42
	 */
43
	private $elementSerializer;
44
45 20
	public function __construct( MappingService $service = null ) {
46 20
		$this->service = $service;
47 20
	}
48
49
	/**
50
	 * Handles the request from the parser hook by doing the work that's common for all
51
	 * mapping services, calling the specific methods and finally returning the resulting output.
52
	 *
53
	 * @param array $params
54
	 * @param Parser $parser
55
	 *
56
	 * @return string
57
	 */
58 20
	public final function renderMap( array $params, Parser $parser ) {
59 20
		$factory = \Maps\MapsFactory::newDefault();
60
61 20
		$this->locationParser = $factory->newLocationParser();
62 20
		$this->fileUrlFinder = $factory->getFileUrlFinder();
63
64 20
		$this->wikitextParser = new WikitextParser( clone $parser );
65 20
		$this->elementSerializer = new ElementJsonSerializer( $this->wikitextParser );
66
67 20
		$this->handleMarkerData( $params );
68
69 20
		$output = $this->getMapHTML(
70 20
			$params,
71 20
			$this->service->getMapId()
72
		);
73
74 20
		$this->service->addHtmlDependencies(
75 20
			self::getLayerDependencies( $params['mappingservice'], $params )
76
		);
77
78 20
		$this->service->addDependencies( $parser->getOutput() );
79
80 20
		return $output;
81
	}
82
83
	/**
84
	 * Converts the data in the coordinates parameter to JSON-ready objects.
85
	 * These get stored in the locations parameter, and the coordinates on gets deleted.
86
	 */
87 20
	private function handleMarkerData( array &$params ) {
88 20
		$params['centre'] = $this->getCenter( $params['centre'] );
89
90 20
		if ( is_object( $params['wmsoverlay'] ) ) {
91
			$params['wmsoverlay'] = $params['wmsoverlay']->getJSONObject();
92
		}
93
94 20
		$params['locations'] = $this->getLocationJson( $params );
95
96 20
		unset( $params['coordinates'] );
97
98 20
		$this->handleShapeData( $params );
99
100 20
		if ( $params['mappingservice'] === 'openlayers' ) {
101
			$params['layers'] = self::evilOpenLayersHack( $params['layers'] );
0 ignored issues
show
Deprecated Code introduced by
The method Maps\MediaWiki\ParserHoo...r::evilOpenLayersHack() has been deprecated.

This method has been deprecated.

Loading history...
102
		}
103 20
	}
104
105 20
	private function getCenter( $coordinatesOrAddress ) {
106 20
		if ( $coordinatesOrAddress === false ) {
107 20
			return false;
108
		}
109
110
		try {
111
			// FIXME: a Location makes no sense here, since the non-coordinate data is not used
112
			$location = $this->locationParser->parse( $coordinatesOrAddress );
113
		}
114
		catch ( \Exception $ex ) {
115
			// TODO: somehow report this to the user
116
			return false;
117
		}
118
119
		return $location->getJSONObject();
120
	}
121
122 20
	private function getLocationJson( array $params ) {
123 20
		$iconUrl = $this->fileUrlFinder->getUrlForFileName( $params['icon'] );
124 20
		$visitedIconUrl = $this->fileUrlFinder->getUrlForFileName( $params['visitedicon'] );
125
126 20
		$locationJsonObjects = [];
127
128 20
		foreach ( $params['coordinates'] as $coordinatesOrAddress ) {
129
			try {
130 15
				$location = $this->locationParser->parse( $coordinatesOrAddress );
131
			}
132 1
			catch ( \Exception $ex ) {
133
				// TODO: somehow report this to the user
134 1
				continue;
135
			}
136
137 14
			$locationJsonObjects[] = $this->getLocationJsonObject(
138 14
				$location,
139 14
				$params,
140 14
				$iconUrl,
141 14
				$visitedIconUrl
142
			);
143
		}
144
145 20
		return $locationJsonObjects;
146
	}
147
148 14
	private function getLocationJsonObject( Location $location, array $params, $iconUrl, $visitedIconUrl ) {
149 14
		$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
150
151 14
		$this->elementSerializer->titleAndText( $jsonObj );
152
153 14
		if ( isset( $jsonObj['inlineLabel'] ) ) {
154 1
			$jsonObj['inlineLabel'] = strip_tags(
155 1
				$this->wikitextParser->wikitextToHtml( $jsonObj['inlineLabel'] ),
156 1
				'<a><img>'
157
			);
158
		}
159
160 14
		return $jsonObj;
161
	}
162
163 20
	private function handleShapeData( array &$params ) {
164
		$textContainers = [
165 20
			&$params['lines'],
166 20
			&$params['polygons'],
167 20
			&$params['circles'],
168 20
			&$params['rectangles'],
169 20
			&$params['imageoverlays'], // FIXME: this is Google Maps specific!!
170
		];
171
172 20
		foreach ( $textContainers as &$textContainer ) {
173 20
			if ( is_array( $textContainer ) ) {
174 20
				foreach ( $textContainer as &$obj ) {
175 20
					$obj = $this->elementSerializer->wikitextToHtml( $obj );
176
				}
177
			}
178
		}
179 20
	}
180
181
	/**
182
	 * FIXME
183
	 *
184
	 * Temporary hack until the mapping service handling gets a proper refactor
185
	 * This kind of JS construction is also rather evil and should not be done at this point
186
	 *
187
	 * @since 3.0
188
	 * @deprecated
189
	 *
190
	 * @param string[] $layers
191
	 *
192
	 * @return string[]
193
	 */
194
	public static function evilOpenLayersHack( $layers ) {
195
		global $egMapsOLLayerGroups, $egMapsOLAvailableLayers;
196
197
		$layerDefs = [];
198
		$layerNames = [];
199
200
		foreach ( $layers as $layerOrGroup ) {
201
			$lcLayerOrGroup = strtolower( $layerOrGroup );
202
203
			// Layer groups. Loop over all items and add them if not present yet:
204
			if ( array_key_exists( $lcLayerOrGroup, $egMapsOLLayerGroups ) ) {
205
				foreach ( $egMapsOLLayerGroups[$lcLayerOrGroup] as $layerName ) {
206
					if ( !in_array( $layerName, $layerNames ) ) {
207
						if ( is_array( $egMapsOLAvailableLayers[$layerName] ) ) {
208
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName][0];
209
						} else {
210
							$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$layerName];
211
						}
212
						$layerNames[] = $layerName;
213
					}
214
				}
215
			} // Single layers. Add them if not present yet:
216
			elseif ( array_key_exists( $lcLayerOrGroup, $egMapsOLAvailableLayers ) ) {
217
				if ( !in_array( $lcLayerOrGroup, $layerNames ) ) {
218
					if ( is_array( $egMapsOLAvailableLayers[$lcLayerOrGroup] ) ) {
219
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup][0];
220
					} else {
221
						$layerDefs[] = 'new ' . $egMapsOLAvailableLayers[$lcLayerOrGroup];
222
					}
223
224
					$layerNames[] = $lcLayerOrGroup;
225
				}
226
			}
227
		}
228
		return $layerDefs;
229
	}
230
231
	/**
232
	 * Returns the HTML to display the map.
233
	 *
234
	 * @param array $params
235
	 * @param string $mapName
236
	 *
237
	 * @return string
238
	 */
239 20
	protected function getMapHTML( array $params, $mapName ) {
240 20
		return Html::rawElement(
241 20
			'div',
242
			[
243 20
				'id' => $mapName,
244 20
				'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;",
245 20
				'class' => 'maps-map maps-' . $this->service->getName()
246
			],
247 20
			wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() .
248 20
			Html::element(
249 20
				'div',
250 20
				[ 'style' => 'display:none', 'class' => 'mapdata' ],
251 20
				FormatJson::encode( $params )
252
			)
253
		);
254
	}
255
256 20
	public static function getLayerDependencies( $service, $params ) {
257 20
		global $egMapsOLLayerDependencies, $egMapsOLAvailableLayers,
258 20
			   $egMapsLeafletLayerDependencies, $egMapsLeafletAvailableLayers,
259 20
			   $egMapsLeafletLayersApiKeys;
260
261 20
		$layerDependencies = [];
262
263 20
		if ( $service === 'leaflet' ) {
264 13
			$layerNames = $params['layers'];
265 13
			foreach ( $layerNames as $layerName ) {
266 13
				if ( array_key_exists( $layerName, $egMapsLeafletAvailableLayers )
267 13
					&& $egMapsLeafletAvailableLayers[$layerName]
268 13
					&& array_key_exists( $layerName, $egMapsLeafletLayersApiKeys )
269 13
					&& array_key_exists( $layerName, $egMapsLeafletLayerDependencies ) ) {
270
					$layerDependencies[] = '<script src="' . $egMapsLeafletLayerDependencies[$layerName] .
271 13
						$egMapsLeafletLayersApiKeys[$layerName] . '"></script>';
272
				}
273
			}
274
		} else {
275 7
			if ( $service === 'openlayers' ) {
276
				$layerNames = $params['layers'];
277
				foreach ( $layerNames as $layerName ) {
278
					if ( array_key_exists( $layerName, $egMapsOLAvailableLayers ) // The layer must be defined in php
279
						&& is_array( $egMapsOLAvailableLayers[$layerName] ) // The layer must be an array...
280
						&& count( $egMapsOLAvailableLayers[$layerName] ) > 1 // ...with a second element...
281
						&& array_key_exists(
282
							$egMapsOLAvailableLayers[$layerName][1],
283
							$egMapsOLLayerDependencies
284
						) ) { //...that is a dependency.
285
						$layerDependencies[] = $egMapsOLLayerDependencies[$egMapsOLAvailableLayers[$layerName][1]];
286
					}
287
				}
288
289
			}
290
		}
291
292 20
		return array_unique( $layerDependencies );
293
	}
294
295
}
296