Usuario:ManuelRomero/PHP/hibridas/practica

De WikiEducator
Saltar a: navegación, buscar



Práctica guiada de aplicaciones híbridas

Se trata de hacer una aplicación híbrida cuya descripción es la siguiente (Se puede ver en el docuemnto pdf que os he pasado).

  • Desarrollo usando el servicio task de google con rest


Realizando la aplicacion de repartos

  • Las especificaciones según el enunciado del tema son las siguientes
  1. Se utilizará la API del servicio de tareas de Google (Google Tasks) para almacenar como listas de tareas la información de los repartos. Cada lista de tareas se corresponde en la aplicación con una lista de reparto, y cada una de sus tareas con un envío.
    1. Para diferenciar una lista de otra, se le pone como parte del título la fecha del día en que se hará el reparto.
  2. Para cada producto que se reparte se creará una tarea en la lista correspondiente. Esa tarea almacenará la dirección de envío y sus coordenadas. Para obtenerlas, y para mostrar su ubicación en un mapa, en el momento en que se introduzca la dirección se utilizará el servicio de geocodificación de Google (Google Geocoding).
  3. Para optimizar la ruta que se ha de recorrer, se utilizará Google Directions. La idea es reorganizar de forma automática el orden de los productos que se van a repartir cada día de forma que se minimice la distancia recorrida.
  4. Se visualizará en una nueva ventana el mapa correspondiente a las coordenadas de envío (google maps)
  5. En total usaremos cuatro servicios
    1. Google Task usaremos la versión 1 v1. Decir que es una version beta y puede tener modificaciones que no mantengan compatibilidad
    2. Google Geocoding
    3. Google Directons
    4. Google Maps

Repartos.png

  • Cuando se cree una nueva tarea (un nuevo envío), se pedirá la dirección y se mostrará una pantalla como la siguiente para que el usuario complete los datos necesarios.

Repartos1.jpg


Icon inter.gif

Recursos de la Web


  • Página para realizar usos y accesos a API de google
https://developers.google.com/api-client-library/php/start/get_started
  • La página de google donde tenemos toda la información de las apis
https://developers.google.com/google-apps
  • Información con las clases de la API de Tasks
https://github.com/google/google-api-php-client/blob/master/src/Google/Service/Tasks.php
  • Para descargar las librerías de Xajax
http://www.xajax-project.org/en/download/
http://sourceforge.net/projects/xajax/files/xajax/
https://github.com/Xajax/Xajax
http://stackoverflow.com/questions/2126410/xajax-alternative
  • Qué es crear un proyecto en google
https://developers.google.com/console/help/?hl=es
  • Otras web que he mirado
https://developers.google.com/google-apps/tasks/
http://rubenvasallo.es/php/google-y-su-oauth2/
https://developers.google.com/apis-explorer/#p/tasks/v1/

}}

Creando el proyecto en google

  • El primer paso es crear el proyecto en google y crearnos los credenciales necesarios para incorporar en nuestra aplicación

AppHibridaRepartos1.png

  • Para poder utilizar las API de google, debemos crear un proyecto donde las incluiremos,
  • Un proyecto en google consiste en un conjunto de información relacionada con un desarrollo, donde espeficicas datos de autentificación Api que tu proyecto puede usar, puedes ver cuanto se utiliza tu aplicación, especificar accesos por url o por email y mas conceptos.
  • Google facilita una consola para este cometido donde puedes modificar, crear y/o visulizar esta información.
  • Para crear un proyecto, accedemos a la consola de google (previamente hay que identificarse si no lo has hecho antes).
https://console.developers.google.com/
  • Una vez dentro debemos crear una clave para acceder a nuestra aplicación. Estos conceptos están especificados en los apuntes.
  • Accedemos a google, (debemos crear una cuenta)
  • Cada uno que haga como quiera, podéis crearos un nuevo usuario en google para estas tareas e independizaros de vuestro usuario habitual.

Configurando servicios

  • Descargamos las librerías para utilizar las API de google usando php
  • Las podemos descargar en línea de comandos con el comando
 git clone https://github.com/google/google-api-php-client

Si vamos a descargarlas al url especificado, nos redirigen La página de google donde tenemos toda la información de las apis

https://developers.google.com/google-apps
  • Una vez descargados tendremos en el directorio donde lo hayamos descargado (mejor hacerlo en el directorio del proyecto), el directorio google-api-php y dentro de él, los directorios con los fuentes para usar las diferentes librerías
  • Especificamos en nuestro programa la ruta para esta ubicación
set_include_path("google-api-php-client/src/" . PATH_SEPARATOR . get_include_path());
  • Ahora incluimos las librerías necesarias
 require_once 'Google/Client.php';
 require_once 'Google/Service/Tasks.php';
 require_once'Google/Service/Calendar.php';
  • Para el tema de Ajax, descargamos la librería de xAjax que es lo que vamos a usar, y dejo en una carpeta llmada libs, dentro del directorio del proyecto las carpetas con sus contenidos de xajax_core y xajax_js

Creando objeto Xajax

  • Directamente ponemos el código para usar ajax
  • Ahora creamos el objeto xAjax
