LoginSignup
6
5

More than 1 year has passed since last update.

複数のGoogleカレンダーから1つのNotionのカレンダーにスケジュールを同期するバッチ(追加だけ)

Last updated at Posted at 2021-11-19

処理方法を見直したので全体的に修正しました。(2022/04/26 修正)

環境

  • Laravel8.69.0
  • PHP8

前準備

1. Laravelのインストール

2. 以下の2つのパッケージをインストール

laravel-notion-api( https://github.com/5am-code/laravel-notion-api
google-api-php-cient( https://github.com/googleapis/google-api-php-client

3. 同期したいGoogleカレンダーのカレンダーIDを調べる

20211119132243.png
カレンダー>カレンダーの設定>カレンダーID

4. Google Calendar APIの準備

https://liginc.co.jp/472637 を参考にして Google Calendar APIからGoogleカレンダーが参照できるようにする。

5. NotionAPIの準備

https://tektektech.com/notion-api/ を参考にして同期したいNotionのカレンダーがAPIから操作できるようにする。

6. 同期させたいNotionカレンダーのデータベースIDを調べる

https://zenn.dev/5t111111/articles/785fec8d21d82b を参考にしました。

7. Notion側のカレンダーに「googleCalendarId」というテキストのプロパティを追加

20211119142251.png

Laravelでバッチを作成

https://codelikes.com/laravel-batch-command/ を参考にしました。

1. .envに設定を追加

.env
NOTION_API_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxx
NOTION_DATABASE_ID=xxxxxxxxxxxxxxxxxxxxx

TIMEZONE=Asia/Tokyo

NotionのAPIトークンとカレンダーのデータベースIDを設定。
またGoogleカレンダーのタイムゾーンを設定しておく。

2. config/app.php

config/app.php
     /*
    |--------------------------------------------------------------------------
    | アプリ独自の定義
    |--------------------------------------------------------------------------
    |
    | デフォルトではない、後付けの定義
    |
    */
    'notion_database_id_of_calendar' => env('NOTION_DATABASE_ID', null),

.envファイルよりNotionカレンダーのデータベースIDを利用できるする。

3.構造体の準備

Console/Commands/GoogleCalendarSyncNotion.php
        $this->google_calendar_list = array (
            'personal' => array (
                'calendar_id' => (string)config('app.google_calendar_id_personal'),
                'notion_label' => '生活',
            ),
            'business' => array(
                'calendar_id' => (string)config('app.google_calendar_id_business'),
                'notion_label' => '仕事',
            ),
            'school' => array(
                'calendar_id' => (string)config('app.google_calendar_id_school'),
                'notion_label' => '学校',
            )
        );

        $this->google_holiday_calendar_list = array (
            'holiday' => array (
                'calendar_id' => (string)config('app.google_calendar_id_holiday'),
                'notion_label' => '祝日',
            )
        );

今回は個人用、仕事用、子供の学校用、日本の祝日の3つのカレンダーを同期させるため上記定数を準備する。
「notion_label」はNotionカレンダーに同期した際にラベル付けしたい文字列。

holidayモードを追加し、休日カレンダーは別スケジュールで実行されるようにする。

Console/Commands/GoogleCalendarSyncNotion.php
    public function handle()
    {
        // Mode
        if( $this->argument('mode') === 'holiday'){
            $calendar_list = $this->google_holiday_calendar_list;
        }else{
            $calendar_list = $this->google_calendar_list;
        }

4. メインロジック

Console/Commands/GoogleCalendarSyncNotion.php

        // 設定値(sync_max_days)に従い日数分のデータをSyncさせる
        $targetDateStart = (string)date("Y-m-d");
        $targetDateEnd = (string)date("Y-m-d", strtotime('+'. config('app.sync_max_days') .'day'));

設定値(SYNC_MAX_DAYS)に従って本日より何日分の予定を同期させるかを決定。

Console/Commands/GoogleCalendarSyncNotion.php
        // Google Calenterから指定日のデータを取得
        foreach (array_keys($calendar_list) as $key){
            if(is_null($calendar_list[$key]['calendar_id'])){
                continue;
            }                

            $events = array();  
            $googlecal = new GoogleCalendarModel;

            try{
                $events = $googlecal->getGoogleCalendarEventList( $targetDateStart, $targetDateEnd, $calendar_list[$key]['calendar_id']);
            }catch (\Exception $e){
                report($e);
                return Command::FAILURE;
            };

カレンダー毎に予定されているイベントを取得。

Console/Commands/GoogleCalendarSyncNotion.php

            foreach ($events as $event) {

                // このイベントがNotionに登録されているか検索
                try{
                    $collections = $notions->getCollectionsFromNotion($event->id);
                }catch(\Exception $e){
                    report($e);
                    return Command::FAILURE;
                }

                // 既にNotionに登録されているのでスルー
                if (count($collections)) {
                    continue;
                }

                // Notionに登録
                try{
                    $notions->registNotion($event, $calendar_list[$key]['notion_label']); // insert
                }catch(\Exception $e){
                    report($e);
                    return Command::FAILURE;
                }
            } 

イベントが既にNotionに登録されているかどうかを判断。Notion側に設定したテキストプロパティにGoogle Calendar Idを入れておいてその値で判断します。
未登録だったらNotionデータベースに追加。

5.Googleカレンダー用のロジック

Models/GoogleCalendarModle.php
    public function getGoogleCalendarEventList(string $targetDateStart, string $targetDateEnd, string $google_calendar_id)
    {
        // Googleカレンダーに登録されているデータを取得
        $client = $this->getClient();
        $service = new Google_Service_Calendar($client);

        $optParams = array(
            'maxResults' => 50,
            'orderBy' => 'startTime',
            'singleEvents' => true,
            'timeMin' => date('c', strtotime($targetDateStart ." 00:00:00")),
            'timeMax' => date('c', strtotime($targetDateEnd ." 23:59:59")), 
            'timeZone' => config('app.timezone'),
        );

        $results = $service->events->listEvents($google_calendar_id, $optParams);
        
        return $results->getItems();
    }

Googleカレンダーに登録されているデータを取得

6.Notionカレンダー用のロジック

Models/NotionModel.php
    public function getCollectionsFromNotion(string $googleCalendarId)
    {
        $notion = new Notion((string)config('app.notion_api_token'));

        // 現在Notionに登録されているデータを取得
        $sortings = new Collection();
        $filters = new Collection();
        $filters->add(
            Filter::textFilter("googleCalendarId", Operators::EQUALS, $googleCalendarId), 
        );
        $collections = $notion->database(config('app.notion_database_id_of_calendar'))
            ->filterBy($filters) // filters are optional
            ->query()
            ->asCollection();

        return $collections;
    }

テキストプロパティのGoogle Calendar Idをキーにしてデータを取得する。

7. バッチ登録

Console/Kernel.php
        $schedule->command('command:gcal-sync-notion')
            ->everyThirtyMinutes()
            ->timezone('Asia/Ho_Chi_Minh')
            ->between('6:00', '23:00');

        $schedule->command('command:gcal-sync-notion holiday')
            ->monthly()
            ->timezone('Asia/Ho_Chi_Minh');

とりあえず30分に一回動かす。夜中は動かなくていいやと思ったので6時~23時まで。
スケジュールは複数登録できることを知ったので 「holiday」モードを追加し休日カレンダーは1カ月に1回起動するように変更。

crontab
* * * * *	/usr/bin/php artisan schedule:run

20211119152247.png
こんな感じでそれぞれのカレンダーからイベントがラベル付きで追加されるようになりました。(アイコンはあとから手作業で追加してます)

8. 終わり

他のサービスを利用すれば同じようなことできそうですが、Laravelを勉強したかったので苦労しながら作ってみました。
Notionにデータを登録する際に(特に日本の祝日の場合は)アイコンを指定したかったけど今回使用したパッケージではまだできなかったようなので、Notionにデータ同期された後に手作業でアイコン付けてます。

https://github.com/BiaHoi-BaChien/multi-googlecalendar-sync-to-one-notioncalendar

GitHubでソースコードを公開しました。(2021/12/03 修正)

https://github.com/BiaHoi-BaChien/SyncMultiGoogleCalendarToOneNotionDatabase
リポジトリを作り直しました。(2022/04/26)

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5