Completed
Push — master ( 4c4bcb...8e8eb9 )
by Bradley
02:26
created

Mapper   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 386
Duplicated Lines 19.69 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
dl 76
loc 386
rs 8.295
c 0
b 0
f 0
wmc 42
lcom 1
cbo 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
B render() 0 21 8
A searchLocation() 0 12 1
C location() 0 56 19
A map() 0 17 1
A streetview() 0 19 1
A marker() 0 15 2
A informationWindow() 0 15 2
B polyline() 0 24 2
B polygon() 25 25 2
B rectangle() 25 25 2
B circle() 26 26 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Mapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Mapper, and based on these observations, apply Extract Interface, too.

1
<?php namespace Cornford\Googlmapper;
2
3
use Cornford\Googlmapper\Contracts\MappingInterface;
4
use Cornford\Googlmapper\Exceptions\MapperArgumentException;
5
use Cornford\Googlmapper\Exceptions\MapperException;
6
use Cornford\Googlmapper\Exceptions\MapperSearchException;
7
use Cornford\Googlmapper\Exceptions\MapperSearchLimitException;
8
use Cornford\Googlmapper\Exceptions\MapperSearchResultException;
9
use Cornford\Googlmapper\Models\Location;
10
use Cornford\Googlmapper\Models\Map;
11
use Cornford\Googlmapper\Models\Streetview;
12
use Exception;
13
14
class Mapper extends MapperBase implements MappingInterface {
15
16
	const GOOGLE_RESPONSE_OK = 'OK';
17
	const GOOGLE_RESPONSE_ZERO_RESULTS = 'ZERO_RESULTS';
18
	const GOOGLE_RESPONSE_QUERY_LIMIT = 'OVER_QUERY_LIMIT';
19
	const GOOGLE_RESPONSE_DENIED = 'REQUEST_DENIED';
20
	const GOOGLE_RESPONSE_INVALID = 'INVALID_REQUEST';
21
	const GOOGLE_RESPONSE_UNKNOWN = 'UNKNOWN_ERROR';
22
23
	/**
24
	 * Renders and returns Google Map code.
25
	 *
26
	 * @param integer $item
27
	 *
28
	 * @return string
29
	 */
30
	public function render($item = -1)
31
	{
32
		if (!$this->isEnabled()) {
33
			return;
34
		}
35
36
		$options = $this->getOptions();
37
38
		foreach (($item > -1 ? [$this->getItem($item)] : $this->getItems()) as $model) {
39
			foreach ($model->getOptions() as $key => $option) {
40
				if (array_key_exists($key, $this->getOptions()) && $this->getOptions()[$key] !== $option) {
41
					$options[$key] = $option;
42
				}
43
			}
44
		}
45
46
		return $this->view->make('googlmapper::mapper')
0 ignored issues
show
Bug introduced by
The method withView() does not seem to exist on object<Illuminate\Contracts\View\View>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
47
			->withView($this->view)
48
			->withOptions($options)
49
			->withItems($item > -1 ? [$item => $this->getItem($item)] : $this->getItems())->render();
50
	}
51
52
	/**
53
	 * Search for a location against Google Maps Api.
54
	 *
55
	 * @param string $location
56
	 *
57
	 * @return mixed
58
	 */
59
	protected function searchLocation($location)
60
	{
61
		$request = file_get_contents(
62
			sprintf(
63
				'https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false&key=%s',
64
				urlencode($location),
65
				$this->getKey()
66
			)
67
		);
68
69
		return json_decode($request);
70
	}
71
72
	/**
73
	 * Locate a location and return a Location instance.
74
	 *
75
	 * @param string $location
76
	 *
77
	 * @throws MapperArgumentException
78
	 * @throws MapperSearchException
79
	 * @throws MapperSearchResultException
80
	 * @throws MapperSearchLimitException
81
	 * @throws MapperException
82
	 *
83
	 * @return Location
84
	 */
85
	public function location($location)
86
	{
87
		if (empty($location)) {
88
			throw new MapperArgumentException('Invalid location search term provided.');
89
		}
90
91
		try {
92
			$resultObject = $this->searchLocation($location);
93
		} catch (Exception $exception) {
94
			throw new MapperSearchException('Unable to perform location search, the error was: "' . $exception->getMessage() .  '".');
95
		}
96
97
		if (isset($resultObject->status) && $resultObject->status == self::GOOGLE_RESPONSE_QUERY_LIMIT) {
98
			throw new MapperSearchLimitException('Unable to perform location search, your API key is over your quota.');
99
		}
100
101
		if (isset($resultObject->status) &&
102
			in_array(
103
				$resultObject->status,
104
				[
105
					self::GOOGLE_RESPONSE_DENIED,
106
					self::GOOGLE_RESPONSE_INVALID,
107
					self::GOOGLE_RESPONSE_UNKNOWN
108
				]
109
			)
110
		) {
111
			throw new MapperSearchResultException('An error occurred performing the location search.');
112
		}
113
114
		if ((isset($resultObject->status) && $resultObject->status == self::GOOGLE_RESPONSE_ZERO_RESULTS) ||
115
			!isset($resultObject->results) ||
116
			(isset($resultObject->results) && count($resultObject->results) == 0)
117
		) {
118
			throw new MapperSearchResultException('No results found for the location search.');
119
		}
120
121
		if (!isset($resultObject->results[0]->formatted_address) ||
122
			!isset($resultObject->results[0]->address_components[0]->types[0]) ||
123
			!isset($resultObject->results[0]->geometry->location->lat) ||
124
			!isset($resultObject->results[0]->geometry->location->lng) ||
125
			!isset($resultObject->results[0]->place_id) ||
126
			isset($resultObject->status) && $resultObject->status != self::GOOGLE_RESPONSE_OK
127
		) {
128
			throw new MapperException('The location search return invalid result data.');
129
		}
130
131
		return new Location([
132
			'mapper'    => $this,
133
			'search'    => $location,
134
			'address'   => $resultObject->results[0]->formatted_address,
135
			'type'      => $resultObject->results[0]->address_components[0]->types[0],
136
			'latitude'  => $resultObject->results[0]->geometry->location->lat,
137
			'longitude' => $resultObject->results[0]->geometry->location->lng,
138
			'placeId'   => $resultObject->results[0]->place_id,
139
		]);
140
	}
141
142
	/**
143
	 * Add a new map.
144
	 *
145
	 * @param float $latitude
146
	 * @param float $longitude
147
	 * @param array $options
148
	 *
149
	 * @return self
150
	 */
151
	public function map($latitude, $longitude, array $options = [])
152
	{
153
		$parameters = array_replace_recursive(
154
			$this->getOptions(),
155
			[
156
				'latitude' => $latitude,
157
				'longitude' => $longitude,
158
				'map' => 'map_' . count($this->getItems())
159
			],
160
			$options
161
		);
162
163
		$item = new Map($parameters);
164
		$this->addItem($item);
165
166
		return $this;
167
	}
168
169
	/**
170
	 * Add a new street view map.
171
	 *
172
	 * @param float   $latitude
173
	 * @param float   $longitude
174
	 * @param integer $heading
175
	 * @param integer $pitch
176
	 * @param array   $options
177
	 *
178
	 * @return self
179
	 */
180
	public function streetview($latitude, $longitude, $heading, $pitch, array $options = [])
181
	{
182
		$parameters = array_replace_recursive(
183
			$this->getOptions(),
184
			[
185
				'latitude' => $latitude,
186
				'longitude' => $longitude,
187
				'heading' => $heading,
188
				'pitch' => $pitch,
189
				'map' => 'map_' . count($this->getItems())
190
			],
191
			$options
192
		);
193
194
		$item = new Streetview($parameters);
195
		$this->addItem($item);
196
197
		return $this;
198
	}
199
200
	/**
201
	 * Add a new map marker.
202
	 *
203
	 * @param float $latitude
204
	 * @param float $longitude
205
	 * @param array $options
206
	 *
207
	 * @throws MapperException
208
	 *
209
	 * @return self
210
	 */
211
	public function marker($latitude, $longitude, array $options = [])
212
	{
213
		$items = $this->getItems();
214
		$parameters = $this->getOptions();
215
		$options = array_replace_recursive(['user' => $parameters['user']], $parameters['markers'], $options);
216
217
		if (empty($items)) {
218
			throw new MapperException('No map found to add a marker to.');
219
		}
220
221
		$item = end($items);
222
		$item->marker($latitude, $longitude, $options);
223
224
		return $this;
225
	}
226
227
	/**
228
	 * Add a new map information window.
229
	 *
230
	 * @param float  $latitude
231
	 * @param float  $longitude
232
	 * @param string $content
233
	 * @param array  $options
234
	 *
235
	 * @throws MapperException
236
	 *
237
	 * @return self
238
	 */
239
	public function informationWindow($latitude, $longitude, $content, array $options = [])
240
	{
241
		$items = $this->getItems();
242
243
		if (empty($items)) {
244
			throw new MapperException('No map found to add a information window to.');
245
		}
246
247
		$parameters = $this->getOptions();
248
		$options = array_replace_recursive(['user' => $parameters['user']], ['markers' => $parameters['markers']], $options);
249
		$item = end($items);
250
		$item->marker($latitude, $longitude, array_replace_recursive($options, ['markers' => ['content' => $content]]));
251
252
		return $this;
253
	}
254
255
	/**
256
	 * Add a new map polyline.
257
	 *
258
	 * @param array $coordinates
259
	 * @param array $options
260
	 *
261
	 * @throws MapperException
262
	 *
263
	 * @return self
264
	 */
265
	public function polyline(array $coordinates = [], array $options = [])
266
	{
267
		$items = $this->getItems();
268
		$parameters = $this->getOptions();
269
270
		$defaults = [
271
			'coordinates' => $coordinates,
272
			'geodesic' => false,
273
			'strokeColor' => '#FF0000',
274
			'strokeOpacity' => 0.8,
275
			'strokeWeight' => 2,
276
			'editable' => false
277
		];
278
		$options = array_replace_recursive(['user' => $parameters['user']], $defaults, $options);
279
280
		if (empty($items)) {
281
			throw new MapperException('No map found to add a polyline to.');
282
		}
283
284
		$item = end($items);
285
		$item->shape('polyline', $coordinates, $options);
286
287
		return $this;
288
	}
289
290
	/**
291
	 * Add a new map polygon.
292
	 *
293
	 * @param array $coordinates
294
	 * @param array $options
295
	 *
296
	 * @throws MapperException
297
	 *
298
	 * @return self
299
	 */
300 View Code Duplication
	public function polygon(array $coordinates = [], array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
301
	{
302
		$items = $this->getItems();
303
		$parameters = $this->getOptions();
304
305
		$defaults = [
306
			'coordinates' => $coordinates,
307
			'strokeColor' => '#FF0000',
308
			'strokeOpacity' => 0.8,
309
			'strokeWeight' => 2,
310
			'fillColor' => '#FF0000',
311
			'fillOpacity' => 0.35,
312
			'editable' => false
313
		];
314
		$options = array_replace_recursive(['user' => $parameters['user']], $defaults, $options);
315
316
		if (empty($items)) {
317
			throw new MapperException('No map found to add a polygon to.');
318
		}
319
320
		$item = end($items);
321
		$item->shape('polygon', $coordinates, $options);
322
323
		return $this;
324
	}
325
326
	/**
327
	 * Add a new map rectangle.
328
	 *
329
	 * @param array $coordinates
330
	 * @param array $options
331
	 *
332
	 * @throws MapperException
333
	 *
334
	 * @return self
335
	 */
336 View Code Duplication
	public function rectangle(array $coordinates = [], array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
	{
338
		$items = $this->getItems();
339
		$parameters = $this->getOptions();
340
341
		$defaults = [
342
			'coordinates' => $coordinates,
343
			'strokeColor' => '#FF0000',
344
			'strokeOpacity' => 0.8,
345
			'strokeWeight' => 2,
346
			'fillColor' => '#FF0000',
347
			'fillOpacity' => 0.35,
348
			'editable' => false
349
		];
350
		$options = array_replace_recursive(['user' => $parameters['user']], $defaults, $options);
351
352
		if (empty($items)) {
353
			throw new MapperException('No map found to add a rectangle to.');
354
		}
355
356
		$item = end($items);
357
		$item->shape('rectangle', $coordinates, $options);
358
359
		return $this;
360
	}
361
362
	/**
363
	 * Add a new map circle.
364
	 *
365
	 * @param array $coordinates
366
	 * @param array $options
367
	 *
368
	 * @throws MapperException
369
	 *
370
	 * @return self
371
	 */
372 View Code Duplication
	public function circle(array $coordinates = [], array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
373
	{
374
		$items = $this->getItems();
375
		$parameters = $this->getOptions();
376
377
		$defaults = [
378
			'coordinates' => $coordinates,
379
			'strokeColor' => '#FF0000',
380
			'strokeOpacity' => 0.8,
381
			'strokeWeight' => 2,
382
			'fillColor' => '#FF0000',
383
			'fillOpacity' => 0.35,
384
			'radius' => 100000,
385
			'editable' => false
386
		];
387
		$options = array_replace_recursive(['user' => $parameters['user']], $defaults, $options);
388
389
		if (empty($items)) {
390
			throw new MapperException('No map found to add a circle to.');
391
		}
392
393
		$item = end($items);
394
		$item->shape('circle', $coordinates, $options);
395
396
		return $this;
397
	}
398
399
}
400