// Creamos el objeto xajax
$xajax = new xajax('ajaxmaps.php');
 
// Configuramos la ruta en que se encuentra la carpeta xajax_js
$xajax->configure('javascript URI','http://localhost/Repartos/libs/');
 
// Y registramos las funciones que vamos a llamar desde JavaScript
//Estas funciones vienen implementadas en el fichero facilitado '''''ajaxmaps.php'''''
$xajax->register(XAJAX_FUNCTION,"obtenerCoordenadas");
$xajax->register(XAJAX_FUNCTION,"ordenarReparto");

Objetos del api

  • Definimos objetos para usar el api de google.
  • En esta parte hay alguna diferencia con lo facilitado en la plataforma pues usamos una versión diferentes, aunque no son demasiados.
  • El objeto de Google_Cliente(), se va a instanciar para autentificarse y autorizar oAuth2
  • Ver el wiki de al lado. Autentificarnos consiste en que obligaremos al usuario de nuestra aplicación a que un tercer, en este caso google, le pida que se identifique con usuario y contraseña
  • Autorizar consiste en que el usuario de nuestra aplicación autoriza a la aplicación a acceder en su nombre a ciertos recursos privados que especificaremos con el método setScope, sin necesidad de que la aplicación conozca ni su usuario ni su contraseña.
  • Además de la aplicación web, tenemos un proyecto en google donde estás las API's configuradas para que nuestra aplicación las pueda utilizar
  • A continuación el proceso para este objetivo


 $idCliente='xxxxxxxxxxxxxxxx.apps.googleusercontent.com';
 $passCliente ='Axxsadfdp4yOmt9bnSOSsCpiaQCypw';
 $keyDeveloper='AIzaSyDddesaceLUcv5J93-0BRaS4nM1hQ7cWglrUaZ5Gw';
 
//URL Donde google redirigirá la aplicación una vez que se haya autentificado
//En mi caso el mismo fichero php que contiene la aplicación
 $urlRedirect = 'http://localhost/Repartos/index.php';
 
 
// Creamos el objeto de la API de Google, primero un objeto de la clase Client
$cliente = new Google_Client();
 
 
// Y lo configuramos con los nuestros identificadores
 
$cliente->setApplicationName("Gestor de repartos");
 
//Establecemos las credenciales para este cliente
$cliente->setClientId($idCliente);
$cliente->setClientSecret($passCliente);
$cliente->setDeveloperKey($keyDeveloper);
 
//Este método especificará la url donde queremos que google redirija la aplicación una vez que se haya logeado correctamente el usuario y que se hayan establecido de manera correcta las credenciales correspondiente. En nuestro caso será al mismo fichero.
$cliente->setRedirectUri($urlRedirect);
 
 
//Establecemos los permisos que queremos otorgar. En este caso queremos conceder acceso a tasks y a calendar para que el usuario pueda acceder a tareas y 
$cliente->setScopes(array('https://www.googleapis.com/auth/tasks','https://www.googleapis.com/auth/calendar'));
  • Para asegurar de donde tomar los datos, aunque es muy intuitivo, vemos la siguiente imagen que se relaciona con los métodos que requieren sus datos.

DatosGoogle.png

Verificando la autentificacion

  • Este código está tomado de uno de los ficheros ejemplo que google facilita junto con las librerías
//NEcesitamos hacer dos cosas
Si el usuario se deslogue nos vendrá una variable de tipo logout por get, por se acaso lo podemos mirar en REQUEST
//El token lo guarda el sistema en una variable de sesion  por ejemplo token
/************************************************
<!--
  If we're logging out we just need to clear our
  local access token in this case
 ************************************************/
if (isset($_REQUEST['logout'])) {
  unset($_SESSION['access_token']);
}
-->
 
/*
Ahora queda verificar si estamos o no logueados
si nos viene el token vendrá en GET['code']
Si necesitamos hacer el intercambio , método setAccessToken
*/
 
