Completed
Push — master ( f67785...2177d9 )
by mw
07:32
created

SMMapPrinter::getParameterInfo()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 60
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20
Metric Value
dl 0
loc 60
ccs 0
cts 34
cp 0
rs 8.9618
cc 4
eloc 34
nc 3
nop 0
crap 20

How to fix   Long Method   

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
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
 * @file SM_MapPrinter.php
13
 * @ingroup SemanticMaps
14
 *
15
 * @licence GNU GPL v2+
16
 * @author Jeroen De Dauw < [email protected] >
17
 */
18
class SMMapPrinter extends SMW\ResultPrinter {
19
	
20
	/**
21
	 * @since 0.6
22
	 * 
23
	 * @var iMappingService
24
	 */
25
	protected $service;	
26
	
27
	/**
28
	 * @since 1.0
29
	 * 
30
	 * @var string|boolean false
31
	 */
32
	protected $fatalErrorMsg = false;
33
	
34
	/**
35
	 * Constructor.
36
	 * 
37
	 * @param $format String
38
	 * @param $inline
39
	 */
40 2
	public function __construct( $format, $inline = true ) {
41 2
		$this->service = MapsMappingServices::getValidServiceInstance( $format, 'qp' );
42
		
43 2
		parent::__construct( $format, $inline );
44 2
	}
45
46
	/**
47
	 * Returns an array containing the parameter info.
48
	 * 
49
	 * @since 1.0
50
	 * 
51
	 * @return array
52
	 */
53
	protected function getParameterInfo() {
54
		global $smgQPShowTitle, $smgQPTemplate, $smgQPHideNamespace;
55
		
56
		$params = ParamDefinition::getCleanDefinitions( MapsMapper::getCommonParameters() );
0 ignored issues
show
Documentation introduced by
\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...
Deprecated Code introduced by
The method MapsMapper::getCommonParameters() has been deprecated.

This method has been deprecated.

Loading history...
57
58
		$this->service->addParameterInfo( $params );
59
60
		$params['staticlocations'] = array(
61
			'type' => 'mapslocation',
62
			'aliases' => array( 'locations', 'points' ),
63
			'default' => array(),
64
			'islist' => true,
65
			'delimiter' => ';',
66
			'message' => 'semanticmaps-par-staticlocations',
67
		);
68
69
		$params['showtitle'] = array(
70
			'type' => 'boolean',
71
			'aliases' => 'show title',
72
			'default' => $smgQPShowTitle,
73
		);
74
75
		$params['hidenamespace'] = array(
76
			'type' => 'boolean',
77
			'aliases' => 'hide namespace',
78
			'default' => $smgQPHideNamespace,
79
		);
80
81
		$params['template'] = array(
82
			'default' => $smgQPTemplate,
83
		);
84
85
		$params['userparam'] = array(
86
			'default' => '',
87
		);
88
89
		$params['activeicon'] = array (
90
			'type' => 'string',
91
			'default' => '',
92
		);
93
94
		$params['pagelabel'] = array (
95
			'type' => 'boolean',
96
			'default' => false,
97
		);
98
99
		// Messages:
100
		// semanticmaps-par-staticlocations, semanticmaps-par-forceshow, semanticmaps-par-showtitle,
101
		// semanticmaps-par-hidenamespace, semanticmaps-par-centre, semanticmaps-par-template,
102
		// semanticmaps-par-geocodecontrol, semanticmaps-par-activeicon semanticmaps-par-markerlabel
103
		foreach ( $params as $name => &$data ) {
104
			if ( is_array( $data ) && !array_key_exists( 'message', $data ) ) {
105
				$data['message'] = 'semanticmaps-par-' . $name;
106
			}
107
		}
108
109
		$params = array_merge( $params, MapsDisplayMap::getCommonMapParams() );
0 ignored issues
show
Deprecated Code introduced by
The method MapsDisplayMap::getCommonMapParams() has been deprecated.

This method has been deprecated.

Loading history...
110
		
111
		return $params;
112
	}
113
	
114
	/**
115
	 * Builds up and returns the HTML for the map, with the queried coordinate data on it.
116
	 *
117
	 * @param SMWQueryResult $res
118
	 * @param $outputmode
119
	 * 
120
	 * @return array or string
121
	 */
122
	public final function getResultText( SMWQueryResult $res, $outputmode ) {
123
		if ( $this->fatalErrorMsg !== false ) {
124
			return $this->fatalErrorMsg;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->fatalErrorMsg; (string|boolean) is incompatible with the return type documented by SMMapPrinter::getResultText of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
125
		}
126
127
		/**
128
		 * @var Parser $wgParser
129
		 */
130
		global $wgParser;
131
132
		$params = $this->params;
133
134
		$queryHandler = new SMQueryHandler( $res, $outputmode );
135
		$queryHandler->setLinkStyle($params['link']);
136
		$queryHandler->setHeaderStyle($params['headers']);
137
		$queryHandler->setShowSubject( $params['showtitle'] );
138
		$queryHandler->setTemplate( $params['template'] );
139
		$queryHandler->setUserParam( $params['userparam'] );
140
		$queryHandler->setHideNamespace( $params['hidenamespace'] );
141
		$queryHandler->setActiveIcon( $params['activeicon'] );
142
143
		$this->handleMarkerData( $params, $queryHandler );
144
		$locationAmount = count( $params['locations'] );
145
146
		if ( $locationAmount > 0 ) {
147
			// We can only take care of the zoom defaulting here,
148
			// as not all locations are available in whats passed to Validator.
149
			if ( $this->fullParams['zoom']->wasSetToDefault() && $locationAmount > 1 ) {
150
				$params['zoom'] = false;
151
			}
152
153
			$mapName = $this->service->getMapId();
154
155
			SMWOutputs::requireHeadItem(
156
				$mapName,
157
				$this->service->getDependencyHtml() .
158
				$configVars = Skin::makeVariablesScript( $this->service->getConfigVariables() )
159
			);
160
161
			foreach ( $this->service->getResourceModules() as $resourceModule ) {
162
				SMWOutputs::requireResource( $resourceModule );
163
			}
164
165
			if ( array_key_exists( 'source', $params ) ) {
166
				unset( $params['source'] );
167
			}
168
169
			return $this->getMapHTML( $params, $wgParser, $mapName );
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getMapHTML..., $wgParser, $mapName); (string) is incompatible with the return type documented by SMMapPrinter::getResultText of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
170
		}
171
		else {
172
			return $params['default'];
173
		}
174
	}
175
176
	/**
177
	 * Returns the HTML to display the map.
178
	 *
179
	 * @since 1.1
180
	 *
181
	 * @param array $params
182
	 * @param Parser $parser
183
	 * @param string $mapName
184
	 *
185
	 * @return string
186
	 */
187
	protected function getMapHTML( array $params, Parser $parser, $mapName ) {
188
		return Html::rawElement(
189
			'div',
190
			array(
191
				'id' => $mapName,
192
				'style' => "width: {$params['width']}; height: {$params['height']}; background-color: #cccccc; overflow: hidden;",
193
				'class' => 'maps-map maps-' . $this->service->getName()
194
			),
195
			wfMessage( 'maps-loading-map' )->inContentLanguage()->escaped() .
196
				Html::element(
197
					'div',
198
					array( 'style' => 'display:none', 'class' => 'mapdata' ),
199
					FormatJson::encode( $this->getJSONObject( $params, $parser ) )
200
				)
201
		);
202
	}
203
204
	/**
205
	 * Returns a PHP object to encode to JSON with the map data.
206
	 *
207
	 * @since 1.1
208
	 *
209
	 * @param array $params
210
	 * @param Parser $parser
211
	 *
212
	 * @return mixed
213
	 */
214
	protected function getJSONObject( array $params, Parser $parser ) {
215
		return $params;
216
	}
217
	
218
	/**
219
	 * Converts the data in the coordinates parameter to JSON-ready objects.
220
	 * These get stored in the locations parameter, and the coordinates on gets deleted.
221
	 * 
222
	 * @since 1.0
223
	 * 
224
	 * @param array &$params
225
	 * @param SMQueryHandler $queryHandler
226
	 */
227
	protected function handleMarkerData( array &$params, SMQueryHandler $queryHandler ) {
228
		if ( is_object( $params['centre'] ) ) {
229
			$params['centre'] = $params['centre']->getJSONObject();
230
		}
231
232
		$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...
233
		$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...
234
235
		$params['locations'] = $this->getJsonForStaticLocations(
236
			$params['staticlocations'],
237
			$params,
238
			$iconUrl,
239
			$visitedIconUrl
240
		);
241
242
		unset( $params['staticlocations'] );
243
244
		$this->addShapeData( $queryHandler->getShapes(), $params, $iconUrl, $visitedIconUrl );
245
246
		if ( $params['format'] === 'openlayers' ) {
247
			$params['layers'] = MapsDisplayMapRenderer::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...
248
		}
249
	}
