TigerZF
🌐Español

37.6. Uso de Google Calendar

Puede usar la clase Zend_Gdata_Calendar para ver, crear, actualizar y eliminar eventos en el servicio en línea de Google Calendar.

Consulte http://code.google.com/apis/calendar/overview.html para obtener más información sobre la API de Google Calendar.

37.6.1. Conexión con el servicio de Calendar

La API de Google Calendar, como todas las APIs de GData, está basada en el Atom Publishing Protocol (APP), un formato basado en XML para gestionar recursos basados en web. El tráfico entre un cliente y los servidores de Google Calendar se produce a través de HTTP y permite tanto conexiones autenticadas como no autenticadas.

Antes de que puedan producirse transacciones, es necesario establecer esta conexión. Crear una conexión con los servidores de calendario implica dos pasos: crear un cliente HTTP y enlazar una instancia del servicio Zend_Gdata_Calendar a ese cliente.

37.6.1.1. Autenticación

La API de Google Calendar permite el acceso tanto a feeds de calendario públicos como privados. Los feeds públicos no requieren autenticación, pero son de solo lectura y ofrecen una funcionalidad reducida. Los feeds privados ofrecen la funcionalidad más completa pero requieren una conexión autenticada a los servidores de calendario. Hay tres esquemas de autenticación admitidos por Google Calendar:

  • ClientAuth proporciona autenticación directa mediante nombre de usuario/contraseña con los servidores de calendario. Dado que este esquema requiere que los usuarios proporcionen a su aplicación su contraseña, esta autenticación solo se recomienda cuando los demás esquemas de autenticación resultan insuficientes.

  • AuthSub permite la autenticación con los servidores de calendario a través de un servidor proxy de Google. Esto proporciona el mismo nivel de comodidad que ClientAuth pero sin el riesgo de seguridad, lo que lo convierte en una opción ideal para aplicaciones basadas en web.

  • MagicCookie permite la autenticación basada en una URL semialeatoria disponible desde la interfaz de Google Calendar. Este es el esquema de autenticación más sencillo de implementar, pero requiere que los usuarios recuperen manualmente su URL segura antes de poder autenticarse, no proporciona acceso a las listas de calendario y está limitado al acceso de solo lectura.

La biblioteca Zend_Gdata proporciona soporte para los tres esquemas de autenticación. El resto de este capítulo asumirá que está familiarizado con los esquemas de autenticación disponibles y con cómo crear una conexión autenticada adecuada. Para obtener más información, consulte la sección Autenticación de este manual o la Descripción general de autenticación en la Guía del desarrollador de la API de Google Data.

37.6.1.2. Creación de una instancia del servicio

Para interactuar con Google Calendar, esta biblioteca proporciona la clase de servicio Zend_Gdata_Calendar. Esta clase proporciona una interfaz común a los modelos de Google Data y Atom Publishing Protocol y ayuda a organizar las peticiones hacia y desde los servidores de calendario.

Una vez decidido el esquema de autenticación, el siguiente paso es crear una instancia de Zend_Gdata_Calendar. El constructor de la clase acepta una instancia de Zend_Http_Client como único argumento. Esto proporciona una interfaz para la autenticación AuthSub y ClientAuth, ya que ambas requieren la creación de un cliente HTTP autenticado especial. Si no se proporciona ningún argumento, se creará automáticamente una instancia no autenticada de Zend_Http_Client.

El siguiente ejemplo muestra cómo crear una clase de servicio Calendar utilizando la autenticación ClientAuth:

// Parameters for ClientAuth authentication
$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
$user = "sample.user@gmail.com";
$pass = "pa$$w0rd";

// Create an authenticated HTTP client
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);

// Create an instance of the Calendar service
$service = new Zend_Gdata_Calendar($client);

Un servicio Calendar que utilice AuthSub se puede crear de forma similar, aunque un poco más extensa:

