Created
February 10, 2022 13:48
-
-
Save afiqiqmal/f0bcf84fecaff11ceedb99d72bb5496b to your computer and use it in GitHub Desktop.
Helper class for geocode mapping
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Helpers; | |
use Illuminate\Support\Facades\Http; | |
class GoogleGeocode | |
{ | |
private $url = "https://maps.googleapis.com/maps/api/geocode/json"; | |
protected $client; | |
public function __construct() | |
{ | |
$this->client = Http::withoutRedirecting(); | |
} | |
public static function make() | |
{ | |
return new self; | |
} | |
public function byLatLng($lat, $lng, $components = []) | |
{ | |
$result = $this->client->retry(3, 200)->get($this->url, [ | |
'key' => config('api.google.map'), | |
'latlng' => "$lat,$lng", | |
'components' => collect($components)->map(function ($item, $key) { | |
return "$key:$item"; | |
})->join('|') | |
]); | |
if ($result->ok()) { | |
if ($result->json()['status'] == 'OK') { | |
$data = $this->formattedAddress($result->json()['results'] ?? []); | |
if (isset($data['country']) && $data['country'] == 'Malaysia') { | |
$data = $this->fixMissingValueForMalaysiaCountry($data); | |
} | |
$data['latitude'] = $result->json()['results'][0]['geometry']['location']['lat'] ?? null; | |
$data['longitude'] = $result->json()['results'][0]['geometry']['location']['lng'] ?? null; | |
return $data; | |
} | |
} | |
return null; | |
} | |
public function byAddress($address, $components = []) | |
{ | |
$result = $this->client->retry(3, 200)->get($this->url, [ | |
'key' => config('api.google.map'), | |
'address' => $address, | |
'components' => collect($components)->map(function ($item, $key) { | |
return "$key:$item"; | |
})->join('|') | |
]); | |
if ($result->ok()) { | |
if ($result->json()['status'] == 'OK') { | |
$data = $this->formattedAddress($result->json()['results'] ?? []); | |
if (isset($data['country']) && $data['country'] == 'Malaysia') { | |
$data = $this->fixMissingValueForMalaysiaCountry($data, $address); | |
} | |
$data['latitude'] = $result->json()['results'][0]['geometry']['location']['lat'] ?? null; | |
$data['longitude'] = $result->json()['results'][0]['geometry']['location']['lng'] ?? null; | |
return $data; | |
} | |
} | |
return null; | |
} | |
private function formattedAddress($result) | |
{ | |
if (($result[0]['types'][0] ?? null) != "point_of_interest") { | |
$data = $this->traverseComponent($result, 0); | |
if (!isset($data['city'])) { | |
if (isset($result[1])) { | |
return $this->traverseComponent($result, 1); | |
} | |
} | |
return $data; | |
} else { | |
if (isset($result[1])) { | |
return $this->traverseComponent($result, 1); | |
} | |
} | |
return null; | |
} | |
private function identifyKey($key) | |
{ | |
if ($key == 'administrative_area_level_1') { | |
return 'state'; | |
} | |
if ($key == 'locality') { | |
return 'city'; | |
} | |
if ($key == 'postal_code') { | |
return 'postcode'; | |
} | |
return $key; | |
} | |
private function formattedLongName(mixed $long_name) | |
{ | |
return str_replace(["Wilayah Persekutuan ", "Federal Territory of ", "Federal Territory"], "", $long_name); | |
} | |
private function buildAddress(array $data) | |
{ | |
return join(', ', array_filter([ | |
$data['floor'] ?? null, | |
$data['room'] ?? null, | |
$data['street_number'] ?? null, | |
$data['landmark'] ?? null, | |
$data['street_address'] ?? null, | |
$data['route'] ?? null, | |
$data['political'] ?? null, | |
])); | |
} | |
private function traverseComponent($result, $index): array | |
{ | |
$data = collect($result[$index]['address_components'])->mapWithKeys(function ($item) { | |
return [ | |
$this->identifyKey($item['types'][0]) => $this->formattedLongName($item['long_name']) | |
]; | |
})->toArray(); | |
$data['formatted_address'] = $result[$index]['formatted_address'] ?? null; | |
$data['lot_address'] = $this->buildAddress($data); | |
if (empty($data['lot_address'])) { | |
$data['lot_address'] = null; | |
} | |
return $data; | |
} | |
private function fixMissingValueForMalaysiaCountry(array $data, $address = null): array | |
{ | |
$states = json_decode(file_get_contents(storage_path('assets/malaysia_postcode.json')), true); | |
if (isset($data['city']) && !isset($data['postcode'])) { | |
foreach ($states as $item) { | |
$flag = false; | |
foreach ($item['city'] as $city) { | |
if ($city['name'] == $data['city']) { | |
$data['postcode'] = $city['postcode'][0] ?? null; | |
$flag = true; | |
break; | |
} | |
} | |
if ($flag) { | |
break; | |
} | |
} | |
} | |
if ((!isset($data['city']) || !isset($data['state'])) && isset($data['postcode'])) { | |
foreach ($states as $item) { | |
$flag = false; | |
foreach ($item['city'] as $city) { | |
if (in_array($data['postcode'], $city['postcode'])) { | |
$data['city'] = $city['name']; | |
$data['state'] = $item['name']; | |
$flag = true; | |
break; | |
} | |
} | |
if ($flag) { | |
break; | |
} | |
} | |
} | |
if ($address && !isset($data['city']) && !isset($data['postcode'])) { | |
//extract postcode from address | |
if (preg_match('/((?<!\d)\d{5}(?!\d))/', $address, $matches) > 0) { | |
$postcode = $matches[0]; | |
foreach ($states as $item) { | |
$flag = false; | |
foreach ($item['city'] as $city) { | |
if (in_array($postcode, $city['postcode'])) { | |
$data['city'] = $city['name']; | |
$data['state'] = $item['name']; | |
$data['postcode'] = $city['postcode'][0]; | |
$flag = true; | |
break; | |
} | |
} | |
if ($flag) { | |
break; | |
} | |
} | |
} | |
} | |
if (isset($data['city']) && $data['city'] == 'Kuala Lumpur') { | |
$data['state'] = $data['city']; | |
} | |
return $data; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment