2
votes

Summary:

Google_Service_Calendar seems to be "force-paginating" results of $service->events->listEvents();

Background:

google calendar API v3, using php client library

We are developing a mechanism to sync our internal calendar with a user's google calendar. Please note I will refer below to $x, which represents google's default limit on the number of events, similar to $options['maxResults']; The default value is 250, but it should not matter: we have tested the below with and without explicitly defined request parameters such as 'maxResults', 'timeMin', and 'timeMax' - the problem occurs in all cases.

Another relevant test we did: export this calendar to foobar.ics, created a new gmail user form scratch, import foobar.ics to [email protected]. DOES NOT REPLICATE THIS ISSUE. We have reviewed/reset various options in the subject calendar (sharing, etc) but cannot find any setting that has any effect.

The Problem:

Normally, when we call this:

$calendar='primary';
$optParams=array();
$events = $this->service->events->listEvents($calendar, $optParams);

$events comes back as a Google_Service_Calendar_Events object, containing $n "items". IF there are more than $x items, the results could be paginated, but the vanilla response (for a 'normal', result set with ( count($items) < $x ) ) is a single object, and $events->nextPageToken should be empty.

One account we are working with (of course, the boss's personal account) does not behave this way. The result of:

$events = $this->service->events->listEvents('primary', []);

is a Google_Service_Calendar_Events object like this:

Google_Service_Calendar_Events Object
(
    [accessRole] => owner
    [defaultRemindersType:protected] => Google_Service_Calendar_EventReminder
    [defaultRemindersDataType:protected] => array
    [description] => 
    [etag] => "-kakMffdIzB99fTAlD9HooLp8eo/WiDS9OZS7i25CVZYoK2ZLLwG7bM"
    [itemsType:protected] => Google_Service_Calendar_Event
    [itemsDataType:protected] => array
    [kind] => calendar#events
    [nextPageToken] => CigKGmw5dGh1Mms4aWliMDNhanRvcWFzY3Y1ZGkwGAEggICA6-L3lrgUGg0IABIAGLig_Zfi278C
    [nextSyncToken] => 
    [summary] => [email protected]
    [timeZone] => America/New_York
    [updated] => 2014-07-23T15:38:50.195Z
    [collection_key:protected] => items
    [modelData:protected] => Array
        (
            [defaultReminders] => Array
                (
                    [0] => Array
                        (
                            [method] => popup
                            [minutes] => 30
                        )

                )

            [items] => Array
                (
                )

        )

    [processed:protected] => Array
        (
        )

)

Notice that $event['items'] is empty, and nextPageToken is not null. If we then do a paginated request like this:

        while (true) {
            $pageToken = $events->getNextPageToken();
            if ($pageToken) {
                $optParams = array('pageToken' => $pageToken);
                $events = $this->service->events->listEvents($calendar, $optParams);
                if(count($events) > 0){
                    h2("Google Service returned total of ".count($events)." events.");
                }

            } else {
                break;
            }
        }

The next result set gives us the events. In other words, the google service seems to be paginating the initial results, despite the fact that we are certain the result is less than $x.

To be clear, if we have 5 events on our calendar, we expect 1 result with 5 items. Instead, we get 1 result with 0 items, but the first result of the 'nextPageToken' logic gives us the desired 5 items.

Solution Ideas?:

A. handle paginated results, and/or "Incremental Syncronization'. These are on our list of features to implement, but we consider these to be more 'optimization' than 'necessity'. In other words, I understand that handling/sending nextSyncToken and nextPageToken are OPTIONAL- thus the issue we are having should not depend on our client code doing this.

B. use a different, non-primary calendar for this user. we think this particular primary calendar may corrupt or somehow cached on google's side: to be fair, we did at one point accidentally insert a bunch of junk events on this calendar to the point that google put us in read-only mode as described here: https://support.google.com/a/answer/2905486?hl=en but we understand that was a temporary result of clunky testing.... In other words, we know we HAD screwed this calendar up badly, but this morning we deleted ALL events, added a single test event, and got the same result as above FOR THIS CALENDAR. Cannot replicate for any other user.... including a brand new gmail user.

C. delete the 'primary' calendar, create a new one. Unfortunately, we understand it is not possible to delete the primary CALENDAR, only to delete the CALENDAR EVENTS.

D. make the boss open a brand new google account

Any other suggestions? We are proceeding with A, but even that is a band-aid to the problem, and does not answer WHY is this happening? How can we avoid it in the future? (Please don't say "D")

Thanks in advance for any advice or input!

1

1 Answers

2
votes

There is a maximum page size, if you don't specify one yourself there is an implicit one (https://developers.google.com/google-apps/calendar/v3/pagination). Given this it's necessary to implement pagination for your app to work correctly.

As you noticed, a page does not always contain the maximum number of results so pagination is important even if the number of events does not exceed the page size. Just keep following the page tokens and it will eventually give you all the results (there will be a page with no nextPageToken)

TL;DR A :)