if (!isset($_GET['code'])) {
    //Si tenemos token lo usamos para que la aplicación acceda a los datos en nombre de un usuario
    $auth_url = $cliente->createAuthUrl();
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
    $cliente->authenticate($_GET['code']);
    $_SESSION['access_token'] = $cliente->getAccessToken();
 
}
  • Por otro lado sería bueno que si ya tenemos el tocken almacenado en una variable de sesión, que esta ya no tuvuera que ser solicitada o validarla desde el code'
  • Por lo que el código anterior lo condicionaríamos a ello
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $cliente->setAccessToken($_SESSION['access_token']);
} else {
       if (!isset($_GET['code'])) {
        //Si tenemos token lo usamos para que la aplicación acceda a los datos en nombre de un usuario
         $auth_url = $cliente->createAuthUrl();
         header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
       } else {
             $cliente->authenticate($_GET['code']);
             $_SESSION['access_token'] = $cliente->getAccessToken();
  }
  • El tocken normalmente tiene una hora de validez, luego caduca
  • Para verificar si el tocken está caducado se emplea el método
$cliente->isAccessTokenExpired();
  • Este método retornará true si está validado
  • No voy a controlar esto en el código que os aporto, podéis mirar las páginas facilitadas por Carlos Pérez Marín
Referencias en la web
  1. https://github.com/google/google-api-php-client/issues/213
  2. http://stackoverflow.com/questions/15905104/automatically-refresh-token-using-google-drive-api-with-php-script
  3. https://www.igorkromin.net/index.php/2015/05/21/example-of-using-the-google-plus-oauth-refresh-token/
  4. http://stackoverflow.com/questions/10827920/google-oauth-refresh-token-is-not-being-received
  5. https://www.igorkromin.net/index.php/2015/05/21/example-of-using-the-google-plus-oauth-refresh-token/

La parte de html

Primero aportamos el css

  • A continuación editamos el fichero de estilo css
@charset "utf-8";
body {
	font: 100%/1.4 Verdana, Arial, Helvetica, sans-serif;
	background: #699;
	margin: 0;
	padding: 0;
	color: #000;
}
 
h1, h2, h3, h4, h5, h6  {
	margin-top: 0;
	padding-left: 15px;
}
 
a:link {
	color:#414958;
	text-decoration: underline;
}
a:visited {
	color: #4E5869;
	text-decoration: underline;
}
a:hover, a:active, a:focus {
	text-decoration: none;
}
 
.accion  {
	font-size: x-small;
}
 
.contenedor {
	min-width: 780px;
	background: #FFF;
	margin: 0 auto;
}
 
.encabezado {
	padding-top: 10px;
	background-color: #699;
}
 
.contenido {
	padding: 10px 0;
}
 
.contenido ul { 
	padding: 0 15px 15px 40px; 
        margin: 0;
}
 
.pie {
        color: #F00;
	padding: 10px 0;
	background: #699;
	position: relative;
	clear: both;
}
.titulo {
	padding-top: 5px;
	padding-right: 10px;
	padding-bottom: 0px;
	padding-left: 20px;
	font-size: large;
	font-weight: bold;
}
 
.clearfloat {
	clear:both;
	height:0;
	font-size: 1px;
	line-height: 0px;
}
#dialogo {
	display:none;
	position:fixed;
	_position:absolute; /* para IE6*/
	height:340px;
	width:408px;
	background:#FFFFFF;
	border:2px solid #cecece;
	z-index:2;
	padding:12px;
	font-size:13px;
}
h1  {
	color:#039;
	font-size:24px;
	font-weight:700;
	padding-bottom:2px;
}
 
#cerrarDialogo {
	font-size:14px;
	line-height:14px;
	right:6px;
	top:4px;
	position:absolute;
	color:#6fa5fd;
	font-weight:700;
	display:block;
	cursor: pointer;
	text-decoration:none;
}
 
#fondonegro {
	display:none;
	position:fixed;
	_position:absolute; /* para IE6*/
	height:100%;
	width:100%;
	top:0;
	left:0;
	background:#000000;
	border:1px solid #cecece;
	z-index:1;
}

El código html

  • Ahora hacemos la parte de html
  • Empezamos haciendo la parte de repartos
  • Simplemente una página que contenga un botón para dar de alta una lista de repartos
  • Posteriormente añadiremos para cada lista de repartos los repartos que contienen
  • Vamos a decidir insertar para cada posible acción en un formulario un texto oculto llamado accion (name) y como value la acción que queremos hacer
  • En el siguiente código en el formulario empezamos por la acción nuevalista
<!DOCTYPE html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Ejemplo Tema 8: Rutas de reparto</title>
    <link href="estilos.css" rel="stylesheet" type="text/css" />
    </head>
<body>
    <div class="contenedor">
        <div class="encabezado">
            <h1>Ejemplo Tema 8: Rutas de reparto</h1>
            <form id="nuevoreparto" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
                <fieldset>
                    <input type='hidden' name='accion' value='nuevalista' />
                    <input type='submit' id='crearnuevotitulo' value='Crear Nueva Lista de Reparto' />
                    <label for='nuevotitulo' >Fecha de reparto:</label>
                    <input type='text' name='fechaReparto' id='fechaReparto' />
                </fieldset>
            </form>
        </div>
        <div class="contenido">
        </div>
        <div class="pie">
            <?php print $error; ?>
        </div>
    </div>
</body>
</html>

Usando los servicios de api

  • Ahora ya viene la parte de utilizar los métodos del api de google
  • Cuando nosotros generemos la accion nueva lista querremos dar de alta una nueva lista en la task del usuario que está usando nuestra aplicación y que ha dado permiso a la aplicación mediante un token para que en su nombre acceda y pueda modificar esos datos

Definimos objetos de cada servicio API que queremos utilizar

 
//Objeto con el api que queremos trabajar en este caso task
$apiTareas= new Google_Service_Tasks($cliente);
 
//Objeto con el api que queremos trabajar con el calendario
$apiCalendario = new Google_Service_Calendar($cliente);
  • En función de que hayamos seleccionado haremos una cosa u otra
//Si ejecutamos el fichero habiendo dando al botón de un formulario llamado accion
if (isset($_GET['accion'])){
    switch ($_GET['accion']) {
          case 'nuevalista':
            //Si no está vacío el titulo creamos una nueva lista de reparto
            break;
          case 'nuevatarea':
            break;
          case 'borrarlista':
            break;
          case 'borrartarea':
             break;
     }//end switch... accion
  }//end isset...accion
