Servicio API RESTfull de Google MAP -Geocoding API-

Google dispone de un conjunto muy amplio de API’s que ofrecen servicios extraordinarios a las aplicaciones.

En concreto, lo que deseo contaros en esta ocasión es algo que en mi vida profesional siempre ha sido un objetivo, pero que nunca había conseguido resolverlo fácilmente.

Siempre que trabajamos con personas (clientes, pacientes, proveedores, etc.) siempre utilizamos un elemento de identificación que es el domicilio postal (la dirección).

Si hablas con el personal que lleva el GIS en tu organización, te dirá que una dirección requiere de un conjunto amplio de campos (tipo de calle, nombre de calle, número o KM, etc.) haciéndose muy difícil la recopilación de estos datos. Hasta hace poco, todos estos datos eran necesarios para obtener la latitud y longitud (X,Y) y representar dicha dirección en un mapa. Además, la latitud y longitud (X,Y) se utiliza para cálculo de distancias entre dos lugares y otras muchas funciones.

En este ejemplo que os dejo, mis requisitos eran:

  • Se facilita la dirección postal de un cliente y el sistema me debe facilitar una dirección normalizada (completa) y su latitud y longitud, para situarla en un mapa.
  • Representar a los clientes en un mapa.
  • Decidir qué tienda debe facilitar (por proximidad) los productos al cliente.

El punto (3) se resuelve fácilmente aplicando el teorema de Pitágoras . La distancia es la Hipotenusa y los Catetos son las diferencias de las coordenadas X e Y, entre el cliente y la tienda. Aquella diferencia que sea más pequeña significa que esa tienda es la más próxima al cliente.

Para utilizar los servicios de Google Map es necesario:

  • Disponer de una cuenta de Gmail.
  • Conectarse a la herramienta de gestión de los servicios de Google. https://console.cloud.google.com/
  • Definir los servicios:
    • Geocoding API .- Para validar direcciones y obtener la latitud y longitud de la dirección.
    • Maps JavaScript API.- Para mostrar mapas con las referencias.
  • Para que estos servicios funcionen, tienes que facilitar a Google tus datos de facturación, en concreto tu tarjeta de crédito. Google te facilita 300 dólares para descontar de tu facturación del año y te indica que no te hará ninguna facturación hasta que tú le autorices a hacerla. Esos 300 dólares, indica que son más que suficientes para web de poco tráfico con Google Map. Y que si tú haces negocio con tu blog o aplicación, desean que algo del beneficio les llegue a ellos por el servicio que te prestan. En principio, no deberíamos tener “miedo” en facilitarles esos datos.

DEMO: https://fhumanes.com/streetmap

(Va a estar poco tiempo, ya que no deseo consumir los 300$ con esta demo)

(1) Dirección que se entregó al sistema

(2) Dirección que ha obtenido de Google Map

(3) Tienda asignada por Proximidad

(1) Mapa de la ubicación definida

(2) Latitud y Longitud calculada por Google Map

Solución Técnica

La presentación de mapas, he utilizado la forma estándar que tienen PHPrunner de presentar mapas de Google Map, servicio Maps Javascript Api.

Para la validación de la dirección he utilizado el servicio Geocoding API. Hay múltiples formas de utilizar este servicio en el lenguaje PHP, pero como con la versión 10.4 de PHPRunner se “ha puesto de moda los servicios RESTfull API”, lo he utilizado con este interface.

Como es en un evento en donde tengo que hacer la ejecución del servicio, lo he hecho fuera de la solución de PHPRunner (no sé si se podría hacer directamente) y para hacer la petición he utilizado la librería de PHP unirest 3.0.4, que ya he utilizado en otras ocasiones para los servicos RESTfull API.

Os adjunto algunos de los códigos más interesantes:

find_street.php .- Búsqueda de la dirección normalizada y las coordenadas X,Y de Clientes y Tiendas.

<?php 
//  Validate postal address and obtain the latitude and longitude of the address 
function valueToZero($val){ 
    return empty($val)?0:$val; 
} 

@ini_set("display_errors","1"); 
@ini_set("display_startup_errors","1"); 

require_once __DIR__ . '/../unirest_3.0.4/autoload.php';  

$url_basic = 'https://maps.googleapis.com/maps/api/geocode/json'; 
$host = 'maps.googleapis.com'; 
$api_key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaa'; // Your Api Key of Google MAP 
$lang='es'; // For services of Google Map 

$address = $values['address']; 
$address = str_replace("\n", ',', $address); 
$address = str_replace("\r", ' ', $address); 
$address = htmlspecialchars($address); 

$response = Unirest\Request::get("$url_basic?address=$address&language=$lang&key=$api_key", 
  array() 
      ); 