/*
 * Retrieve the current URL so that the AuthSub server knows where to
 * redirect the user after authentication is complete.
 */
function getCurrentUrl()
{
    global $_SERVER;

    // Filter php_self to avoid a security vulnerability.
    $php_request_uri =
        htmlentities(substr($_SERVER['REQUEST_URI'],
                            0,
                            strcspn($_SERVER['REQUEST_URI'], "\n\r")),
                            ENT_QUOTES);

    if (isset($_SERVER['HTTPS']) &&
        strtolower($_SERVER['HTTPS']) == 'on') {
        $protocol = 'https://';
    } else {
        $protocol = 'http://';
    }
    $host = $_SERVER['HTTP_HOST'];
    if ($_SERVER['HTTP_PORT'] != '' &&
        (($protocol == 'http://' && $_SERVER['HTTP_PORT'] != '80') ||
        ($protocol == 'https://' && $_SERVER['HTTP_PORT'] != '443'))) {
        $port = ':' . $_SERVER['HTTP_PORT'];
    } else {
        $port = '';
    }
    return $protocol . $host . $port . $php_request_uri;
}

/**
 * Obtain an AuthSub authenticated HTTP client, redirecting the user
 * to the AuthSub server to login if necessary.
 */
function getAuthSubHttpClient()
{
    global $_SESSION, $_GET;

    // if there is no AuthSub session or one-time token waiting for us,
    // redirect the user to the AuthSub server to get one.
    if (!isset($_SESSION['sessionToken']) && !isset($_GET['token'])) {
        // Parameters to give to AuthSub server
        $next = getCurrentUrl();
        $scope = "http://www.google.com/calendar/feeds/";
        $secure = false;
        $session = true;

        // Redirect the user to the AuthSub server to sign in

        $authSubUrl = Zend_Gdata_AuthSub::getAuthSubTokenUri($next,
                                                             $scope,
                                                             $secure,
                                                             $session);
         header("HTTP/1.0 307 Temporary redirect");

         header("Location: " . $authSubUrl);

         exit();
    }

    // Convert an AuthSub one-time token into a session token if needed
    if (!isset($_SESSION['sessionToken']) && isset($_GET['token'])) {
        $_SESSION['sessionToken'] =
            Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
    }

    // At this point we are authenticated via AuthSub and can obtain an
    // authenticated HTTP client instance

    // Create an authenticated HTTP client
    $client = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
    return $client;
}

// -> Script execution begins here <-

// Make sure that the user has a valid session, so we can record the
// AuthSub session token once it is available.
session_start();

// Create an instance of the Calendar service, redirecting the user
// to the AuthSub server if necessary.
$service = new Zend_Gdata_Calendar(getAuthSubHttpClient());

Por último, se puede crear un servidor no autenticado para usarlo con feeds públicos o con la autenticación MagicCookie:

// Create an instance of the Calendar service using an unauthenticated
// HTTP client

$service = new Zend_Gdata_Calendar();

Tenga en cuenta que la autenticación MagicCookie no se proporciona con la conexión HTTP, sino que se especifica junto con la visibilidad deseada al enviar las consultas. Consulte la sección sobre recuperación de eventos a continuación para ver un ejemplo.

37.6.2. Recuperación de una lista de calendarios

El servicio de calendario admite la recuperación de una lista de calendarios del usuario autenticado. Esta es la misma lista de calendarios que se muestra en la interfaz de usuario de Google Calendar, salvo que también están disponibles aquellos marcados como "ocultos".

La lista de calendarios siempre es privada y debe accederse a través de una conexión autenticada. No es posible recuperar la lista de calendarios de otro usuario y no se puede acceder a ella utilizando la autenticación MagicCookie. Si se intenta acceder a una lista de calendarios sin las credenciales adecuadas, la operación fallará y devolverá un código de estado 401 (Authentication Required).

$service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
$client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
$service = new Zend_Gdata_Calendar($client);

