11
votes

So I want our work calendar to automatically sync with each employee's Google Calendar when the scheduling manager posts/updates the schedules. Users would initially opt-in using the AuthSub token, but after that it should be automatic. In order to avoid conflicts with other events they have scheduled, I want to create a new calendar called "Work App" or something else fairly unique. Then for updates, it would simply delete any events from that range before creating the new events. So I have some questions...

  1. How do I select the specific calendar I want using the API? (this all in PHP, by the way, using the Zend Framework). I see where I can query for the list of calendars, but the documentation doesn't show how to add to that specific calendar.

  2. Can I create calendars? Do I need to just have the users who opt in create such a calendar? If so, is there a URL I could generate for them to create one like there is for adding events? (Anything to make things simple and consistent, right?)

  3. I don't want users to store their credentials, obviously, but I also don't want to request access for each update. Do I need an OAuth token in order to have persistent access? I know that the URL token is one time use, but can I store session token and reuse it a week later?

  4. Is there a way other than querying for each event to avoid duplicates? I was testing this last night and I now have 7 instances of the same 50 events. I don't want to add to the server time with checking before each add.

  5. Finally, is there a way to add several events, or even to simply push the ics file to the calendar. Right now I have the script do a SQL query and add each event as it loops through the results. It seems to take much longer than expected, so just building either the ics file or adding all of the events to one object and adding them all at once would be better. Thanks!

2
I removed the google-app-engine tag, as I don't think you are using it at all.Peter Recore

2 Answers

26
votes

Well since no one answered, I decided to start poking around at the non-PHP documentation for the Google Calendar API, specifically at the .NET stuff and just a bit in the raw protocol. And wouldn't you know it...

If you go to the .NET documentation it mentions cool new features, specifically how to create new non-primary calendars for authenticated users and how to add events to non-primary calendars.

Of course, this documentation shows up nowhere in the PHP area, and there does not seem to be a one-to-one correlation. For the creating of the new calendar, I tried some obvious stuff first, then, going for broke, tried something not-so-obvious that worked. I thought I'd share in case the reason for the radio silence was that no one knew the answer but sure would like to.

To create a new calendar:

There are two keys to this:

  1. You have to use the same method for adding calendar events, which is insertEvent()

  2. You have to set the post URL in the method, which otherwise goes to the default feed URL.

This example checks to see if the App Calendar already exists and if not, creates it:

 //Standard creation of the HTTP client
 $gdataCal = new Zend_Gdata_Calendar($client);

 //Get list of existing calendars
 $calFeed = $gdataCal->getCalendarListFeed();

 //Set this to true by default, only gets set to false if calendar is found
 $noAppCal = true;

 //Loop through calendars and check name which is ->title->text
 foreach ($calFeed as $calendar) {
  if($calendar -> title -> text == "App Calendar") {
   $noAppCal = false;
  }
 }

 //If name not found, create the calendar
 if($noAppCal) {

  // I actually had to guess this method based on Google API's "magic" factory
  $appCal = $gdataCal -> newListEntry();
  // I only set the title, other options like color are available.
  $appCal -> title = $gdataCal-> newTitle("App Calendar"); 

  //This is the right URL to post to for new calendars...
  //Notice that the user's info is nowhere in there
  $own_cal = "http://www.google.com/calendar/feeds/default/owncalendars/full";

  //And here's the payoff. 
  //Use the insertEvent method, set the second optional var to the right URL
  $gdataCal->insertEvent($appCal, $own_cal);
 }

And there you have it. The next goal is to insert events to that calendar, not to the default calendar.

Adding events to non-primary calendar

The easy part that you can probably guess is that you need to set that optional URL again, like such : insertEvent($newEvent, $calURL), the tricky part is getting the calendar's URL. Unlike the "owned calendars" path, specific calendars not only have user-specifc info in it, they have some kind of hash-lookin' ID in there, too.

Here's the code:

 //Set up  that loop again to find the new calendar:
 $calFeed = $gdataCal->getCalendarListFeed();
 foreach ($calFeed as $calendar) {
  if($calendar->title->text == "App Calendar")
   //This is the money, you need to use '->content-src'
   //Anything else and you have to manipulate it to get it right. 
   $appCalUrl = $calendar->content->src;
 }

 //.......... Some Assumed MySQL query and results .............

      while ($event = $result->fetch_assoc()) {
   $title = $event['description'];

   //Quick heads up
   //This is a handy way of getting the date/time in one expression.
   $eventStart = date('Y-m-d\TH:i:sP', strtotime($event['start']));
   $eventEnd = date('Y-m-d\TH:i:sP', strtotime($event['end']));

   $newEvent = $gdataCal->newEventEntry();
   $newEvent->title = $gdataCal->newTitle($title);
   $when = $gdataCal->newWhen();
   $when->startTime = $eventStart;
   $when->endTime = $eventEnd;

   $newEvent->when = array($when);

   //And at last, the insert is set to the calendar URL found above
   $createdEvent = $gdataCal->insertEvent($newEvent, $appCalUrl);
  }
  echo "<p>".$result->num_rows." added to your Google calendar.</p>";

Thanks to anyone who read my question and did any thinking on it. If anyone knows of a way to tighten the above code up (maybe I don't need two loops?) I'd love to get feedback.

1
votes

I believe Anthony is referring to either the v1 docs or the v2 docs on the Google Calendar APIs site. I managed this pretty easily in Perl, by following the v2 protocol guide.

The key is to change the URL you are POSTing to. Instead of the default "/calendar/feeds/default/private/full", first fetch the list of available calendars, then get the content/@src value from the calendar you want, and post to that, e.g. /calendar/feeds/1234567890abcdefeg%40group.calendar.google.com/private/full