?>
A continuación vamos a implementar el código asociado a cada una de las acciones, y vamos verificando que dicha acción se ha realizado correctamente

Nueva Lista

  • En el cliente se nos facilita una fecha
  • A partir de ella (la validamos), creamos un evento en el calendario que vaya desde las 9 horas de la mañana hasta las 20 horas de la tarde
  • Una vez creado este evento creamos una nueva lista de tareas con el nombre Repartos y fecha aportada
Creando un evento en el calendario
  • Para ello debemos usar los objetos de las clases event como se puede ver en el código siguiente
 ......
 case 'nuevalista':
                if (!empty($_GET['fechaReparto'])) {
                    // Crear una nueva lista de reparto
                    try {
                        // Vamos a analizar la fecha que obtememos a ver si es válida
                        $fecha = explode("/", $_GET['fechaReparto']);
                        if (count($fecha) == 3 && checkdate($fecha[1], $fecha[0], $fecha[2])) {
                            // La fecha es correcta creamos la entrada en Calendar
                            // Insertar evento
                            $evento = new Google_Service_Calendar_Event();
                            $evento->setSummary("Reparto");
                            // hora de comienzo
                            $comienzo = new Google_Service_Calendar_EventDateTime();
                            $comienzo->setDateTime("$fecha[2]-$fecha[1]-$fecha[0]T09:00:00.000");
                            $comienzo->setTimeZone("Europe/Madrid");
                            $evento->setStart($comienzo);
                            // hora de terminación
                            $final = new Google_Service_Calendar_EventDateTime();
                            $final->setDateTime("$fecha[2]-$fecha[1]-$fecha[0]T20:00:00.000");
                            $final->setTimeZone("Europe/Madrid");
                            $evento->setEnd($final);
                            $createdEvent = $calendario->events->insert('primary', $evento);
                        } else {
                            // La fecha está mal
                            throw new Exception("Fecha incorrecta");
                        }
//Ahora creamos la nueva lista
                        $nuevalista = new TaskList();
                        $nuevalista->setTitle("Reparto " . $_GET['fecha']);
                        $tareas->tasklists->insert($nuevalista);
                    } catch (Exception $e) {
                        $error = "Se ha producido un error al intentar crear un nuevo reparto. " . $e->getMessage();
                    }
                }
                break;
  • Una vez que hemos creado la lista, vamos a hacer que en el código nos aparezcan todas las listas de tareas que tenemos en nuestra agenda de listas de tareas
  • Para ello podemos usar el obejeto de la clase
//Defino un objeto para manejar la lista de tareas
$tareas = new Google_Service_Tasks($cliente);

Y con él recorre su estructura

  • Es un array asociativo donde hay un elemento que contiene el nombre de la lista y un identificador
             <div class="contenido">
              <?php
                $repartos = $tareas->tasklists->listTasklists();
                // Para cada lista de reparto
                foreach ($repartos['items'] as $reparto) {
                    echo '<span class="titulo">' . $reparto['title'] . '</span>';
                    echo "<br />";
                }
                ?>
             </div>

Nueva Envío

  • Cada lista va a constar de una serie de envíos
  • Para ello vamos a implementar un nuevo envío o la acción de una nueva tarea dentro de la lista de tareas
  • Primero añadimos el botón correspondiente en el cliente
  • Una nueva tarea es un nuevo reparto
  • Un reparto necesita una coordenadas para localizarla.
  • Para ello usaremos una ventana de localización y usaremos google maps

HibridaMaps.png

  • Esta ventana queremos que sea una ventana modal que tengamos en nuestra aplicación
   <div id="dialogo">
        <a id="cerrarDialogo" onclick="ocultarDialogo();">x</a>
        <h1>Datos del nuevo envío</h1>
        <form id="formenvio" name="formenvio" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
            <fieldset>
                <div id="datosDireccion">
                    <p>
                        <label for='direccion' >Dirección:</label>
                        <input type='text' size="45" name='direccion' id='direccion' />
                    </p>
                    <input type='button' id='obtenerCoordenadas' value='Obtener coordenadas' onclick="getCoordenadas();"/><br />
                </div>
                <div id="datosEnvio">
                    <p>
                        <label for='latitud' >Latitud:</label>
                        <input type='text' size="10" name='latitud' id='latitud' />
                    </p>
                    <p>
                        <label for='longitud' >Longitud:</label>
                        <input type='text' size="10" name='longitud' id='longitud' />
                    </p>
                    <p>
                        <label for='nuevotitulo' >Título:</label>
                        <input type='text' size="40" name='nuevotitulo' id='titulo' />
                    </p>
                    <input type='hidden' name='accion' value='nuevatarea' />
                    <input type='hidden' name='idreparto' id='idrepartoactual' />
                    <input type='submit' id='nuevoEnvio' value='Crear nuevo Envío' />
                    <a href="#" onclick="abrirMaps();">Ver en Google Maps</a><br />
                </div>
            </fieldset>
        </form>
    </div>  <!-- end div dialogo-->
  • La podremos al principio de la página html
  • Para abrir esta ventana u ocultarla usaremos javascript
  • Ahora sí que necesitmos meter código de ajax para que esto funcione
  • Este formulario tiene el botón que nos hará crear una nueva tarea, pero antes vamos a ver como visualizar este formulario y veremos también la llamada a Ver en Google Maps

  • En cada Lista de tareas vamos a poner un botón para abrir esta ventana de diálogo
  • Agregaremos para cada lista un botón de nuevo reparto
  • Como vamos a hacerlo por , usamos el envento onclick()
echo '<span class="accion">(<a href="#" onclick="nuevoEnvio();">Nuevo Envío</a>)</span>';
  • Tenemos un fichero codigo.js donde vamos a ir metiendo el código de javascript
  • La función nuevo envío básicamente va a abrir la ventana de diálogo para aportar los datos del nuevo envío
// Indica si se está mostrando o no el diálogo de dirección / coordenadas
//  para la introducción de un nuevo envío
var estadoDialogo = false;
 
 
function nuevoEnvio(idReparto) {
    $('#idrepartoactual').val(idReparto);
    mostrarDialogo();
}
 
 
function mostrarDialogo() {
//Centramos en pantalla
var anchoVentana = document.documentElement.clientWidth;
var altoVentana = document.documentElement.clientHeight;
var altoDialogo = $("#dialogo").height();
var anchoDialogo = $("#dialogo").width();
 
    $("#dialogo").css({
        "position": "absolute",
        "top": altoVentana/2-altoDialogo/2,
        "left": anchoVentana/2-anchoDialogo/2
    });
 
    //Para IE6
    $("#fondonegro").css({"height": altoVentana});
 
    //Si no está visible el diálogo
    if(!estadoDialogo){
        // Se muestra el fondo negro
        $("#fondonegro").css({"opacity": "0.7"});
        $("#fondonegro").fadeIn("slow");
        //  y el diálogo
        $("#dialogo").fadeIn("slow");
 
        $("#datosenvio").hide();
        estadoDialogo = true;
    }
}
  • A la vez tendremos que tener la función ocultar diálogo
function ocultarDialogo() {
    // Si está visible
    if(estadoDialogo){
        // Se oculta el fondo y el diálogo
        $("#fondonegro").fadeOut("slow");
        $("#dialogo").fadeOut("slow");
        estadoDialogo = false;
    }
}
  • Debemos especificar que vamos a usar javascript
  • También, para facilitar las cosas, vamos a usar el framework de java script JQuery
    <script type="text/javascript" src="codigo.js"></script>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
  • Ahora vamos a ver cómo obtener las coordenadas de una posicion usando la api de google Maps
  • Esta es una api que es importante de estudiar por vuestra cuenta
  • En nuestro caso vamos a usar ajax para obtener coordenadas
  • Para ello primero incluimos la librería de xajax para incorporar ajax en nuestro proyecto
// Creamos el objeto xajax
$xajax = new xajax('ajaxmaps.php');
 
// Configuramos la ruta en que se encuentra la carpeta xajax_js
//$xajax->configure('javascript URI', 'http://localhost/Repartos/libs/');
 
// Y registramos las funciones que vamos a llamar desde JavaScript
//Estas funciones vienen implementadas en el fichero facilitado '''''ajaxmaps.php'''''
$xajax->register(XAJAX_FUNCTION, "obtenerCoordenadas");
  • En el código html escribimos el código javascript en el cliente

<sourece lang=php> <?php // Le indicamos a Xajax que incluya el código JavaScript necesario $xajax->printJavascript(); ?> </source>

  • El código de las funciones en el servidor las escribimos en el fichero que le pasamos a la instacia del objeto $xajax ajaxmaps.php
<?php
/**
 
 */
 
// No aseguramos que se usa UTF-8
mb_internal_encoding("UTF-8");
 
// Incluimos la lilbrería Xajax
require_once("lib/xajax_core/xajax.inc.php");
 
// Creamos el objeto xajax
$xajax = new xajax();
 
// Y registramos la función que vamos a llamar desde JavaScript
$xajax->register(XAJAX_FUNCTION,"obtenerCoordenadas");
$xajax->register(XAJAX_FUNCTION,"ordenarReparto");
 
// El método processRequest procesa las peticiones que llegan a la página
// Debe ser llamado antes del código HTML
$xajax->processRequest();
 
function obtenerCoordenadas($parametros)
{
    $respuesta = new xajaxResponse();
    $search = 'http://maps.google.com/maps/api/geocode/xml?address='.$parametros['direccion'].'&sensor=false&appid=z9hiLa3e';
    $xml = simplexml_load_file($search);
    // latitud
    $latitud = (string) $xml->result[0]->geometry->location->lat;
    $longitud = (string) $xml->result[0]->geometry->location->lng; 
    // Para obtener la elevación
    $urlElevacion = "https://maps.googleapis.com/maps/api/elevation/xml?locations=".$latitud.",".$longitud."&sensor=false&key=AIzaSyBT-lkJm_puGvwbii42fXqaeyVToenZRDw";
    $xmlElevacion = simplexml_load_file($urlElevacion);
 
    $elevacion = (string) $xmlElevacion->result[0]->elevation;
 
    //$respuesta->assign("latitud", "value", (string) $xml->result[0]->geometry->location->lat);
    //$respuesta->assign("longitud", "value", (string) $xml->result[0]->geometry->location->lng);
 
    $respuesta->assign("latitud", "value", $latitud);
    $respuesta->assign("longitud", "value", $longitud);
    $respuesta->assign("elevacion", "value", $elevacion);
 
    $respuesta->assign("obtenerCoordenadas","value","Obtener coordenadas y elevación");
    $respuesta->assign("obtenerCoordenadas","disabled",false); 
 
    return $respuesta;
}
 
?>
La parte del cliente
  • Ahora nos queda invocar a esta función desde el cliente
  • Esto lo haremos en el formulario de la ventana de dialogo obtener Coordenadas
  • Este botón llamará al método javascript getCoordenadas implementado en el fichero código.js
function getCoordenadas() {
    // Comprobamos que se haya introducido una dirección
    if($("#direccion").val().length < 10) {
        alert("Introduzca una dirección válida.");
        return false;
    }
 
    // Se cambia el botón de Enviar y se deshabilita
    //  hasta que llegue la respuesta
    xajax.$('obtenerCoordenadas').disabled=true;
    xajax.$('obtenerCoordenadas').value="Un momento...";
 
    // Aquí se hace la llamada a la función registrada de PHP
    xajax_obtenerCoordenadas (xajax.getFormValues("formenvio"));
 
    return false;    
}
  • Y ahora miramos lo que hace el método obtenerCoordenadas en php, el cual recibe los datos de las coordenadas
  • Lo que hace es una solicitud REST a google pasándoles las coordenadas
function obtenerCoordenadas($parametros)
{
    $respuesta = new xajaxResponse();
    $search = 'http://maps.google.com/maps/api/geocode/xml?address='.$parametros['direccion'].'&sensor=false&appid=z9hiLa3e';
    $xml = simplexml_load_file($search);
    // latitud
    $latitud = (string) $xml->result[0]->geometry->location->lat;
    $longitud = (string) $xml->result[0]->geometry->location->lng; 
    // Para obtener la elevación
    $urlElevacion = "https://maps.googleapis.com/maps/api/elevation/xml?locations=".$latitud.",".$longitud."&sensor=false&key=AIzaSyBT-lkJm_puGvwbii42fXqaeyVToenZRDw";
    $xmlElevacion = simplexml_load_file($urlElevacion);
 
    $elevacion = (string) $xmlElevacion->result[0]->elevation;
 
    //$respuesta->assign("latitud", "value", (string) $xml->result[0]->geometry->location->lat);
    //$respuesta->assign("longitud", "value", (string) $xml->result[0]->geometry->location->lng);
 
    $respuesta->assign("latitud", "value", $latitud);
    $respuesta->assign("longitud", "value", $longitud);
    $respuesta->assign("elevacion", "value", $elevacion);
 
    $respuesta->assign("obtenerCoordenadas","value","Obtener coordenadas y elevación");
    $respuesta->assign("obtenerCoordenadas","disabled",false); 
 
    return $respuesta;
}
  • En respuesta pasamos los valores de las coordenadas
  • En caso de querer acceder a Maps para obtener las coordenadas, se ha implementado un botón en la propia ventana de diálogo Ver en Google Maps
  • Este botón ejecuta el método abrirMaps() de javaScript que lo único que hace es abrir una nueva ventana de google Maps
function abrirMaps(coordenadas) {
    var url = "http://maps.google.com/maps?hl=es&t=h&z=17&output=embed&ll=";
 
    if(!coordenadas) {
        // Cogemos las coordenadas del diálogo
        url+=$("#latitud").val()+","+$("#longitud").val();
    }
    else {
        // Si hay coordenadas, las usamos
        url+=coordenadas;
    }
 
    window.open(url,'nuevaventana','width=425,height=350');
}
  • Ahora tenemos que terminar de implementar la acción de nuevo reparto. Ya tenemos las coordenadas, ahora debemos usar el api de google para crear este nuevo reparto
  • Necesitamos tener el identificador de la lista de tareas para incorporar esa tarea en la lista de tareas
  • Para ello recogemos el dato cuando solicitamos una nueva tarea y se lo pasamos a la función nuevoEnvio de javaScritp
