Adding events in bulk to Google Calendar API with PHP - php

What is the best way I could add possibly 10,000 to 20,000 events at once to a Google Calendar with PHP?
If I try adding them separately I get a "limit exceeded" error far before the daily max.
I've also been looking at importing ICAL/ICS files but I also can't seem to find a function for this besides the calendar subscriptions. Calendar Subscriptions are great but I need to have almost "real-time" updates in my calendars when an event gets changed and it's unclear when calendar subscriptions get updated this could take as much as a day from the initial change in the ICS file.

Need to use Batch Requests. A batch request consists of multiple API calls combined into one HTTP request. Batch processing is a known feature request and is actively worked on. Read the following article about it: https://developers.google.com/google-apps/calendar/batch
See my multipleInsert function for example:
class My_google_calendar
{
...
/** Add single Event for Student */
function addEvent($lesson, $instructor, $return_request = false, $enable_attendees = false)
{
$calendar = $this->getGoogleCalendar(); // get calendar service variable
$lesson_from = date(DATE_RFC3339, $lesson->from);
$lesson_to = date(DATE_RFC3339, $lesson->from + $lesson->duration);
$event = new Google_Service_Calendar_Event();
$event->setSummary('Lesson with student: '$lesson->student_full_name);
$start = new Google_Service_Calendar_EventDateTime();
$start->setDateTime($lesson_from);
$start->setTimeZone($this->getGoogleCalendarTimeZone());
$event->setStart($start);
$end = new Google_Service_Calendar_EventDateTime();
$end->setDateTime($lesson_to);
$end->setTimeZone($this->getGoogleCalendarTimeZone());
$event->setEnd($end);
$event->setColorId(4);
$description = "...";
$event->setDescription($description);
if (isset($student->email) && $enable_attendees) {
$attendee1 = new Google_Service_Calendar_EventAttendee();
$attendee1->setResponseStatus('needsAction');
$attendee1->setEmail($student->email);
$attendees = array($attendee1);
$event->setAttendees($attendees);
}
$createdEvent = $this->calendar->events->insert($this->calendar_id, $event, array('fields' => 'id'));
return $return_request ? $createdEvent : $createdEvent->getId();
}
/** Push group of events to the Calendar */
function multipleInsert ($lessons, $instructor)
{
$this->use_batch = true;
$this->client->setUseBatch($this->use_batch);
$batch = new Google_Http_Batch($this->client);
foreach($lessons as $time => $lesson) {
$lesson = array_shift($group['lessons']);
$req = $this->addEvent($lesson, $instructor, true);
$batch->add($req, $time);
}
}
$results = $batch->execute();
return $results;
}
}

Related

Google Analytics - setPageSize not change

