Completed
Push — master ( 3d9086...304184 )
by Bradley
02:01
created

src/Cornford/Googlmapper/Mapper.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\MapperSearchKeyException;
8
use Cornford\Googlmapper\Exceptions\MapperSearchLimitException;
9
use Cornford\Googlmapper\Exceptions\MapperSearchResponseException;
10
use Cornford\Googlmapper\Exceptions\MapperSearchResultException;
11
use Cornford\Googlmapper\Models\Location;
12
use Cornford\Googlmapper\Models\Map;
13
use Cornford\Googlmapper\Models\Streetview;
14
use Exception;
15
16
class Mapper extends MapperBase implements MappingInterface {
17
18
	const GOOGLE_RESPONSE_OK = 'OK';
19
	const GOOGLE_RESPONSE_ZERO_RESULTS = 'ZERO_RESULTS';
20
	const GOOGLE_RESPONSE_QUERY_LIMIT = 'OVER_QUERY_LIMIT';
21
	const GOOGLE_RESPONSE_DENIED = 'REQUEST_DENIED';
22
	const GOOGLE_RESPONSE_INVALID = 'INVALID_REQUEST';
23
	const GOOGLE_RESPONSE_UNKNOWN = 'UNKNOWN_ERROR';
24
25
	/**
26
	 * Renders and returns Google Map code.
27
	 *
28
	 * @param integer $item
29
	 *
30
	 * @return string
31
	 */
32
	public function render($item = -1)
33
	{
34
		if (!$this->isEnabled()) {
35
			return;
36
		}
37
38
		return $this->view->make('googlmapper::mapper')
39
			->withView($this->view)
40
			->withOptions($this->generateRenderOptions($item))
41
			->withItems($item > -1 ? [$item => $this->getItem($item)] : $this->getItems())
42
			->render();
43
	}
44
45
	/**
46
	 * Renders and returns Google Map javascript code.
47
	 *
48
	 * @return string
49
	 */
50
	public function renderJavascript()
51
	{
52
		if (!$this->isEnabled()) {
53
			return;
54
		}
55
56
		return $this->view->make('googlmapper::javascript')
57
			->withView($this->view)
58
			->withOptions($this->generateRenderOptions())
59
			->render();
60
	}
61
62
	/**
63
	 * Generates the render options for Google Map.
64
	 *
65
	 * @param integer $item
66
	 *
67
	 * @return string
68
	 */
69
	protected function generateRenderOptions($item = -1)
70
	{
71
		$options = $this->getOptions();
72
73
		foreach (($item > -1 ? [$this->getItem($item)] : $this->getItems()) as $model) {
74
			foreach ($model->getOptions() as $key => $option) {
75
				if (array_key_exists($key, $this->getOptions()) && $this->getOptions()[$key] !== $option) {
76
					$options[$key] = $option;
77
				}
78
			}
79
		}
80
81
		return $options;
82
	}
83
84
	/**
85
	 * Search for a location against Google Maps Api.
86
	 *
87
	 * @param string $location
88
	 *
89
	 * @return mixed
90
	 */
91
	protected function searchLocation($location)
92
	{
93
		$request = file_get_contents(
94
			sprintf(
95
				'https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false&key=%s',
96
				urlencode($location),
97
				$this->getKey()
98
			)
99
		);
100
101
		return json_decode($request);
102
	}
103
104
	/**
105
	 * Locate a location and return a Location instance.
106
	 *
107
	 * @param string $location
108
	 *
109
	 * @throws MapperArgumentException
110
	 * @throws MapperSearchException
111
	 * @throws MapperSearchResponseException
112
	 * @throws MapperSearchResultException
113
	 * @throws MapperSearchKeyException
114
	 * @throws MapperSearchLimitException
115
	 * @throws MapperException
116
	 *
117
	 * @return Location
118
	 */
119
	public function location($location)
120
	{
121
		if (empty($location)) {
122
			throw new MapperArgumentException('Invalid location search term provided.');
123
		}
124
125
		try {
126
			$resultObject = $this->searchLocation($location);
127
		} catch (Exception $exception) {
128
			throw new MapperSearchException('Unable to perform location search, the error was: "' . $exception->getMessage() .  '".');
129
		}
130
131
		if (isset($resultObject->status) &&
132
			$resultObject->status == self::GOOGLE_RESPONSE_DENIED &&
133
			property_exists($resultObject, 'error_message') &&
134
			$resultObject->error_message == 'The provided API key is invalid.'
135
		) {
136
			throw new MapperSearchKeyException('Unable to perform location search, provided API key is invalid.');
137
		}
138
139
		if (isset($resultObject->status) && $resultObject->status == self::GOOGLE_RESPONSE_QUERY_LIMIT) {
140
			throw new MapperSearchLimitException('Unable to perform location search, your API key is over your quota.');
141
		}
142
143
		if (isset($resultObject->status) &&
144
			in_array(
145
				$resultObject->status,
146
				[
147
					self::GOOGLE_RESPONSE_DENIED,
148
					self::GOOGLE_RESPONSE_INVALID,
149
					self::GOOGLE_RESPONSE_UNKNOWN
150
				]
151
			)
152
		) {
153
			throw new MapperSearchResponseException('An error occurred performing the location search, the error was: "' . (property_exists($resultObject, 'error_message') ? $resultObject->error_message : 'Unknown') .  '".');
154
		}
155
156
		if ((isset($resultObject->status) && $resultObject->status == self::GOOGLE_RESPONSE_ZERO_RESULTS) ||
157
			!isset($resultObject->results) ||
158
			(isset($resultObject->results) && count($resultObject->results) == 0)
159
		) {
160
			throw new MapperSearchResultException('No results found for the location search.');
161
		}
162
163
		if (!isset($resultObject->results[0]->formatted_address) ||
164
			!isset($resultObject->results[0]->address_components[0]->types[0]) ||
165
			!isset($resultObject->results[0]->geometry->location->lat) ||
166
			!isset($resultObject->results[0]->geometry->location->lng) ||
167
			!isset($resultObject->results[0]->place_id) ||
168
			isset($resultObject->status) && $resultObject->status != self::GOOGLE_RESPONSE_OK
169
		) {
170
			throw new MapperException('The location search return invalid result data.');
171
		}
172
173
		return new Location([
174
			'mapper'    => $this,
175
			'search'    => $location,
176
			'address'   => $resultObject->results[0]->formatted_address,
177
			'type'      => $resultObject->results[0]->address_components[0]->types[0],
178
			'latitude'  => $resultObject->results[0]->geometry->location->lat,
179
			'longitude' => $resultObject->results[0]->geometry->location->lng,
180
			'placeId'   => $resultObject->results[0]->place_id,
181
		]);
182
	}
183
184
	/**
185
	 * Add a new map.
186
	 *
187
	 * @param float $latitude
188
	 * @param float $longitude
189
	 * @param array $options
190
	 *
191
	 * @return self
192
	 */
193
	public function map($latitude, $longitude, array $options = [])
194
	{
195
		$parameters = array_replace_recursive(
196
			$this->getOptions(),
197
			[
198
				'latitude' => $latitude,
199
				'longitude' => $longitude,
200
				'map' => 'map_' . count($this->getItems())
201
			],
202
			$options
203
		);
204
205
		$item = new Map($parameters);
206
		$this->addItem($item);
207
208
		return $this;
209
	}
210
211
	/**
212
	 * Add a new street view map.
213
	 *
214
	 * @param float   $latitude
215
	 * @param float   $longitude
216
	 * @param integer $heading
217
	 * @param integer $pitch
218
	 * @param array   $options
219
	 *
220
	 * @return self
221
	 */
222
	public function streetview($latitude, $longitude, $heading, $pitch, array $options = [])
223
	{
224
		$parameters = array_replace_recursive(
225
			$this->getOptions(),
226
			[
227
				'latitude' => $latitude,
228
				'longitude' => $longitude,
229
				'heading' => $heading,
230
				'pitch' => $pitch,
231
				'map' => 'map_' . count($this->getItems())
232
			],
233
			$options
234
		);
235
236
		$item = new Streetview($parameters);
237
		$this->addItem($item);
238
239
		return $this;
240
	}
241
242
	/**
243
	 * Add a new map marker.
244
	 *
245
	 * @param float $latitude
246
	 * @param float $longitude
247
	 * @param array $options
248
	 *
249
	 * @throws MapperException
250
	 *
251
	 * @return self
252
	 */
253
	public function marker($latitude, $longitude, array $options = [])
254
	{
255
		$items = $this->getItems();
256
257
		if (empty($items)) {
258
			throw new MapperException('No map found to add a marker to.');
259
		}
260
261
		$item = end($items);
262
		$parameters = $this->getOptions();
263
		$options = array_replace_recursive(
264
			['user' => $parameters['user']],
265
			['markers' => $parameters['markers']],
266
			$item->getOptions()['markers'],
267
			$options
268
		);
269
270
		$item->marker($latitude, $longitude, $options);
271
272
		return $this;
273
	}
274
275
	/**
276
	 * Add a new map information window.
277
	 *
278
	 * @param float  $latitude
279
	 * @param float  $longitude
280
	 * @param string $content
281
	 * @param array  $options
282
	 *
283
	 * @throws MapperException
284
	 *
285
	 * @return self
286
	 */
287
	public function informationWindow($latitude, $longitude, $content, array $options = [])
288
	{
289
		$items = $this->getItems();
290
291
		if (empty($items)) {
292
			throw new MapperException('No map found to add a information window to.');
293
		}
294
295
		$item = end($items);
296
		$parameters = $this->getOptions();
297
		$options = array_replace_recursive(
298
			['user' => $parameters['user']],
299
			['markers' => $parameters['markers']],
300
			$item->getOptions()['markers'],
301
			$options
302
		);
303
304
		$item->marker($latitude, $longitude, array_replace_recursive($options, ['markers' => ['content' => $content]]));
305
306
		return $this;
307
	}
308
309
	/**
310
	 * Add a new map polyline.
311
	 *
312
	 * @param array $coordinates
313
	 * @param array $options
314
	 *
315
	 * @throws MapperException
316
	 *
317
	 * @return self
318
	 */
319
	public function polyline(array $coordinates = [], array $options = [])
320
	{
321
		$items = $this->getItems();
322
323
		if (empty($items)) {
324
			throw new MapperException('No map found to add a polyline to.');
325
		}
326
327
		$defaults = [
328
			'coordinates' => $coordinates,
329
			'geodesic' => false,
330
			'strokeColor' => '#FF0000',
331
			'strokeOpacity' => 0.8,
332
			'strokeWeight' => 2,
333
			'editable' => false
334
		];
335
336
        $item = end($items);
337
		$parameters = $this->getOptions();
338
		$options = array_replace_recursive(
339
			['user' => $parameters['user']],
340
			$defaults,
341
            ['user' => $item->getOptions()['user']],
342
			$options
343
		);
344
345
		$item->shape('polyline', $coordinates, $options);
346
347
		return $this;
348
	}
349
350
	/**
351
	 * Add a new map polygon.
352
	 *
353
	 * @param array $coordinates
354
	 * @param array $options
355
	 *
356
	 * @throws MapperException
357
	 *
358
	 * @return self
359
	 */
360 View Code Duplication
	public function polygon(array $coordinates = [], array $options = [])
0 ignored issues
show
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...
361
	{
362
		$items = $this->getItems();
363
364
		if (empty($items)) {
365
			throw new MapperException('No map found to add a polygon to.');
366
		}
367
368
		$defaults = [
369
			'coordinates' => $coordinates,
370
			'strokeColor' => '#FF0000',
371
			'strokeOpacity' => 0.8,
372
			'strokeWeight' => 2,
373
			'fillColor' => '#FF0000',
374
			'fillOpacity' => 0.35,
375
			'editable' => false
376
		];
377
378
		$item = end($items);
379
		$parameters = $this->getOptions();
380
		$options = array_replace_recursive(
381
			['user' => $parameters['user']],
382
			$defaults,
383
            ['user' => $item->getOptions()['user']],
384
			$options
385
		);
386
387
		$item->shape('polygon', $coordinates, $options);
388
389
		return $this;
390
	}
391
392
	/**
393
	 * Add a new map rectangle.
394
	 *
395
	 * @param array $coordinates
396
	 * @param array $options
397
	 *
398
	 * @throws MapperException
399
	 *
400
	 * @return self
401
	 */
402 View Code Duplication
	public function rectangle(array $coordinates = [], array $options = [])
0 ignored issues
show
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...
403
	{
404
		$items = $this->getItems();
405
406
		if (empty($items)) {
407
			throw new MapperException('No map found to add a rectangle to.');
408
		}
409
410
		$defaults = [
411
			'coordinates' => $coordinates,
412
			'strokeColor' => '#FF0000',
413
			'strokeOpacity' => 0.8,
414
			'strokeWeight' => 2,
415
			'fillColor' => '#FF0000',
416
			'fillOpacity' => 0.35,
417
			'editable' => false
418
		];
419
420
		$item = end($items);
421
		$parameters = $this->getOptions();
422
		$options = array_replace_recursive(
423
			['user' => $parameters['user']],
424
			$defaults,
425
            ['user' => $item->getOptions()['user']],
426
			$options
427
		);
428
429
		$item->shape('rectangle', $coordinates, $options);
430
431
		return $this;
432
	}
433
434
	/**
435
	 * Add a new map circle.
436
	 *
437
	 * @param array $coordinates
438
	 * @param array $options
439
	 *
440
	 * @throws MapperException
441
	 *
442
	 * @return self
443
	 */
444 View Code Duplication
	public function circle(array $coordinates = [], array $options = [])
0 ignored issues
show
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...
445
	{
446
		$items = $this->getItems();
447
448
		if (empty($items)) {
449
			throw new MapperException('No map found to add a circle to.');
450
		}
451
452
		$defaults = [
453
			'coordinates' => $coordinates,
454
			'strokeColor' => '#FF0000',
455
			'strokeOpacity' => 0.8,
456
			'strokeWeight' => 2,
457
			'fillColor' => '#FF0000',
458
			'fillOpacity' => 0.35,
459
			'radius' => 100000,
460
			'editable' => false
461
		];
462
463
		$item = end($items);
464
		$parameters = $this->getOptions();
465
		$options = array_replace_recursive(
466
			['user' => $parameters['user']],
467
			$defaults,
468
            ['user' => $item->getOptions()['user']],
469
			$options
470
		);
471
472
		$item->shape('circle', $coordinates, $options);
473
474
		return $this;
475
	}
476
477
}
478