Skip to content

Instantly share code, notes, and snippets.

@afiqiqmal
Created February 10, 2022 13:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afiqiqmal/f0bcf84fecaff11ceedb99d72bb5496b to your computer and use it in GitHub Desktop.
Save afiqiqmal/f0bcf84fecaff11ceedb99d72bb5496b to your computer and use it in GitHub Desktop.
Helper class for geocode mapping
<?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