250
251
	protected function getJsonForStaticLocations( array $staticLocations, array $params, $iconUrl, $visitedIconUrl ) {
0 ignored issues
show
Coding Style introduced by
getJsonForStaticLocations uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
252
		/**
253
		 * @var Parser $wgParser
254
		 */
255
		global $wgParser;
256
257
		$parser = version_compare( $GLOBALS['wgVersion'], '1.18', '<' ) ? $wgParser : clone $wgParser;
258
259
		$locationsJson = array();
260
261
		foreach ( $staticLocations as $location ) {
262
			$locationsJson[] = $this->getJsonForStaticLocation(
263
				$location,
264
				$params,
265
				$iconUrl,
266
				$visitedIconUrl,
267
				$parser
268
			);
269
		}
270
271
		return $locationsJson;
272
	}
273
274
	protected function getJsonForStaticLocation( Location $location, array $params, $iconUrl, $visitedIconUrl, Parser $parser ) {
275
		$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
276
277
		$jsonObj['title'] = $parser->parse( $jsonObj['title'], $parser->getTitle(), new ParserOptions() )->getText();
278
		$jsonObj['text'] = $parser->parse( $jsonObj['text'], $parser->getTitle(), new ParserOptions() )->getText();
279
280
		$hasTitleAndtext = $jsonObj['title'] !== '' && $jsonObj['text'] !== '';
281
		$jsonObj['text'] = ( $hasTitleAndtext ? '<b>' . $jsonObj['title'] . '</b><hr />' : $jsonObj['title'] ) . $jsonObj['text'];
282
		$jsonObj['title'] = strip_tags( $jsonObj['title'] );
283
284
		if ( $params['pagelabel'] ) {
285
			$jsonObj['inlineLabel'] = Linker::link( Title::newFromText( $jsonObj['title'] ) );
286
		}
287
288
		return $jsonObj;
289
	}
290
291
	/**
292
	 * @param Element[] $queryShapes
293
	 * @param array $params
294
	 * @param string $iconUrl
295
	 * @param string $visitedIconUrl
296
	 */
297
	protected function addShapeData( array $queryShapes, array &$params, $iconUrl, $visitedIconUrl ) {
298
		$params['locations'] = array_merge(
299
			$params['locations'],
300
			$this->getJsonForLocations(
301
				$queryShapes['locations'],
302
				$params,
303
				$iconUrl,
304
				$visitedIconUrl
305
			)
306
		);
307
308
		$params['lines'] = $this->getElementJsonArray( $queryShapes['lines'], $params );
309
		$params['polygons'] = $this->getElementJsonArray( $queryShapes['polygons'], $params );
310
	}
311
312
	/**
313
	 * @param Location[] $locations
314
	 * @param array $params
315
	 * @param string $iconUrl
316
	 * @param string $visitedIconUrl
317
	 *
318
	 * @return array
319
	 */
320
	protected function getJsonForLocations( array $locations, array $params, $iconUrl, $visitedIconUrl ) {
321
		$locationsJson = array();
322
323
		foreach ( $locations as $location ) {
324
			$jsonObj = $location->getJSONObject( $params['title'], $params['label'], $iconUrl, '', '', $visitedIconUrl );
325
326
			$jsonObj['title'] = strip_tags( $jsonObj['title'] );
327
328
			$locationsJson[] = $jsonObj;
329
		}
330
331
		return $locationsJson;
332
	}
333
334
	/**
335
	 * @param BaseElement[] $elements
336
	 * @param array $params
337
	 *
338
	 * @return array
339
	 */
340
	protected function getElementJsonArray( array $elements, array $params ) {
341
		$elementsJson = array();
342
343
		foreach ( $elements as $element ) {
344
			$jsonObj = $element->getJSONObject( $params['title'], $params['label'] );
0 ignored issues
show
Deprecated Code introduced by
The method Maps\Elements\BaseElement::getJSONObject() has been deprecated.

This method has been deprecated.

Loading history...
345
			$elementsJson[] = $jsonObj;
346
		}
347
348
		return $elementsJson;
349
	}
350
351
	/**
352
	 * Returns the internationalized name of the mapping service.
353
	 * 
354
	 * @return string
355
	 */
356
	public final function getName() {
357
		return wfMessage( 'maps_' . $this->service->getName() )->text();
358
	}
359
	
360
	/**
361
	 * Returns a list of parameter information, for usage by Special:Ask and others.
362
	 * 
363
	 * @return array
364
	 */
365
    public function getParameters() {
366
        $params = parent::getParameters();
0 ignored issues
show
Deprecated Code introduced by
The method SMW\ResultPrinter::getParameters() has been deprecated with message: since 1.8, use getParamDefinitions instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
367
        $paramInfo = $this->getParameterInfo();
368
        
369
        // Do not display this as an option, as the format already determines it
370
        // TODO: this can probably be done cleaner with some changes in Maps
371
        unset( $paramInfo['mappingservice'] );
372
        
373
        $params = array_merge( $params, $paramInfo );
374
375
		return $params;
376
    }
377
}
378