function nuevoEnvio(idReparto) {
    $('#idrepartoactual').val(idReparto);
    mostrarDialogo();
}
  • Para poder acceder a esta información debemos guardarla cuando hacemos un listado de todas las listas de tareas en un input de tipo hidden, y lo pasaremos como parámetro al nueva envío
  • quedaría de la siguiente manera


      echo '<div id="' . $reparto['id'] . '">';
      echo '<span class="titulo">' . $reparto['title'] . '</span>';
      $idreparto = "'" . $reparto['id'] . "'";
      echo '<span class="accion">(<a href="#" onclick="nuevoEnvio(' . $idreparto . ');">Nuevo Envío</a>)</span>';
      echo "</div>"
  • Y ahora nos quedaría visualizar los repartos que tenemos en cada lista de repartos
  • De esta forma podremos visualizar los repartos de cada lista de repartos
 print '<ul>';
                // Cogemos de la lista de reparto las tareas de envío
                $envios = $apiTareas->tasks->listTasks($reparto['id']);
                // Por si no hay tareas de envío en la lista
                if (!empty($envios['items'])) {
                    foreach ($envios['items'] as $envio) {
                        // Creamos un elemento para cada una de las tareas de envío
                        $idenvio = "'" . $envio['id'] . "'";
                        echo '<li title="' . $envio['notes'] . '" id="' . $idenvio . '">' . $envio['title'] . ' (' . $envio['notes'] . ')';
                        $coordenadas = "'" . $envio['notes'] . "'";
                        echo '<span class="accion">  (<a href="#" onclick="abrirMaps(' . $coordenadas . ');">Ver mapa</a>)</span>';
                        echo '<span class="accion">  (<a href="' . $_SERVER['PHP_SELF'] . '?accion=borrartarea&reparto=' . $reparto['id'] . '&envio=' . $envio['id'] . '">Borrar</a>)</span>';
                        echo '</li>';
                    }
                }
                print '</ul>';
                print '</div>';
            }
La parte del servidor
  • Ahora que tenemos hecho lo del cliente, vamos a ver como se comporta el servidor
  • El servidor va a reaccionar ante una solicitud GET de nuevaTarea
  • Por lo que actuaremos en el switch-case de $_GET
