Интеграция Symfony 2 и Google Calendar

    При создании современного веб проекта вам не обойтись без работы с внешними сервисами. Недавно у нас возникла задача по работе с календарями. В этой статье я бы хотел рассказать о некоторых моментах интеграции проекта на Symfony2 с Google Calendar.

    Получение ключа


    Для обмена данными с google нужно получить ключ. Наш сайт будет обращаться за информацией незаметно для пользователя, поэтому нам нужен ключ для сервис аккаунта. Для получения ключа нужно отправиться в консоль для разработчиков. Добавить приложение, зайти во вкладку Api и активировать календарь. Теперь вы сможете получить ключ на вкладке Credentials.
    Есть вариант json или p12. Особой разницы нету, зависит от того, что вам удобнее.

    Модуль Google Api


    Для работы с сервисами google есть api клиент. Установим его через composer
    php composer.phar require google/apiclient

    Сделаем небольшую обертку и объявить ее как сервис.
    class Google
    {
        /* @var \Google_Client */
        private $client;
    
        /* @var \Google_Service_Calendar */
        private $calendar;
    
        private $scope;
    
        public function __construct($scope)
        {
            $this->client = new \Google_Client();
            $this->scope = $scope;
        }
    
        public function setCredentialsP12($p12Path, $email)
        {
            $credentials = new \Google_Auth_AssertionCredentials(
                $email,
                $this->scope,
                file_get_contents($p12Path)
            );
    
            $this->client->setAssertionCredentials($credentials);
        }
    
        public function setCredentialsJson($jsonPath)
        {
            $this->client->loadServiceAccountJson($jsonPath, $this->scope);
        }
    
        /**
         * @return \Google_Service_Calendar
         */
        public function getCalendar()
        {
            if (!$this->calendar) {
                $this->calendar = new \Google_Service_Calendar($this->client);
            }
    
            return $this->calendar;
        }
    }
    


    services:
        google.client:
            class: MyBundle\Google
            arguments: ['https://www.googleapis.com/auth/calendar.readonly'] # Сейчас нам нужны только права на чтение календаря
    

    Методы setCredentialsP12 и setCredentialsJson нужны для того чтобы передавать ключи внутрь нашего сервиса. Метод getCalendar возвращает подготовленный объект календаря и нам не нужно как-то его дополнять вне нашего сервиса.

    Подключение ключа


    У нас могут быть разные ключи в разных окружениях, а также у каждого разработчика может быть свой ключ. Поэтому ключ в сервис будем передавать в зависимости от наличия определенных параметров, которые могут задаваться в локальном конфиге. Для этого напишем и подключим CompilerPass.
    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
    use Symfony\Component\DependencyInjection\ContainerBuilder;
    
    class CredentialsPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            $googleClient = $container->getDefinition('google.client'); //Имя сервиса который мы объявили в предыдущем абзаце
    
            if ($container->hasParameter('google_p12_path') && $container->hasParameter('google_p12_email')) {
                $path = $container->getParameter('google_p12_path');
                $email = $container->getParameter('google_p12_email');
    
                $googleClient->addMethodCall('setCredentialsP12', [$path, $email]);
            } elseif ($container->hasParameter('google_json_path')) {
                $googleClient->addMethodCall('setCredentialsJson', [$container->getParameter('google_json_path')]);
            }
        }
    }
    

    И теперь нам достаточно написать в локальном конфиге.
    parameters:
        google_p12_path: my-certificate.p12
        google_p12_email: my-email@mail.com
    
    или
    parameters:
        google_json_path: my-certificate.json
    


    Получение списка событий


    Теперь у нас есть сервис и мы можем запросить список событий.
    try {
        /* @var $start \DateTime */
        $start;
    
        /* @var $end \DateTime */
        $end;
    
        $events = $google->getCalendar()->events->listEvents('example@mail.com', [
            'timeMin' => $start->format('c'),
            'timeMax' => $end->format('c'),
        ]);
    } catch (\Google_Service_Exception $exception) {
        //TODO implement error catching
    }
    

    Для каждого календаря есть свой уникальный email (example@mail.com в примере выше). С помощью метода listEvents здесь мы получаем все события из нашего календаря за определенный промежуток времени. Гугл использует стандарт ISO 8601 для временных параметров (timeMin, timeMax), так что для форматирования времени достаточно использовать букву c.

    Вместо заключения


    Потратив немного времени, мы получаем доступ из нашего проекта к google calendar. Дальше можно развивать эту интеграцию, например можно организовать более сложный поиск или добавление событий из нашего проекта. И если вы готовы доверить свои календари (а может и не свои) гуглу, то вы можете получить за дешево очень мощный инструмент, который при этом можно гибко подстроить под ваши нужды.
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 1
    • +2
      Добавлю информацию по работе с календарями пользователей.

      Например, example@mail.com — это email пользователя, имя основного календаря обычно совпадает с email. Просто так поставить событие пользователю в календарь не получится. Надо предоставить доступ для сервисного аккаунта. Есть 2 варианта — предоставление доступа вручную и domain-wide authority.

      Когда генерируем API key, там же генерируются 2 параметра:

      Client ID:
      123456789012-abcdef1g2hijkl34mn56opqrstuvwxyz.apps.googleusercontent.com
      Email address:
      123456789012-abcdef1g2hijkl34mn56opqrstuvwxyz@developer.gserviceaccount.com

      Предоставление доступа вручную:
      Надо чтобы пользователь сам зашел в календарь и добавил разрешение вносить изменения для сервисного аккаунта (Email address).
      Настройки — Календари — [Название календаря] — Открытие общего доступа к этому календарю — Общий доступ для отдельных пользователей
      Пользователь: 123456789012-abcdef1g2hijkl34mn56opqrstuvwxyz@developer.gserviceaccount.com
      Настройки разрешений: Вносить изменения

      Domain-wide authority:
      Если в компании используется свой домен для рабочей почты пользователей, можно настроить авторизацию по всему домену. Приложение при этом совершает действия как бы от имени пользователя (impersonate).
      Это делается через консоль администратора домена: admin.google.com. Для предоставления доступа используется Client ID.
      Подробно написано здесь developers.google.com/identity/protocols/OAuth2ServiceAccount в разделе Delegating domain-wide authority to the service account.

      В коде надо добавить установку свойства sub (email пользователя, которым мы прикидываемся):
      $credentials = new Google_Auth_AssertionCredentials(
          $service_email,  // 123456789012-abcdef1g2hijkl34mn56opqrstuvwxyz@developer.gserviceaccount.com
          $scope,          // https://www.googleapis.com/auth/calendar
          file_get_contents($p12Path)
      );
      $credentials->sub = $user_email;  // example@mail.com
      

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.