Completed
Push — AUTOMATED_TESTING ( 6591ac...6229f9 )
by Gordon
15:27
created

MapAPI::setDelayLoadMapFunction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
/*
4
*
5
* This script is distributed in the hope that it will be useful,
6
* but WITHOUT ANY WARRANTY; without even the implied warranty of
7
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8
* GNU General public License for more details.
9
*
10
* This copyright notice MUST APPEAR in all copies of the script!
11
*
12
*  @author            CERDAN Yohann <[email protected]>
13
*  @copyright      (c) 2009  CERDAN Yohann, All rights reserved
14
*  @ version         18:13 26/05/2009
15
*/
16
17
class MapAPI extends ViewableData
18
{
19
20
	 /** GoogleMap key **/
21
	protected $googleMapKey = '';
22
23
	/** GoogleMap ID for the HTML DIV  **/
24
	protected $googleMapId = 'googlemapapi';
25
26
	/* Additional CSS classes to use when rendering the map */
27
	protected $set_additional_css_classes = '';
28
29
	/** Width of the gmap **/
30
	protected $width = 800;
31
32
	/** Height of the gmap **/
33
	protected $height = 600;
34
35
	/* array of lines to be drawn on the map */
36
	protected $lines = array();
37
38
	/* kml file to be rendered */
39
	protected $kmlFiles = array();
40
41
	/** Default zoom of the gmap **/
42
	protected $zoom = 9;
43
44
	/** Enable the zoom of the Infowindow **/
45
	protected $enableWindowZoom = false;
46
47
	/** Default zoom of the Infowindow **/
48
	protected $infoWindowZoom = 13;
49
50
	/** Lang of the gmap **/
51
	protected $lang = 'en';
52
53
	/**Center of the gmap **/
54
	protected $center = 'Paris, France';
55
56
	/*
57
	 Additional CSS classes to render as a class attribute for the div of the
58
	 map.  Use this if you want more  fine grained control over your map using
59
	 CSS.  If blank it will be ignored
60
	 */
61
	protected $additional_css_classes = '';
62
63
64
	/* Decided whether or not to show the inline map css style on div creation */
65
	protected $show_inline_map_div_style = true;
66
67
	protected $latLongCenter = null;
68
69
	protected $jsonMapStyles = '[]';
70
71
	/**
72
	 * Type of the gmap, can be:
73
	 *  'road' (roadmap),
74
	 *  'satellite' (sattelite/aerial photographs)
75
	 *  'hybrid' (hybrid of road and satellite)
76
	 *  'terrain' (terrain)
77
	 *  The JavaScript for the mapping service will convert this into a suitable mapping type
78
	 */
79
80
	protected $mapType = 'road';
81
82
83
	/** Content of the HTML generated **/
84
	protected $content = '';
85
86
	protected $mapService = 'google';
87
88
	/** Hide the marker by default **/
89
	protected $defaultHideMarker = false;
90
91
	/** Extra content (marker, etc...) **/
92
	protected $contentMarker = '';
93
94
	// a list of markers, markers being associative arrays
95
	protected $markers = array();
96
97
	/** Use clusterer to display a lot of markers on the gmap **/
98
	protected $useClusterer = false;
99
	protected $gridSize = 50;
100
	protected $maxZoom = 17;
101
	protected $clustererLibraryPath = "/mappable/javascript/google/markerclusterer.js";
102
103
	/** Enable automatic center/zoom **/
104
	protected $enableAutomaticCenterZoom = false;
105
106
	/** maximum longitude of all markers **/
107
	protected $maxLng = -1000000;
108
109
	/** minimum longitude of all markers **/
110
	protected $minLng = 1000000;
111
112
	/** max latitude of all markers **/
113
	protected $maxLat = -1000000;
114
115
	/** min latitude of all markers **/
116
	protected $minLat = 1000000;
117
118
	/** map center latitude (horizontal), calculated automatically as markers
119
	are added to the map **/
120
	protected $centerLat = null;
121
122
	/** map center longitude (vertical),  calculated automatically as markers
123
	are added to the map **/
124
	protected $centerLng = null;
125
126
	/** factor by which to fudge the boundaries so that when we zoom encompass,
127
	the markers aren't too close to the edge **/
128
	protected $coordCoef = 0.01;
129
130
	/* set this to true to render button to maximize / minimize a map */
131
	protected $allowFullScreen = null;
132
133
	/**
134
	 * Class constructor
135
	 *
136
	 * @param string  $googleMapKey the googleMapKey
137
	 */
138
139
	public function __construct($googleMapKey = '') {
140
		$this->googleMapKey = $googleMapKey;
141
	}
142
143
	/**
144
	 * Set the key of the gmap
145
	 *
146
	 * @param string  $googleMapKey the googleMapKey
147
	 *
148
	 * @return MapAPI
149
	 */
150
151
	public function setKey($googleMapKey) {
152
		$this->googleMapKey = $googleMapKey;
153
		return $this;
154
	}
155
156
	public function setShowInlineMapDivStyle($new_show_inline_map_div_style) {
157
		$this->show_inline_map_div_style = $new_show_inline_map_div_style;
158
		return $this;
159
	}
160
161
	public function setAdditionalCSSClasses($new_additional_css_classes) {
162
		$this->additional_css_classes = $new_additional_css_classes;
163
		return $this;
164
	}
165
166
167
	public function setMapStyle($newStyles) {
168
		$this->jsonMapStyles = $newStyles;
169
		return $this;
170
	}
171
172
	/**
173
	 * Set the useClusterer parameter (optimization to display a lot of marker)
174
	 *
175
	 * @param boolean $useClusterer     use cluster or not
176
	 * @param int     $gridSize         grid size
177
	 * @param int     $maxZoom 			max zoom to cluster at
178
	 *
179
	 * * @return MapAPI This same object, in order to enable chaining of methods
180
	 */
181
182
	public function setClusterer($useClusterer, $gridSize = 50, $maxZoom = 17,
183
		$clustererLibraryPath = '/mappable/javascript/google/markerclusterer.js') {
184
		$this->useClusterer = $useClusterer;
185
		$this->gridSize = $gridSize;
186
		$this->maxZoom = $maxZoom;
187
		$this->clustererLibraryPath = $clustererLibraryPath;
188
		return $this;
189
	}
190
191
	/**
192
	 * Set the ID of the default gmap DIV
193
	 *
194
	 * @param string  $googleMapId the google div ID
195
	 *
196
	 * @return MapAPI This same object, in order to enable chaining of methods
197
	 */
198
199
	public function setDivId($googleMapId) {
200
		$this->googleMapId = $googleMapId;
201
		return $this;
202
	}
203
204
	/**
205
	 * Set the size of the gmap.  If these values are not provided
206
	 * then CSS is used instead
207
	 *
208
	 * @param int     $width  GoogleMap  width
209
	 * @param int     $height GoogleMap  height
210
	 *
211
	 * @return MapAPI This same object, in order to enable chaining of methods
212
	 */
213
214
	public function setSize($width, $height) {
215
		$this->width = $width;
216
		$this->height = $height;
217
		return $this;
218
	}
219
220
	/**
221
	 * Set the lang of the gmap
222
	 *
223
	 * @param string  $lang GoogleMap  lang : fr,en,..
224
	 *
225
	 * @return MapAPI This same object, in order to enable chaining of methods
226
	 */
227
228
	public function setLang($lang) {
229
		$this->lang = $lang;
230
		return $this;
231
	}
232
233
	/**
234
	 * Set the zoom of the gmap
235
	 *
236
	 * @param int $zoom GoogleMap zoom.
237
	 *
238
	 * @return MapAPI This same object, in order to enable chaining of methods
239
	 */
240
241
	public function setZoom($zoom) {
242
		$this->zoom = $zoom;
243
		return $this;
244
	}
245
246
	/**
247
	 * Set the zoom of the infowindow
248
	 *
249
	 * @param int 	$infoWindowZoom GoogleMap information window zoom.
250
	 *
251
	 * @return MapAPI This same object, in order to enable chaining of methods
252
	 */
253
254
	public function setInfoWindowZoom($infoWindowZoom) {
255
		$this->infoWindowZoom = $infoWindowZoom;
256
		return $this;
257
	}
258
259
	/**
260
	 * Enable the zoom on the marker when you click on it
261
	 *
262
	 * @param int $enableWindowZoom info window enabled zoom.
263
	 *
264
	 * @return MapAPI This same object, in order to enable chaining of methods
265
	 */
266
267
	public function setEnableWindowZoom($enableWindowZoom) {
268
		$this->enableWindowZoom = $enableWindowZoom;
0 ignored issues
show
Documentation Bug introduced by
The property $enableWindowZoom was declared of type boolean, but $enableWindowZoom is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
269
		return $this;
270
	}
271
272
	/**
273
	 * Enable theautomatic center/zoom at the gmap load
274
	 *
275
	 * @param int $enableAutomaticCenterZoom enable automatic centre zoom
276
	 *
277
	 * @return MapAPI This same object, in order to enable chaining of methods
278
	 */
279
280
	public function setEnableAutomaticCenterZoom($enableAutomaticCenterZoom) {
281
		$this->enableAutomaticCenterZoom = $enableAutomaticCenterZoom;
0 ignored issues
show
Documentation Bug introduced by
The property $enableAutomaticCenterZoom was declared of type boolean, but $enableAutomaticCenterZoom is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
282
		return $this;
283
	}
284
285
	/**
286
	 * Set the center of the gmap (an address)
287
	 *
288
	 * @param string  $center GoogleMap  center (an address)
289
	 *
290
	 * @return MapAPI This same object, in order to enable chaining of methods
291
	 */
292
293
	public function setCenter($center) {
294
		$this->center = $center;
295
		return $this;
296
	}
297
298
	/**
299
	 * Set the type of the gmap.  Also takes into account legacy settings
300
	 *
301
	 * FIXME - allow other valid settings in config for map type
302
	 *
303
	 * @param string  $mapType  Can be one of road,satellite,hybrid or terrain. Defaults to road
304
	 *
305
	 * @return MapAPI This same object, in order to enable chaining of methods
306
	 */
307
308
	public function setMapType($mapType) {
309
		$this->mapType = $mapType;
310
311
		// deal with legacy values for backwards compatbility
312
		switch ($mapType) {
313
			case 'google.maps.MapTypeId.SATELLITE':
314
				$this->mapType = "satellite";
315
				break;
316
			case 'google.maps.MapTypeId.G_HYBRID_MAP':
317
				$this->mapType = "hybrid";
318
				break;
319
			case 'google.maps.MapTypeId.G_PHYSICAL_MAP':
320
				$this->mapType = "terrain";
321
				break;
322
			case 'google.maps.MapTypeId.ROADMAP':
323
				$this->mapType = "road";
324
				break;
325
		}
326
		return $this;
327
	}
328
329
	/*
330
	Set whether or not to allow the full screen tools
331
	@return MapAPI This same object, in order to enable chaining of methods
332
	*/
333
	public function setAllowFullScreen($allowed) {
334
		$this->allowFullScreen = $allowed;
335
		return $this;
336
	}
337
338
	/**
339
	* Set the center of the gmap
340
	*
341
	* @return MapAPI This same object, in order to enable chaining of methods
342
	**/
343
	public function setLatLongCenter($center) {
344
		// error check, we want an associative array with lat,lng keys numeric
345
346
		if (!is_array($center)) {
347
			throw new InvalidArgumentException('Center must be an associative array containing lat,lng');
348
		}
349
350
		$keys = array_keys($center);
351
		sort($keys);
352
		if (implode(',', $keys) != 'lat,lng') {
353
			throw new InvalidArgumentException('Keys provided must be lat, lng');
354
		}
355
356
		$this->latLongCenter = $center;
357
		return $this;
358
	}
359
360
	/**
361
	 * Set the defaultHideMarker
362
	 *
363
	 * @param boolean $defaultHideMarker hide all the markers on the map by default
364
	 *
365
	 * @return MapAPI
366
	 */
367
368
	public function setDefaultHideMarker($defaultHideMarker) {
369
		$this->defaultHideMarker = $defaultHideMarker;
370
		return $this;
371
	}
372
373
	/**
374
	 * Get the google map content
375
	 *
376
	 * @return string the google map html code
377
	 */
378
379
	public function getGoogleMap() {
380
		return $this->content;
381
	}
382
383
384
	/**
385
	 * Get URL content using cURL.
386
	 *
387
	 * @param string  $url the url
388
	 *
389
	 * @return string the html code
390
	 *
391
	 * @todo add proxy settings
392
	 */
393
394
	public function getContent($url) {
395
		$curl = curl_init();
396
		curl_setopt($curl, CURLOPT_TIMEOUT, 10);
397
		curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
398
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
399
		curl_setopt($curl, CURLOPT_URL, $url);
400
		$data = curl_exec($curl);
401
		curl_close($curl);
402
		return $data;
403
	}
404
405
	/**
406
	 * Geocoding an address (address -> lat,lng)
407
	 *
408
	 * @param string  $address an address
409
	 *
410
	 * @return string array with precision, lat & lng
411
	 */
412
413
	public function geocoding($address) {
414
		$geocoder = new MappableGoogleGeocoder();
415
		$locations = $geocoder->getLocations($address);
416
		$result = null;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
417
		if (!empty($locations)) {
418
			$place = $locations[0];
419
			$location = $place['geometry']['location'];
420
			$result = array(
421
				'lat' => $location['lat'],
422
				'lon' => $location['lng'],
423
				'geocoded' => true
424
			);
425
426
		} else {
427
			$result = array(); // no results
428
		}
429
		return $result;
430
	}
431
432
	/**
433
	 * Add marker by his coord
434
	 *
435
	 * @param string  $lat      lat
436
	 * @param string  $lng      lngs
437
	 * @param string  $html     html code display in the info window
438
	 * @param string  $category marker category
439
	 * @param string  $icon     an icon url
440
	 *
441
	 * @return MapAPI
442
	 */
443
444
	public function addMarkerByCoords($lat, $lng, $html = '', $category = '', $icon = '') {
445
		$m = array(
446
			'latitude' => $lat,
447
			'longitude' => $lng,
448
			'html' => $html,
449
			'category' => $category,
450
			'icon' => $icon
451
		);
452
		array_push($this->markers, $m);
453
		return $this;
454
	}
455
456
457
	/**
458
	 * Add marker by his address
459
	 *
460
	 * @param string  $address  an ddress
461
	 * @param string  $content  html code display in the info window
462
	 * @param string  $category marker category
463
	 * @param string  $icon     an icon url
464
	 *
465
	 * @return MapAPI
466
	 */
467
468
	public function addMarkerByAddress($address, $content = '', $category = '', $icon = '') {
469
		$point = $this->geocoding($address);
470
		if ($point !== null) {
471
			$this->addMarkerByCoords($point['lat'], $point['lon'], $content, $category, $icon);
472
		}
473
		return $this;
474
	}
475
476
	/**
477
	 * Add marker by an array of coord
478
	 *
479
	 * @param array  $coordtab an array of lat,lng,content
480
	 * @param string  $category marker category
481
	 * @param string  $icon     an icon url
482
	 *
483
	 * @return MapAPI
484
	 */
485
486
	public function addArrayMarkerByCoords($coordtab, $category = '', $icon = '') {
487
		foreach ($coordtab as $coord) {
488
			$this->addMarkerByCoords($coord[0], $coord[1], $coord[2], $category, $icon);
489
		}
490
		return $this;
491
	}
492
493
494
	/**
495
	 * Adds a {@link ViewableData} object that implements {@link Mappable}
496
	 * to the map.
497
	 * @param   $infowindowtemplateparams Optional array of extra parameters to pass to the map info window
498
	 *
499
	 * @param ViewableData $obj
500
	 */
501
	public function addMarkerAsObject(ViewableData $obj, $infowindowtemplateparams = null) {
502
		$extensionsImplementMappable = false;
503
		$extensions = Object::get_extensions(get_class($obj));
504
		if (is_array($extensions)) {
505
506
			foreach ($extensions as $extension) {
507
				$class = new ReflectionClass($extension);
508
				if ($class->implementsInterface('Mappable')) {
509
					$extensionsImplementMappable = true;
510
				}
511
512
			}
513
		}
514
515
		if ($extensionsImplementMappable ||
516
			($obj instanceof Mappable) ||
517
			(Object::has_extension($obj->ClassName, 'MapExtension'))
518
		) {
519
			$cat = $obj->hasMethod('getMappableMapCategory') ? $obj->getMappableMapCategory() : "default";
520
			if ($infowindowtemplateparams !== null) {
521
				foreach ($infowindowtemplateparams as $key => $value) {
522
					$obj->{$key} = $value;
523
				}
524
			}
525
			$this->addMarkerByCoords(
526
				$obj->getMappableLatitude(),
527
				$obj->getMappableLongitude(),
528
				$obj->getMappableMapContent(),
529
				$cat,
530
				$obj->getMappableMapPin()
531
			);
532
		}
533
534
		return $this;
535
	}
536
537
538
	/**
539
	 * Draws a line between two {@link ViewableData} objects
540
	 *
541
	 * @param ViewableData $one   The first point
542
	 * @param ViewableData $two   The second point
543
	 * @param string  $color The hexidecimal color of the line
544
	 */
545
	public function connectPoints(ViewableData $one, ViewableData $two, $color = "#FF3300") {
546
		$this->addLine(
547
			array($one->getMappableLatitude(), $one->getMappableLongitude()),
548
			array($two->getMappableLatitude(), $two->getMappableLongitude()),
549
			$color
550
		);
551
	}
552
553
554
	public function forTemplate() {
555
		$this->generate();
556
		return $this->getGoogleMap();
557
	}
558
559
	/**
560
	 * Add a KML file which will be rendered on this map.  Normally used for likes
561
	 * of GPS traces from activities
562
	 *
563
	 * @param string  $url      url of the kml file compatible with gmap and gearth
564
	 *
565
	 * @return MapAPI
566
	 */
567
568
	public function addKML($url) {
569
		array_push($this->kmlFiles, $url);
570
		return $this;
571
	}
572
573
574
	/*
575
	Add a line to the map
576
577
	*/
578
	public function addLine($from = array(), $to = array(), $color = "#FF3300") {
579
		$line = array(
580
			'lat1' => $from[0],
581
			'lon1' => $from[1],
582
			'lat2' => $to[0],
583
			'lon2' => $to[1],
584
			'color' => $color
585
		);
586
587
		array_push($this->lines, $line);
588
		return $this;
589
	}
590
591
592
	/*
593
	For php 5.3
594
	*/
595
	public static function jsonRemoveUnicodeSequences($struct) {
596
		 return preg_replace("/\\\\u([a-f0-9]{4})/e",
597
		 					"iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))",
598
		 					json_encode($struct));
599
	}
600
601
602
	/**
603
	 * Generate the gmap
604
	 *
605
	 * @return void
606
	 */
607
608
	public function generate() {
609
		// from http://stackoverflow.com/questions/3586401/cant-decode-json-string-in-php
610
		$jsonMarkers = null;
0 ignored issues
show
Unused Code introduced by
$jsonMarkers is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
611
		$linesJson = null;
0 ignored issues
show
Unused Code introduced by
$linesJson is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
612
		$kmlJson = null;
0 ignored issues
show
Unused Code introduced by
$kmlJson is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
613
614
		// prior to PHP version 5.4, one needs to use regex
615
		if (PHP_VERSION_ID < 50400) {
616
			$jsonMarkers = stripslashes(MapAPI::jsonRemoveUnicodeSequences($this->markers));
617
			$linesJson = stripslashes(MapAPI::jsonRemoveUnicodeSequences($this->lines));
618
			$kmlJson = stripslashes(MapAPI::jsonRemoveUnicodeSequences($this->kmlFiles));
619
		} else {
620
			$jsonMarkers = stripslashes(json_encode($this->markers, JSON_UNESCAPED_UNICODE));
621
			$linesJson = stripslashes(json_encode($this->lines, JSON_UNESCAPED_UNICODE));
622
			$kmlJson = stripslashes(json_encode($this->kmlFiles, JSON_UNESCAPED_UNICODE));
623
		}
624
625
		 // Center of the GMap - text centre takes precedence
626
		$geocodeCentre = ($this->latLongCenter) ?
627
							$this->latLongCenter : $this->geocoding($this->center);
628
629
		// coordinates for centre depending on which method used
630
		if (isset($geocodeCentre['geocoded'] )) {
631
			$latlngCentre = array(
632
				'lat' => $geocodeCentre['lat'],
633
				'lng' => $geocodeCentre['lon']
634
			);
635
		} else if (is_array($this->latLongCenter)) {
636
			$latlngCentre = $this->latLongCenter;
637
		}
638
639
		$this->LatLngCentreJSON = stripslashes(json_encode($latlngCentre));
0 ignored issues
show
Documentation introduced by
The property LatLngCentreJSON does not exist on object<MapAPI>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The variable $latlngCentre does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
640
641
		$lenLng = $this->maxLng - $this->minLng;
642
		$lenLat = $this->maxLat - $this->minLat;
643
		$this->minLng -= $lenLng * $this->coordCoef;
644
		$this->maxLng += $lenLng * $this->coordCoef;
645
		$this->minLat -= $lenLat * $this->coordCoef;
646
		$this->maxLat += $lenLat * $this->coordCoef;
647
648
		// add the css class mappable as a handle onto the map styling
649
		$this->additional_css_classes .= ' mappable';
650
651
		if (!$this->enableAutomaticCenterZoom) {
652
			$this->enableAutomaticCenterZoom = 'false';
0 ignored issues
show
Documentation Bug introduced by
The property $enableAutomaticCenterZoom was declared of type boolean, but 'false' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
653
		}
654
655
		if (!$this->useClusterer) {
656
			$this->useClusterer = 'false';
0 ignored issues
show
Documentation Bug introduced by
The property $useClusterer was declared of type boolean, but 'false' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
657
		}
658
659
		if (!$this->defaultHideMarker) {
660
			$this->defaultHideMarker = 'false';
0 ignored issues
show
Documentation Bug introduced by
The property $defaultHideMarker was declared of type boolean, but 'false' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
661
		}
662
663
		if (!$this->MapTypeId) {
0 ignored issues
show
Bug introduced by
The property MapTypeId does not seem to exist. Did you mean mapType?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
664
			$this->MapTypeId = 'false';
0 ignored issues
show
Bug introduced by
The property MapTypeId does not seem to exist. Did you mean mapType?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
665
		}
666
667
		// initialise full screen as the config value if not already set
668
		if ($this->allowFullScreen === null) {
669
			$this->allowFullScreen = Config::inst()->get('Mappable', 'allow_full_screen');
670
		}
671
672
		if (!$this->allowFullScreen) {
673
			$this->allowFullScreen = 'false';
674
		}
675
676
		if (!$this->enableWindowZoom) {
677
			$this->enableWindowZoom = 'false';
0 ignored issues
show
Documentation Bug introduced by
The property $enableWindowZoom was declared of type boolean, but 'false' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
678
		}
679
680
		$vars = new ArrayData(array(
681
				'JsonMapStyles' => $this->jsonMapStyles,
682
				'AdditionalCssClasses' => $this->additional_css_classes,
683
				'Width' => $this->width,
684
				'Height' => $this->height,
685
				'ShowInlineMapDivStyle' => $this->show_inline_map_div_style,
686
				'InfoWindowZoom' => $this->infoWindowZoom,
687
				'EnableWindowZoom' => $this->enableWindowZoom,
688
				'MapMarkers' => $jsonMarkers,
689
				'DefaultHideMarker' => $this->defaultHideMarker,
690
				'LatLngCentre' => $this->LatLngCentreJSON,
0 ignored issues
show
Documentation introduced by
The property LatLngCentreJSON does not exist on object<MapAPI>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
691
				'EnableAutomaticCenterZoom' => $this->enableAutomaticCenterZoom,
692
				'Zoom' => $this->zoom,
693
				'MaxZoom' => $this->maxZoom,
694
				'GridSize' => $this->gridSize,
695
				'MapType' => $this->mapType,
696
				'GoogleMapID' => $this->googleMapId,
697
				'Lang'=>$this->lang,
698
				'UseClusterer'=>$this->useClusterer,
699
				'ClustererLibraryPath' => $this->clustererLibraryPath,
700
				'ClustererMaxZoom' => $this->maxZoom,
701
				'ClustererGridSize' => $this->gridSize,
702
				'Lines' => $linesJson,
703
				'KmlFiles' => $kmlJson,
704
				'AllowFullScreen' => $this->allowFullScreen,
705
				'UseCompressedAssets' => Config::inst()->get('Mappable', 'use_compressed_assets')
706
			)
707
		);
708
709
		// HTML component of the map
710
		$this->content = $this->processTemplateHTML('Map', $vars);
711
	}
712
713
	/**
714
	 * @param string $templateName
715
	 * @param ArrayData $templateVariables
716
	 */
717
	public function processTemplateHTML($templateName, $templateVariables = null) {
718
		if (!$templateVariables) {
719
			$templateVariables = new ArrayList();
720
		}
721
		$mappingService = Config::inst()->get('Mappable', 'mapping_service');
722
		$result = $templateVariables->renderWith($templateName.$mappingService.'HTML');
723
		return $result;
724
	}
725
}
726