I tried to run query on Analytics Reporting using the "google/apiclient" and based on example on Google Analytics Reporting v4 documentation. It is returning records, but always only 10. NextPageToken is null in response. Response has only one report. Request has set PageSize for 100 records. I tried many configuration PageSize: 100/500/1000 and PageToken: 1/100/1000/abc and always return only 10 records.
I created the same report on page and it has 1169 pages for 10 records on page (for the same date range).
I looked on limit quotas for API and it has default value.
Did i miss something in code or may be there something problem with configuration service account (some limitation for service account)?
private function getReport($analytics, $VIEW_ID) {
$dateRange = new Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("2020-04-01");
$dateRange->setEndDate("2020-04-12");
$quantityCheckedOut = new Google_Service_AnalyticsReporting_Metric();
$quantityCheckedOut->setExpression("ga:quantityCheckedOut");
$quantityCheckedOut->setAlias("itemQuantity");
$dimension1 = new Google_Service_AnalyticsReporting_Dimension();
$dimension1->setName("ga:productSku");
$pivots = new Google_Service_AnalyticsReporting_Pivot();
$pivots->setDimensions([$dimension1]);
$pivots->setMetrics($quantityCheckedOut);
$order = new Google_Service_AnalyticsReporting_OrderBy();
$order->setFieldName("ga:quantityCheckedOut");
$order->setSortOrder("ASCENDING");
$request = new Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges($dateRange);
$request->setPageSize("100");
$request->setHideValueRanges(true);
$request->setMetrics([$quantityCheckedOut]);
$request->setPivots($pivots);
$request->setOrderBys([$order]);
$request->setSamplingLevel("LARGE");
return $request;
}
private function initializeAnalytics()
{
$KEY_FILE_LOCATION = $this->initFolder . '/google.json';
$filesystemAdapter = new Local($this->cacheFolder);
$filesystem = new Filesystem($filesystemAdapter);
$client = new Google_Client();
$client->setApplicationName("App Name");
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setIncludeGrantedScopes(true);
$cache = new FilesystemCachePool($filesystem);
$client->setCache($cache);
$client->addScope(Google_Service_AnalyticsReporting::ANALYTICS_READONLY);
$analytics = new Google_Service_AnalyticsReporting($client);
return $analytics;
}
private function printResults($reports)
{
$nextToken = 0;
/** #var Google_Service_AnalyticsReporting_Report $report */
foreach ($reports->getReports() as $report) {
$nextToken = $report->getNextPageToken();
}
return $nextToken
}
public function run(){
/** #var Google_Service_AnalyticsReporting $analytics */
$analytics = $this->initializeAnalytics();
$pageToken = 1;
$i = 0;
$request = $this->getReport($analytics, "VIEW_IDxxxx");
$body = new Google_Service_AnalyticsReporting_GetReportsRequest();
while($i < 1) {
$request->setPageToken((string)$i);
$body->setReportRequests($request);
$response = $analytics->reports->batchGet($body);
$pageToken = $this->printResults($response);
$i++;
}
}
It wasn't needed
$pivots = new Google_Service_AnalyticsReporting_Pivot();
$pivots->setDimensions([$dimension1]);
$pivots->setMetrics($quantityCheckedOut);
Instead of that i wrote
$request->setDimensions($dimension1);
Then google response was two columns in data: ProductSKU and itemQuantity. That is i wanted. Somehow Pivot removes nextPageToken and nextPageSize doesn`t affect on request.

How can I create an event in google calendar and not have it on trash?

How can I create an event in google calendar and not have it on trash?
I was researching on Google Calendar API ( https://developers.google.com/calendar/v3/reference/events/insert ) how to create an event on the calendar, the insert works fine, the API returns with status: 'confirmed'.
But in the calendar, the event does not appear.
I looked at Google Calendar API and there the status is "canceled", so my events appear on the trash.
I'm not sure of what is happening, someone knows how to create an event on google calendar that does not goes to trash?
<?php
class Calendar
{
private $calendarId = 'primary';
private $service = null;
private $client = null;
public function __construct()
{
$this->client = new Client([
'scopes' => [
Google_Service_Calendar::CALENDAR,
Google_Service_Calendar::CALENDAR_READONLY,
Google_Service_Calendar::CALENDAR_EVENTS,
Google_Service_Calendar::CALENDAR_EVENTS_READONLY,
]
]);
$this->service = new Google_Service_Calendar($this->client->getClient());
}
public function eventAdd()
{
$email = 'seuemail#gmail.com';
$event = new Google_Service_Calendar_Event();
$event->setSummary('Vamos ver agora ;)');
$event->setStatus('confirmed');
$start_datetime = new Google_Service_Calendar_EventDateTime();
$start_datetime->setDateTime('2019-10-10T15:00:00.000-03:00');
$start_datetime->setTimeZone('America/Sao_Paulo');
$event->setStart($start_datetime);
$end_datetime = new Google_Service_Calendar_EventDateTime();
$end_datetime->setDateTime('2019-10-10T20:00:00.000-03:00');
$end_datetime->setTimeZone('America/Sao_Paulo');
$event->setEnd($end_datetime);
$reminder = new Google_Service_Calendar_EventReminder();
$reminder->setMethod('popup');
$reminder->setMinutes(10);
$reminders = new Google_Service_Calendar_EventReminders();
$reminders->setUseDefault(false);
$reminders->setOverrides(array($reminder));
$event->setReminders($reminders);
$attendee1 = new Google_Service_Calendar_EventAttendee();
$attendee1->setEmail($email);
$attendee1->setResponseStatus('accepted');
$attendees = array($attendee1);
$event->attendees = $attendees;
$optParams = array('sendNotifications' => true, 'maxAttendees' => 1);
$event = $this->service->events->insert($this->calendarId, $event, $optParams);
var_dump($event);
}
}
There is an open issue for this problem in Issue Tracker.
As a workaround, you can use your actual calendar ID instead of just 'primary'. This small change should solve your issue.
I hope this helps!

Google Calendar API / Empty the trash of primary calendar

I synchronize a calendar with an external application. I have to have the same events IDs in this application and in Google Calendar. But in this application, when an event is deleted, its ID is available for a future new event. So I'd like that, when I delete an event with Calendar API, the event's ID is available. But it always stay in the trash and I can't empty it with API.
So, the two solutions I found are:
Use the clear function:
$cld = $service->calendars->get($calendarId);
$calendarList = $service->calendarList->listCalendarList()->getItems();
$summary = $cld->getSummary();
$timeZone = $cld->getTimeZone();
$events = $service->events->listEvents("primary")->getItems();
$service->calendars->clear('primary');
$cld->setSummary($summary);
$cld->setTimeZone($timeZone);
foreach($events as $event){
$service->events->insert("primary", $event);
}
But this code return message "Forbidden" with code 403 on line $service->calendars->clear('primary');
Create a new calendar and make it primary
$cld = $service->calendars->get($calendarId);
$calendarList = $service->calendarList->listCalendarList()->getItems();
$summary = $cld->getSummary();
$timeZone = $cld->getTimeZone();
$events = $service->events->listEvents("primary")->getItems();
$calendarListEntry = new Google_Service_Calendar_CalendarListEntry();
$calendarListEntry->setId("account_mail#gmail.com");
$calendarListEntry->setSummary($summary);
$calendarListEntry->setTimeZone($timeZone);
$createdCalendarListEntry = $service->calendarList->insert($calendarListEntry);
foreach($events as $event){
$service->events->insert("account_mail#gmail.com", $event);
}
But this code return message "Invalid Value" with code 400 on line $createdCalendarListEntry = $service->calendarList->insert($calendarListEntry);
If someone has an idea for me, it would be amazing!
Thank you.

Google Calendar sendnotifications not working

I am modifying a Wordpress plugin (gravity forms to google calendar) to add a specific attendee. The event posts to the calendar, and when I view the event, it includes the intended attendee, however, it is not sending the notification for the event to the attendee.
Here is the snippet:
$event->setStart($start);
$event->setEnd($end);
$attendee1 = new Google_EventAttendee();
$attendee1->setEmail('42fjsjjpte2n7ahlld603600l4#group.calendar.google.com');
// ...
$attendees = array($attendee1);
$event->attendees = $attendees;
$optArgs = array('sendNotifications'=>true);
if (! empty($location))
$event->setLocation($location);
$ret = self::$client->insert_event($calendar_id, $event, $optArgs);
Can you spot what I've done wrong?

Batch request Google Calendar php API

I'm working on a google Calendar sync with my application.
I'm using the latest google-api-php-client
Now I want to update all my event, so i want to use the batch operation.
The example code of the php client api is:
$client = new Google_Client();
$plus = new Google_PlusService($client);
$client->setUseBatch(true);
$batch = new Google_BatchRequest();
$batch->add($plus->people->get(''), 'key1');
$batch->add($plus->people->get('me'), 'key2');
$result = $batch->execute();
So when I "translate" it to the calendar API, I become the following code:
$client = new Google_Client();
$this->service = new Google_CalendarService($client);
$client->setUseBatch(true);
// Make new batch and fill it with 2 events
$batch = new Google_BatchRequest();
$gEvent1 = new Google_event();
$gEvent1->setSummary("Event 1");
$gEvent2 = new Google_event();
$gEvent2->setSummary("Event 2");
$batch->add( $this->service->events->insert('primary', $gEvent1));
$batch->add( $this->service->events->insert('primary', $gEvent2));
$result = $batch->execute();
But when I run this code, I get this error:
Catchable fatal error: Argument 1 passed to Google_BatchRequest::add()
must be an instance of Google_HttpRequest, instance of Google_Event given
And I do not think that "$plus->people->get('')" is a HttpRequest.
Does anybody know what I do wrong, or what method / object I should use to add in the batch?
Or what the correct use of the batch operation for the calendar is?
Thanks in advance!
I had the same problem while working with inserts to the MirrorService api, specifically with timeline items. What is happening is that the the Google_ServiceRequest object is seeing that you've set the useBatch flag on the client and is actually returning returning Google_HttpRequest object before executing the call to Google but the insert statement in the calendar service doesn't properly handle it as such and ends up returning the calendar event object instead.
It also looks like your params to batch->add are backwards. Should be:
$batch->add( $this->service->events->insert($gEvent1, 'primary'));
Here is my modification to the insert method (you'll need to do this in the calendar service with the proper object input to the method). Just a few lines to make it check what class is coming back from the ServiceRequest class:
public function insert(google_TimelineItem $postBody, $optParams = array()) {
$params = array('postBody' => $postBody);
$params = array_merge($params, $optParams);
$data = $this->__call('insert', array($params));
if ($this->useObjects()) {
if(get_class($data) == 'Google_HttpRequest'){
return $data;
}else{
return new google_TimelineItem($data);
}
} else {
return $data;
}
}
you can use this code to insert events in batch:
public function addEventInBatch($accessToken, $calendarId, array $events)
{
$client = new Google_Client();
$client->setAccessToken($accessToken);
$client->setUseBatch(true);
$service = new Google_Service_Calendar($client);
$batch = $service->createBatch();
collect($events)->each(fn ($event) => $batch->add($service->events->insert($calendarId, $event)));
return $batch->execute();
}

Categories