$a = $response->code;        // HTTP Status code 
$b = $response->headers;     // Headers 
$c = $response->body;        // Parsed body 
$d = $response->raw_body;    // Unparsed body 
$f = json_decode($d,true); 
// var_dump($f); // DUMP pf array 
$count = count($f["results"]); 

foreach($f["results"] as $results) { 
      $standardAddress = $results["formatted_address"]; 
      $latency = $results["geometry"]["location"]["lat"]; 
      $length = $results["geometry"]["location"]["lng"]; 
      $dir = array(); 
      foreach($results["address_components"] as $e) { 
            $type = $e["types"][0]; 
            $dir[$type] = $e["long_name"]; 
            } 
        $standardAddress2 = $dir["route"].', '.$dir["street_number"].' '.$dir["subpremise"]."\n". 
                           $dir["postal_code"].' '. $dir["locality"]."\n". 
                           $dir["administrative_area_level_2"]."\n". 
                           $dir["administrative_area_level_1"]."\n". 
                           $dir["country"]; 
      $values["standardAddress"] = $standardAddress2; 
      $values["latency"] = $latency; 
      $values["length"] = $length; 
      break; 
}

find_store.php .- Búsqueda de la tienda más próxima al cliente.

<?php
//  Find the store closest to the Customer
$customer = $values['idclient'];

// Pythagoras theorem  | The square of the hypotenuse is equal to the sum of the square of its lengths of the triangle's other two sides.
$sql="
SELECT idclient, ((s.`latency`-c.`latency`)*(s.`latency`-c.`latency`))+((s.`length`-c.`length`)*(s.`length`-c.`length`)) d, s.`idstore`
FROM streetmap_client c
join streetmap_store s
where idclient = $customer
order by 2
";
$resql=db_query($sql,$conn);
$row=db_fetch_array($resql);
$store = $row['idstore']; 

$sql="update streetmap_client set `streetmap_store_idstore` = $store where `idclient` = $customer";
$resql=db_query($sql,$conn);

Ejemplo del JSON de respuesta de una petición de Geocoding

{
   "results": [
      {
         "access_points": [],
         "address_components": [
            {
               "long_name": "4º",
               "short_name": "4º",
               "types": [
                  "subpremise"
               ]
            },
            {
               "long_name": "1",
               "short_name": "1",
               "types": [
                  "street_number"
               ]
            },
            {
               "long_name": "Plaza Puerta del Vado",
               "short_name": "Plaza Puerta del Vado",
               "types": [
                  "route"
               ]
            },
            {
               "long_name": "Alcalá de Henares",
               "short_name": "Alcalá de Henares",
               "types": [
                  "locality",
                  "political"
               ]
            },
            {
               "long_name": "Madrid",
               "short_name": "M",
               "types": [
                  "administrative_area_level_2",
                  "political"
               ]
            },
            {
               "long_name": "Comunidad de Madrid",
               "short_name": "Comunidad de Madrid",
               "types": [
                  "administrative_area_level_1",
                  "political"
               ]
            },
            {
               "long_name": "España",
               "short_name": "ES",
               "types": [
                  "country",
                  "political"
               ]
            },
            {
               "long_name": "28803",
               "short_name": "28803",
               "types": [
                  "postal_code"
               ]
            }
         ],
         "formatted_address": "Plaza Puerta del Vado, 1, 4º, 28803 Alcalá de Henares, Madrid, España",
         "geometry": {
            "location": {
               "lat": 40.4775031,
               "lng": -3.3672253
            },
            "location_type": "ROOFTOP",
            "viewport": {
               "northeast": {
                  "lat": 40.4788520802915,
                  "lng": -3.365876319708498
               },
               "southwest": {
                  "lat": 40.4761541197085,
                  "lng": -3.368574280291502
               }
            }
         },
         "partial_match": true,
         "place_id": "EkZQbGF6YSBQdWVydGEgZGVsIFZhZG8sIDEsIDTCuiwgMjg4MDMgQWxjYWzDoSBkZSBIZW5hcmVzLCBNYWRyaWQsIFNwYWluIh8aHQoWChQKEgnbObgHEUlCDREUmIaYMumwmRIDNMK6",
         "types": [
            "subpremise"
         ]
      }
   ],
   "status": "OK"
}

Como es habitual os dejo el código del proyecto para que lo podáis instalar en vuestros equipos, pero antes, deberéis poner la “Key API” de Google MAP, para que os funcione.

Para cualquier duda o que lo que necesitéis, utilizar mi cuenta de email [email protected]

Adjuntos

Archivo Tamaño de archivo Descargas
zip Backup de la Base de Datos 2 KB 668
zip PHPRUnner 10.4 1 MB 708

Blog personal para facilitar soporte gratuito a usuarios de React y PHPRunner