処理方法を見直したので全体的に修正しました。(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を調べる
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」というテキストのプロパティを追加
Laravelでバッチを作成
https://codelikes.com/laravel-batch-command/ を参考にしました。
1. .envに設定を追加
NOTION_API_TOKEN=secret_xxxxxxxxxxxxxxxxxxxxxxxxxx
NOTION_DATABASE_ID=xxxxxxxxxxxxxxxxxxxxx
TIMEZONE=Asia/Tokyo
NotionのAPIトークンとカレンダーのデータベースIDを設定。
またGoogleカレンダーのタイムゾーンを設定しておく。
2. config/app.php
/*
|--------------------------------------------------------------------------
| アプリ独自の定義
|--------------------------------------------------------------------------
|
| デフォルトではない、後付けの定義
|
*/
'notion_database_id_of_calendar' => env('NOTION_DATABASE_ID', null),
.envファイルよりNotionカレンダーのデータベースIDを利用できるする。
3.構造体の準備
$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モードを追加し、休日カレンダーは別スケジュールで実行されるようにする。
public function handle()
{
// Mode
if( $this->argument('mode') === 'holiday'){
$calendar_list = $this->google_holiday_calendar_list;
}else{
$calendar_list = $this->google_calendar_list;
}
4. メインロジック
// 設定値(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)に従って本日より何日分の予定を同期させるかを決定。
// 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;
};
カレンダー毎に予定されているイベントを取得。
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カレンダー用のロジック
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カレンダー用のロジック
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. バッチ登録
$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回起動するように変更。
* * * * * /usr/bin/php artisan schedule:run
こんな感じでそれぞれのカレンダーからイベントがラベル付きで追加されるようになりました。(アイコンはあとから手作業で追加してます)
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)