//Si ejecutamos el fichero habiendo dando al botón de un formulario llamado accion
if (isset($_GET['accion'])) {
    switch ($_GET['accion']) {
        case 'nuevalista':
            //Si no está vacío el titulo creamos una nueva lista de reparto
            if (!empty($_GET['fechaReparto'])) {
                // Crear una nueva lista de reparto
 
            break;
        case 'nuevatarea':
            //De la ventana de diálogo cogemos el nuevo título 
            //El ide de la lista de repartos la cogemos de un hidden que tenemos en la lista de repartos
            if (!empty($_GET['nuevotitulo']) && !empty($_GET['idreparto']) && !empty($_GET['latitud']) && !empty($_GET['longitud'])) {
                // Crear una nueva tarea de envío
                try {
                    $nuevatarea = new Google_Service_Tasks_Task();
                    $nuevatarea->setTitle($_GET['nuevotitulo']);
                    if (isset($_GET['direccion']))
                        $nuevatarea->setTitle($_GET['nuevotitulo'] . " - " . $_GET['direccion']);
                    else
                        $nuevatarea->setTitle($_GET['nuevotitulo']);
                    $nuevatarea->setNotes($_GET['latitud'] . "," . $_GET['longitud']);
                    // Añadimos la nueva tarea de envío a la lista de reparto
                    $tarea->tasks->insert($_GET['idreparto'], $nuevatarea);
                } catch (Exception $e) {
                    $error = "Se ha producido un error al intentar crear un nuevo envío.";
                }
            }
            break;
        case 'borrarlista':
           //Pendiente de desarrollararea':            break;
    }//end switch... accion
}//end isset...accion


Borrar una lista de envíos

  • Esta parte es muy sencilla
  • Recordemos que tenemos el objeto de la clase TaskList que gestiona las listas que tengo en mi tareas
$tareas = new Google_Service_Tasks($cliente);
  • Ahora si he establecido hacer esta acción, la realizo
 //.........
   case 'borrarlista':
            if (!empty($_GET['reparto'])) {
                // Borrar una lista de reparto
                try {
                    $tareas->tasklists->delete($_GET['reparto']);
                } catch (Exception $e) {
                    $error = "Se ha producido un error al intentar borrar el reparto.";
                }
            }
            break;
//.......

Borrar un envío

  • Borar un envío es borrar una tarea dentro de una tarea de listas
  • Es igual de sencillo que borrar una lista de tareas
  • Al igual que en el caso anterior usamos el objeto con el que gestionamos nuestras listas de tareas
  • Debemos tener el identificador de la lista y el identificador de la tarea o envío que queremos eliminar
  • Después con el método delete procedemos a eliminarlo
$tareas = new Google_Service_Tasks($cliente);
  • Ahora si he establecido hacer esta acción, la realizo
 //.........
      case 'borrartarea':
            if (!empty($_GET['reparto']) && !empty($_GET['envio'])) {
                // Borrar una tarea de envío
                try {
                    $tareas->tasks->delete($_GET['reparto'], $_GET['envio']);
                } catch (Exception $e) {
                    $error = "Se ha producido un error al intentar borrar el envío.";
                }
            }
            break;

Ver un envío en el mapa

  • Este botón lo añadimos junto con cada envío o tarea que damos de alta
  • En el atributo notes tenemos almacenada la información de las coordenadas del envío
  • El botón lo ponemos junto con la posibilidad de borrar la tarea y el nombre de la misma
TareaAbrirMapa.png
foreach ($envios['items'] as $envio) {
                        // Creamos un elemento para cada una de las tareas de envío
                        $idenvio = "'" . $envio['id'] . "'";
                        print '<li title="' . $envio['notes'] . '" id="' . $idenvio . '">' . $envio['title'] . ' (' . $envio['notes'] . ')';
                        $coordenadas = "'" . $envio['notes'] . "'";
                        print '<span class="accion">  (<a href="#" onclick="abrirMaps(' . $coordenadas . ');">Ver mapa</a>)</span>';
                        print '<span class="accion">  (<a href="' . $_SERVER['PHP_SELF'] . '?accion=borrartarea&reparto=' . $reparto['id'] . '&envio=' . $envio['id'] . '">Borrar</a>)</span>';
                        print '</li>';
                    }
  • Ahora vamos a ver la acción que hacemos en la función de javascript abrirMaps
function abrirMaps(coordenadas) {
    var url = "http://maps.google.com/maps?hl=es&t=h&z=17&output=embed&ll=";
 
    if(!coordenadas) {
        // Cogemos las coordenadas del diálogo
        url+=$("#latitud").val()+","+$("#longitud").val();
    }
    else {
        // Si hay coordenadas, las usamos
        url+=coordenadas;
    }
 
    window.open(url,'nuevaventana','width=425,height=350');
}

Ordenar la lista de envíos

  • Este es una acción un poco complicada.
  • Usamos una función de javaScript con jquery, una llamada síncrona y luego código php para que quede reflejado el nuevo orden
  • Por un lado cuando hacemos un click en ordenar la lista en una lista de reparto, vamos a ejecutar una función en javascript según se identifica
  • En la parte del código que ponemos cada lista de reparto añadimos el botón ordenar Reparto
  • Pongo código delante y detrás para que vemos la ubicación concreta
/....
 <?php
            $repartos = $tareas->tasklists->listTasklists();
            // Para cada lista de reparto
            foreach ($repartos['items'] as $reparto) {
                    $idreparto = "'" . $reparto['id'] . "'";
                    print '<span class="accion">(<a href="#" onclick="ordenarReparto(' . $idreparto . ');">Ordenar</a>)</span>';
                    print '<span class="accion">(<a href="#" onclick="nuevoEnvio(' . $idreparto . ');">Nuevo Envío</a>)</span>';
.......
  • Ahora vamos a ver el código de la función ordenaReparto(...) con el contenido explicado
function ordenarReparto(idReparto) {
    // Utilizamos jQuery para obtener una lista con las coordenadas de los puntos intermedios que debemos ordenar
    // También se podrían haber almacenado por ejemplo en la sesión del usuario
    var paradas = $('#'+idReparto+' li').map(function() {
        return this.title;
    }).get().join('|');
 
    // Esta vez utilizamos el modo síncrono (esperamos a obtener una respuesta)
    var respuesta = xajax.request({xjxfun:"ordenarReparto"}, {mode:'synchronous', parameters: [paradas]});
    if (respuesta) {
        // Si obtuvimos una respuesta, reordenamos los envíos del reparto
        // Cogemos la URL base del documento, quitando los parámetros GET si los hay
        var url = document.location.href.replace(/\?.*/,'');
		url = url.replace(/#$/,'');
        // Añadimos el código de la lista de reparto
        url += '?accion=ordenarEnvios&reparto='+idReparto;
        // Y un array con las nuevas posiciones que deben ocupar los envíos
        for(var r in respuesta) url += '&pos[]='+respuesta[r];
 
        window.location = url;
    }
}
  • Y ahora quedaría la parte de php
  • Observamos que la página con los parámetros get para esta parte de php no vienen de un formulario, sino del contenido del código de este método
  • En lugar de explicar aquí lo que se hace, se aportan en el código los comentarios necesarios para entender claramente lo que hace el código
/...
  case 'ordenarEnvios':
            if (!empty($_GET['reparto']) && !empty($_GET['pos'])) {
                // Reordenar las tareas de envío según el orden que se recibe en el array 'pos'
                try {
                    // Primero obtenemos todas las tareas de la lista de reparto
                    $tareas = $tareas->tasks->listTasks($_GET['reparto']);
                    // Y después las movemos según la posición recibida en el array 'pos'
                    // El array 'pos' indica la posición que debe tener cada tarea de la lista
                    // $pos[0] = 3 significa que la 1ª tarea (la de índice 0)
                    // debe ponerse en la 4ª posición (la de índice 3)
                    // 
                    // Lo convertimos en el array 'orden' que contiene las tareas que debe haber
                    //  en cada posición de la lista
                    // $orden[3] = 0 significa que en la 4ª posición debemos poner la 1ª tarea 
                    $orden = array_flip($_GET['pos']);
 
                    // Recorremos el array en orden inverso, esto es, empezando por la tarea
                    //  que debería figurar en última posición de la lista
                    // En cada paso ponemos una tarea en la primera posición de la lista
                    for ($i = count($orden) - 1; $i >= 0; $i--)
                        $tareas->tasks->move($_GET['reparto'], $tareas['items'][$orden[$i]]['id']);
                } catch (Exception $e) {
                    $error = "Se ha producido un error al intentar ordenar los envíos del reparto.";
                }
            }
            break;