try {
    $listFeed= $service->getCalendarListFeed();
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

Al llamar a getCalendarListFeed() se crea una nueva instancia de Zend_Gdata_Calendar_ListFeed que contiene cada calendario disponible como una instancia de Zend_Gdata_Calendar_ListEntry. Tras recuperar el feed, puede utilizar el iterador y los accesores incluidos en el feed para inspeccionar los calendarios contenidos.

echo "<h1>Calendar List Feed</h1>";
echo "<ul>";
foreach ($listFeed as $calendar) {
    echo "<li>" . $calendar->title .
         " (Event Feed: " . $calendar->id . ")</li>";
}
echo "</ul>";

37.6.3. Recuperación de eventos

Al igual que la lista de calendarios, los eventos también se recuperan utilizando la clase de servicio Zend_Gdata_Calendar. La lista de eventos devuelta es de tipo Zend_Gdata_Calendar_EventFeed y contiene cada evento como una instancia de Zend_Gdata_Calendar_EventEntry. Al igual que antes, el iterador y los accesores incluidos en la instancia del feed de eventos permiten inspeccionar eventos individuales.

37.6.3.1. Consultas

Al recuperar eventos mediante la API de Calendar, se utilizan URLs de consulta especialmente construidas para describir qué eventos deben devolverse. La clase Zend_Gdata_Calendar_EventQuery simplifica esta tarea construyendo automáticamente una URL de consulta a partir de los parámetros proporcionados. Puede encontrar una lista completa de estos parámetros en la sección de consultas de la referencia de protocolo de las APIs de Google Data. Sin embargo, hay tres parámetros que merecen especial atención:

  • User se utiliza para especificar el usuario cuyo calendario se está buscando, y se especifica como una dirección de correo electrónico. Si no se proporciona ningún usuario, se utilizará "default" en su lugar para indicar al usuario actualmente autenticado (si está autenticado).

  • Visibility especifica si debe buscarse en el calendario público o privado de un usuario. Si se utiliza una sesión no autenticada y no hay ningún MagicCookie disponible, solo estará disponible el feed público.

  • Projection especifica cuántos datos debe devolver el servidor y en qué formato. En la mayoría de los casos querrá utilizar la proyección "full". También está disponible la proyección "basic", que coloca la mayoría de los metadatos en el campo de contenido de cada evento como texto legible por humanos, y la proyección "composite", que incluye el texto completo de cualquier comentario junto a cada evento. La vista "composite" suele ser mucho más grande que la vista "full".

37.6.3.2. Recuperación de eventos en orden por hora de inicio

El siguiente ejemplo ilustra el uso de la clase Zend_Gdata_Query y especifica el feed de visibilidad privada, lo que requiere que exista una conexión autenticada disponible con los servidores de calendario. Si se está utilizando un MagicCookie para la autenticación, la visibilidad debe establecerse en su lugar en "private-magicCookieValue", donde magicCookieValue es la cadena aleatoria obtenida al visualizar la dirección XML privada en la interfaz de Google Calendar. Los eventos se solicitan cronológicamente por hora de inicio y solo se devuelven los eventos que ocurren en el futuro.

$query = $service->newEventQuery();
$query->setUser('default');
// Set to $query->setVisibility('private-magicCookieValue') if using
// MagicCookie auth
$query->setVisibility('private');
$query->setProjection('full');
$query->setOrderby('starttime');
$query->setFutureevents('true');

// Retrieve the event list from the calendar server
try {
    $eventFeed = $service->getCalendarEventFeed($query);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

// Iterate through the list of events, outputting them as an HTML list
echo "<ul>";
foreach ($eventFeed as $event) {
    echo "<li>" . $event->title . " (Event ID: " . $event->id . ")</li>";
}
echo "</ul>";

Propiedades adicionales como ID, autor, when, estado del evento, visibilidad, contenido web, y contenido, entre otras, están disponibles dentro de Zend_Gdata_Calendar_EventEntry. Consulte la documentación de la API de Zend Framework y la Referencia del protocolo de Calendar para obtener una lista completa.

37.6.3.3. Recuperación de eventos en un rango de fechas específico

Para imprimir todos los eventos dentro de un rango determinado, por ejemplo desde el 1 de diciembre de 2006 hasta el 15 de diciembre de 2007, añada las dos líneas siguientes a la muestra anterior. Tenga cuidado de eliminar "$query->setFutureevents('true')", ya que futureevents anulará startMin y startMax.

$query->setStartMin('2006-12-01');
$query->setStartMax('2006-12-16');

Tenga en cuenta que startMin es inclusivo mientras que startMax es exclusivo. Como resultado, solo se devolverán los eventos hasta el 2006-12-15 23:59:59.

37.6.3.4. Recuperación de eventos mediante consulta de texto completo

Para imprimir todos los eventos que contengan una palabra específica, por ejemplo "dogfood", utilice el método setQuery() al crear la consulta.

$query->setQuery("dogfood");

37.6.3.5. Recuperación de eventos individuales

Los eventos individuales se pueden recuperar especificando su ID de evento como parte de la consulta. En lugar de llamar a getCalendarEventFeed(), debe llamarse a getCalendarEventEntry().

$query = $service->newEventQuery();
$query->setUser('default');
$query->setVisibility('private');
$query->setProjection('full');
$query->setEvent($eventId);

try {
    $event = $service->getCalendarEventEntry($query);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

De forma similar, si se conoce la URL del evento, se puede pasar directamente a getCalendarEntry() para recuperar un evento específico. En este caso, no se requiere ningún objeto de consulta ya que la URL del evento contiene toda la información necesaria para recuperarlo.

$eventURL = "http://www.google.com/calendar/feeds/default/private"
          . "/full/g829on5sq4ag12se91d10uumko";

try {
    $event = $service->getCalendarEventEntry($eventURL);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

37.6.4. Creación de eventos

37.6.4.1. Creación de eventos de ocurrencia única

Los eventos se añaden a un calendario creando una instancia de Zend_Gdata_EventEntry y rellenándola con los datos adecuados. La instancia del servicio de calendario (Zend_Gdata_Calendar) se utiliza entonces para convertir de forma transparente el evento a XML y enviarlo (POST) al servidor de calendario. Crear eventos requiere una conexión autenticada mediante AuthSub o ClientAuth con el servidor de calendario.

Como mínimo, deben establecerse los siguientes atributos:

  • Title proporciona el titular que aparecerá encima del evento dentro de la interfaz de Google Calendar.

  • When indica la duración del evento y, opcionalmente, los recordatorios asociados a él. Consulte la siguiente sección para obtener más información sobre este atributo.

Otros atributos útiles que se pueden establecer opcionalmente incluyen:

  • Author proporciona información sobre el usuario que creó el evento.

  • Content proporciona información adicional sobre el evento que aparece cuando se solicitan los detalles del evento desde dentro de Google Calendar.

  • EventStatus indica si el evento está confirmado, es provisional o está cancelado.

  • Transparency indica si el evento debe consumir tiempo en la lista de disponibilidad del usuario.

  • WebContent permite proporcionar enlaces a contenido externo dentro de un evento.

  • Where indica la ubicación del evento.

  • Visibility permite ocultar el evento de las listas de eventos públicas.

Para obtener una lista completa de los atributos de evento, consulte la documentación de la API de Zend Framework y la Referencia del protocolo de Calendar. Los atributos que pueden contener múltiples valores, como where, se implementan como arrays y deben crearse en consecuencia. Tenga en cuenta que todos estos atributos requieren objetos como parámetros. Intentar rellenarlos usando cadenas o valores primitivos dará como resultado errores durante la conversión a XML.

Una vez rellenado el evento, se puede cargar en el servidor de calendario pasándolo como argumento a la función insertEvent() del servicio de calendario.

// Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information
// Note that each attribute is crated as an instance of a matching class
$event->title = $service->newTitle("My Event");
$event->where = array($service->newWhere("Mountain View, California"));
$event->content =
    $service->newContent(" This is my awesome event. RSVP required.");

// Set the date using RFC 3339 format.
$startDate = "2008-01-20";
$startTime = "14:00";
$endDate = "2008-01-20";
$endTime = "16:00";
$tzOffset = "-08";

$when = $service->newWhen();
$when->startTime = "{$startDate}T{$startTime}:00.000{$tzOffset}:00";
$when->endTime = "{$endDate}T{$endTime}:00.000{$tzOffset}:00";
$event->when = array($when);

// Upload the event to the calendar server
// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

37.6.4.2. Horarios y recordatorios de eventos

La hora de inicio y la duración de un evento vienen determinadas por el valor de su propiedad when, que contiene las propiedades startTime, endTime, y valueString. StartTime y EndTime controlan la duración del evento, mientras que la propiedad valueString no se utiliza actualmente.

Los eventos de todo el día se pueden programar especificando solo la fecha y omitiendo la hora al establecer startTime y endTime. Del mismo modo, los eventos de duración cero pueden especificarse omitiendo endTime. En todos los casos, los valores de fecha y hora deben proporcionarse en el formato RFC3339.

// Schedule the event to occur on December 05, 2007 at 2 PM PST (UTC-8)
// with a duration of one hour.
$when = $service->newWhen();
$when->startTime = "2007-12-05T14:00:00-08:00";
$when->endTime="2007-12-05T15:00:00:00-08:00";

// Apply the when property to an event
$event->when = array($when);

El atributo when también controla cuándo se envían los recordatorios a un usuario. Los recordatorios se almacenan en un array y cada evento puede tener hasta cinco recordatorios asociados.

Para que un recordatorio sea válido, debe tener dos atributos establecidos: method y una hora. Method puede aceptar una de las siguientes cadenas: "alert", "email", o "sms". La hora debe introducirse como un entero y puede establecerse con la propiedad minutes, hours, days, o absoluteTime. Sin embargo, una solicitud válida solo puede tener uno de estos atributos establecido. Si se desea un tiempo mixto, conviértalo a la unidad más precisa disponible. Por ejemplo, 1 hora y 30 minutos deben introducirse como 90 minutos.

// Create a new reminder object. It should be set to send an email
// to the user 10 minutes beforehand.
$reminder = $service->newReminder();
$reminder->method = "email";
$reminder->minutes = "10";

// Apply the reminder to an existing event's when property
$when = $event->when[0];
$when->reminders = array($reminder);

37.6.4.3. Creación de eventos recurrentes

Los eventos recurrentes se crean de la misma forma que los eventos de ocurrencia única, salvo que debe proporcionarse un atributo de recurrencia en lugar de un atributo where. El atributo de recurrencia debe contener una cadena que describa el patrón de recurrencia del evento utilizando propiedades definidas en el estándar iCalendar (RFC 2445).

Las excepciones al patrón de recurrencia se suelen especificar mediante un atributo distinto recurrenceException. Sin embargo, el estándar iCalendar proporciona un formato secundario para definir recurrencias, y debe tenerse en cuenta la posibilidad de que se utilice cualquiera de los dos.

Debido a la complejidad de analizar los patrones de recurrencia, más información sobre este tema queda fuera del alcance de este documento. Sin embargo, se puede encontrar más información en la sección de elementos comunes de la guía del desarrollador de las APIs de Google Data, así como en RFC 2445.

 // Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information
// Note that each attribute is crated as an instance of a matching class
$event->title = $service->newTitle("My Recurring Event");
$event->where = array($service->newWhere("Palo Alto, California"));
$event->content =
    $service->newContent(' This is my other awesome event, ' .
                         ' occurring all-day every Tuesday from ' .
                         '2007-05-01 until 207-09-04. No RSVP required.');

// Set the duration and frequency by specifying a recurrence pattern.

$recurrence = "DTSTART;VALUE=DATE:20070501\r\n" .
        "DTEND;VALUE=DATE:20070502\r\n" .
        "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";

$event->recurrence = $service->newRecurrence($recurrence);

// Upload the event to the calendar server
// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

37.6.4.4. Uso de QuickAdd

QuickAdd es una funcionalidad que permite crear eventos utilizando texto libre. Por ejemplo, la cadena "Dinner at Joe's Diner on Thursday" crearía un evento con el título "Dinner", la ubicación "Joe's Diner" y la fecha "Thursday". Para aprovechar QuickAdd, cree una nueva propiedad QuickAdd establecida en TRUE y almacene el texto libre como una propiedad content.

// Create a new entry using the calendar service's magic factory method
$event= $service->newEventEntry();

// Populate the event with the desired information
$event->content= $service->newContent("Dinner at Joe's Diner on Thursday");
$event->quickAdd = $service->newQuickAdd("true");

// Upload the event to the calendar server
// A copy of the event as it is recorded on the server is returned
$newEvent = $service->insertEvent($event);

37.6.5. Modificación de eventos

Una vez obtenida una instancia de un evento, sus atributos se pueden modificar localmente de la misma forma que al crear un evento. Una vez completadas todas las modificaciones, llamar al método save() del evento cargará los cambios en el servidor de calendario y devolverá una copia del evento tal y como se creó en el servidor.

En caso de que otro usuario haya modificado el evento desde que se recuperó la copia local, save() fallará y el servidor devolverá un código de estado 409 (Conflict). Para resolver esto, debe recuperarse una copia actualizada del evento desde el servidor antes de intentar volver a enviar cualquier modificación.

// Get the first event in the user's event list
$event = $eventFeed[0];

// Change the title to a new value
$event->title = $service->newTitle("Woof!");

// Upload the changes to the server
try {
    $event->save();
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

37.6.6. Eliminación de eventos

Los eventos de calendario se pueden eliminar llamando al método delete() del servicio de calendario y proporcionando la URL de edición de un evento, o bien llamando al propio método delete() de un evento existente.

En cualquier caso, el evento eliminado seguirá apareciendo en el feed de eventos privado de un usuario si se proporciona un parámetro de consulta updateMin. Los eventos eliminados se pueden distinguir de los eventos normales porque su propiedad eventStatus se establecerá en "http://schemas.google.com/g/2005#event.canceled".

// Option 1: Events can be deleted directly
$event->delete();
// Option 2: Events can be deleted supplying the edit URL of the event
// to the calendar service, if known
$service->delete($event->getEditLink()->href);

37.6.7. Acceso a los comentarios de eventos

Cuando se utiliza la vista de evento completa, los comentarios no se almacenan directamente dentro de una entrada. En su lugar, cada evento contiene una URL a su feed de comentarios asociado, que debe solicitarse manualmente.

Trabajar con comentarios es fundamentalmente similar a trabajar con eventos, siendo la única diferencia significativa que debe utilizarse un feed y una clase de evento diferentes y que los metadatos adicionales de los eventos, como where y when, no existen para los comentarios. En concreto, el autor del comentario se almacena en la propiedad author, y el texto del comentario se almacena en la propiedad content.

// Extract the comment URL from the first event in a user's feed list
$event = $eventFeed[0];
$commentUrl = $event->comments->feedLink->url;

// Retrieve the comment list for the event
try {
$commentFeed = $service->getFeed($commentUrl);
} catch (Zend_Gdata_App_Exception $e) {
    echo "Error: " . $e->getMessage();
}

// Output each comment as an HTML list
echo "<ul>";
foreach ($commentFeed as $comment) {
    echo "<li><em>Comment By: " . $comment->author->name "</em><br/>" .
         $comment->content . "</li>";
}
echo "</ul>";