Repository URL to install this package:
|
Version:
6.2.3 ▾
|
<?php
/**
* Created by PhpStorm.
* User: eduarddezacastellano
* Date: 12/09/2018
* Time: 16:36
*/
namespace DigitalAscetic\GoogleApiClientBundle\Service;
use DigitalAscetic\GoogleApiClientBundle\Entity\GoogleApiNotificationsChannel;
use DigitalAscetic\GoogleApiClientBundle\Entity\IGoogleApiCalendarEvent;
use DigitalAscetic\GoogleApiClientBundle\Entity\IGoogleApiUser;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class GoogleCalendarService implements IGoogleApiService
{
const SERVICE_NAME = 'ascetic_google_api_client.calendar';
const SERVICE_ENABLED_PROPERTY = 'ascetic_google_api_client.calendar.enabled';
const SERVICE_WATCH_ENABLED_PROPERTY = 'ascetic_google_api_client.calendar.watch.enabled';
/** @var bool */
private $enabled;
/** @var bool */
private $watching;
/** @var ContainerInterface $container */
private $container;
/** @var EntityManagerInterface $em */
private $em;
/** @var GoogleAuthService $googleAuthService */
private $googleAuthService;
/** @var GoogleNotificationsService */
private $notificationService;
/** @var IGoogleApiEventsService $eventsService */
private $eventsService;
/** @var LoggerInterface */
private $logger;
/**
* GoogleApiCalendarService constructor.
* @param ContainerInterface $container
* @param EntityManagerInterface $em
* @param GoogleAuthService $googleAuthService
* @param GoogleNotificationsService $notificationsService
* @param LoggerInterface $logger
* @param IGoogleApiEventsService $eventsService
*/
public function __construct(ContainerInterface $container,
EntityManagerInterface $em,
GoogleAuthService $googleAuthService,
GoogleNotificationsService $notificationsService,
LoggerInterface $logger,
IGoogleApiEventsService $eventsService = null)
{
$this->container = $container;
$this->googleAuthService = $googleAuthService;
$this->em = $em;
$this->notificationService = $notificationsService;
$this->eventsService = $eventsService;
$this->logger = $logger;
$this->enabled = $container->getParameter(GoogleCalendarService::SERVICE_ENABLED_PROPERTY);
$this->watching = $container->getParameter(GoogleCalendarService::SERVICE_WATCH_ENABLED_PROPERTY);
}
public function isEnabled(): bool
{
return $this->enabled;
}
public function isWatching(): bool
{
return $this->watching;
}
/**
* @param IGoogleApiUser $user
* @param IGoogleApiCalendarEvent $event
* @param string $calendarId
* @return \Google_Service_Calendar_Event
* @throws \Google_Exception
*/
public function getEvent(IGoogleApiUser $user, IGoogleApiCalendarEvent $event, $calendarId = 'primary')
{
if ($this->googleAuthService->hasAuthorization($user) &&
$event->isSyncableGoogleCalendar()) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user));
return $calendarService->events->get($calendarId, $event->getGoogleEventId());
}
}
/**
* @param IGoogleApiUser $user
* @param string $calendarId
* @param GoogleApiNotificationsChannel|null $channel
* @param string|null $host
* @return \Google_Service_Calendar_Event[]|null
* @throws \Google_Exception
*/
public function listEvents(IGoogleApiUser $user, $calendarId = 'primary', GoogleApiNotificationsChannel $channel = null, string $host = null)
{
if ($this->googleAuthService->hasAuthorization($user)) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user, $host));
$optParams = array();
if (isset($channel) && $channel->getLastNotificationHandledDate()) {
$optParams['updatedMin'] = $channel->getLastNotificationHandledDate()->format(\DateTime::RFC3339);
}
if (isset($channel) && $channel->getSyncToken() && $channel->getLastNotificationHandledDate() == null) {
$optParams['syncToken'] = $channel->getSyncToken();
}
/** https://developers.google.com/calendar/api/v3/reference/events/list?hl=es-419 */
$optParams['eventTypes'] = 'default';
try {
$googleEvents = $calendarService->events->listEvents($calendarId, $optParams);
} catch (\Exception $exception) {
$this->logger->error('GOOGLE_API_CLIENT::listEvents(): ' . $exception->getMessage());
/**
* If the syncToken expires, the server will respond with a 410 GONE response code
* and the client should clear its storage and perform a full synchronization without any syncToken.
*/
if ($exception->getCode() === 410) {
if ($channel) {
$this->updateSyncTokenChannel($channel, null);
}
$googleEvents = $calendarService->events->listEvents($calendarId);
}
}
$events = array();
if (isset($channel) && !empty($googleEvents)) {
$this->updateSyncTokenChannel($channel, $googleEvents->getNextSyncToken());
}
if (!empty($googleEvents)) {
/** @var \Google_Service_Calendar_Event[] $events */
$events = $googleEvents->getItems();
}
return $events;
}
return null;
}
public function insertEvent(IGoogleApiUser $user, IGoogleApiCalendarEvent $event, $calendarId = 'primary', string $host = null)
{
if ($this->googleAuthService->hasAuthorization($user) &&
$event->isSyncableGoogleCalendar()) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user, $host));
$newEvent = new \Google_Service_Calendar_Event(array(
'summary' => $event->getSummary(),
'location' => $event->getLocation(),
'description' => $event->getDescription(),
'start' => $event->getStart(),
'end' => $event->getEnd()
));
$googleEvent = $calendarService->events->insert($calendarId, $newEvent);
$event->setGoogleEventId($googleEvent->getId());
$this->em->persist($event);
$this->em->flush();
}
}
public function patchEvent(IGoogleApiUser $user, IGoogleApiCalendarEvent $event, $calendarId = 'primary', string $host = null)
{
if ($this->googleAuthService->hasAuthorization($user) &&
$event->isSyncableGoogleCalendar()) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user, $host));
$newEvent = new \Google_Service_Calendar_Event(array(
'summary' => $event->getSummary(),
'location' => $event->getLocation(),
'description' => $event->getDescription(),
'start' => $event->getStart(),
'end' => $event->getEnd()
));
$calendarService->events->patch($calendarId, $event->getGoogleEventId(), $newEvent);
}
}
public function deleteEvent(IGoogleApiUser $user, IGoogleApiCalendarEvent $event, $calendarId = 'primary')
{
if ($this->googleAuthService->hasAuthorization($user) &&
$event->isSyncableGoogleCalendar()) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user));
$calendarService->events->delete($calendarId, $event->getGoogleEventId());
}
}
public function getNotifications(GoogleApiNotificationsChannel $channel, string $host = null)
{
if ($this->isWatching() && $channel->getToken() === GoogleApiNotificationsChannel::CALENDAR_TOKEN) {
$googleEvents = $this->listEvents($channel->getUser(), 'primary', $channel, $host);
if (!empty($googleEvents)) {
$batchProcesses = 1;
$eventsIds = array_map(function (\Google_Service_Calendar_Event $event) {
return $event->getId();
}, $googleEvents);
$calendarEvents = $this->eventsService->getEventsByGoogleEventsId($eventsIds);
foreach ($calendarEvents as $calendarEvent) {
if ($calendarEvent) {
$googleEventFiltered = array_filter($googleEvents, function (\Google_Service_Calendar_Event $event) use ($calendarEvent) {
return $event->getId() === $calendarEvent->getGoogleEventId();
});
$googleEvent = !empty($googleEventFiltered) ? $googleEventFiltered[0] : null;
if (isset($googleEvent)) {
$calendarEvent = $this->updateGoogleApiCalendarEvent($calendarEvent, $googleEvent);
$this->em->persist($calendarEvent);
}
if ($batchProcesses % 20 === 0) {
$this->em->flush();
$this->em->clear();
}
$batchProcesses++;
}
}
$this->em->flush();
}
}
}
public function syncEvent(IGoogleApiUser $user, IGoogleApiCalendarEvent $calendarEvent)
{
if ($calendarEvent->isSyncableGoogleCalendar()) {
$googleEvent = $this->getEvent($user, $calendarEvent);
if (isset($googleEvent)) {
$this->updateGoogleApiCalendarEvent($calendarEvent, $googleEvent);
$this->em->persist($calendarEvent);
$this->em->flush();
}
}
}
public function disconnect(IGoogleApiUser $user, string $host = null)
{
$client = $this->googleAuthService->getClientAuthenticatedForUser($user, $host);
$client->setUseBatch(true);
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($client);
$batch = $calendarService->createBatch();
/** @var IGoogleApiCalendarEvent[] $events */
$events = $this->eventsService->getEventsByUser($user);
$batchProcesses = 1;
foreach ($events as $event) {
$eventId = $event->getGoogleEventId();
$batch->add($calendarService->events->delete($event->getGoogleCalendarId(), $eventId));
// clear GoogleEventId
$event->setGoogleEventId(null);
$this->em->persist($event);
if ($batchProcesses % 20 === 0) {
$this->em->flush();
$this->em->clear();
}
$batchProcesses++;
}
$this->em->flush();
try {
$batch->execute();
} catch (\Exception $exception) {
$this->logger->error('GOOGLE DISCONNECT ERROR WITH CODE: ' . $exception->getCode() . ' AND MESSAGE: ' . $exception->getMessage());
}
$client->setUseBatch(false);
}
public function watchResource(IGoogleApiUser $user, string $host = null)
{
if ($this->isWatching()) {
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user, $host));
$this->createNewCalendarNotificationsChannel($calendarService, $user, 'primary', $host);
}
}
public function renewWatchChannels(IGoogleApiUser $user, string $host = null)
{
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user, $host));
$channels = $this->notificationService->getChannelsByUser($user);
$batchProcesses = 1;
foreach ($channels as $key => $value) {
if ($channels[$key]->isExpired()) {
$this->em->remove($channels[$key]);
unset($channels[$key]);
if ($batchProcesses % 20 === 0) {
$this->em->flush();
$this->em->clear();
}
$batchProcesses++;
}
}
if ($batchProcesses > 1) {
$this->em->flush();
}
// IF ALL CHANNELS ARE EXPIRED; WE CREATE A NEW CHANNEL
if ($this->isWatching() && count($channels) <= 0) {
$this->createNewCalendarNotificationsChannel($calendarService, $user, 'primary', $host);
}
}
public function stopWatchingResources(IGoogleApiUser $user, string $host = null)
{
/** @var \Google_Service_Calendar $calendarService */
$calendarService = new \Google_Service_Calendar($this->googleAuthService->getClientAuthenticatedForUser($user));
/** @var GoogleApiNotificationsChannel[] $channels */
$channels = $this->notificationService->getChannelsByUser($user);
$batchProcesses = 1;
foreach ($channels as $channel) {
$channelParams = new \Google_Service_Calendar_Channel();
$channelParams->setId($channel->getChannelId());
$channelParams->setResourceId($channel->getResourceId());
$channelParams->setType($channel->getType());
$channelParams->setToken($channel->getToken());
$channelParams->setAddress($this->notificationService->getDeliveryAddress($host));
try {
$calendarService->channels->stop($channelParams);
} catch (\Exception $exception) {
$this->logger->error('GOOGLE STOP CHANNEL ERROR WITH CODE: ' . $exception->getCode() . ' AND MESSAGE: ' . $exception->getMessage());
}
$this->em->remove($channel);
if ($batchProcesses % 20 === 0) {
$this->em->flush();
$this->em->clear();
}
$batchProcesses++;
}
$this->em->flush();
}
private function createNewCalendarNotificationsChannel(\Google_Service_Calendar $calendarService, IGoogleApiUser $user, string $calendarId = 'primary', string $host = null)
{
if (!$user->isPersisted()) {
$this->logger->error('Error creating GoogleApiNotificationsChannel for user: ' . $user . '. User is not persisted.');
return false;
}
$newChannel = new GoogleApiNotificationsChannel(GoogleApiNotificationsChannel::TYPE_WEB_HOOK, GoogleApiNotificationsChannel::CALENDAR_TOKEN, $user);
$channelParams = new \Google_Service_Calendar_Channel();
$channelParams->setId($newChannel->getChannelId());
$channelParams->setType($newChannel->getType());
$channelParams->setToken($newChannel->getToken());
$channelParams->setAddress($this->notificationService->getDeliveryAddress($host));
$optParams = [];
/** https://developers.google.com/calendar/api/v3/reference/events/watch?hl=es-419 */
$optParams['eventTypes'] = 'default';
try {
$channel = $calendarService->events->watch($calendarId, $channelParams, $optParams);
} catch (\Throwable $exception) {
$this->logger->error('Google Calendar Api Watch method, error with code: ' . $exception->getCode() . ' and message: ' . $exception->getMessage());
return false;
}
$newChannel->setResourceId($channel->getResourceId());
$newChannel->setExpiration($channel->getExpiration());
$this->em->persist($newChannel);
$this->em->flush();
return $newChannel;
}
private function updateGoogleApiCalendarEvent(IGoogleApiCalendarEvent $calendarEvent, \Google_Service_Calendar_Event $event)
{
$calendarEvent->setSummary($event->getSummary());
$calendarEvent->setLocation($event->getLocation());
$calendarEvent->setDescription($event->getDescription());
if ($event->getStart()) {
$calendarEvent->setStart($event->getStart());
}
if ($event->getEnd()) {
$calendarEvent->setEnd($event->getEnd());
}
return $calendarEvent;
}
private function updateSyncTokenChannel(GoogleApiNotificationsChannel $channel, ?string $syncToken)
{
$channel->setSyncToken($syncToken);
$this->em->persist($channel);
$this->em->flush();
}
}