Googleのカレンダーを連携するってなってなかなか大変だったメモ。色々と端折ってますが
ローカルだと公開URIがないからうまく出来なくてなかなか吐きそうだった・・・
にしても、PHPて変数のあたまの$を打つのがめんど
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Google_Client;
use Google_Service_Calendar;
use Google_Service_Calendar_Channel;
use Google_Service_Exception;
class SampleControoler
{
public function __construct()
{
$this->user = ユーザー情報;
// Googleオブジェクト作成
$googleClient = new Google_Client();
$googleClient->setAccessType('offline');
$googleClient->setApprovalPrompt('force');
// スコープの設定
$googleClient->setScope(Google_Service_Calendar::Calendar);
// storageに認証ファイル配置
$googleClient->setAuthConfig(storage_path('app/client_secret.json'));
$this->googleClient = $googleClient;
}
// Google認証
public function GoogleAuth()
{
// DBにアクセストークンがあるか
if(!empty($this->user->access_token)) {
// トークンの発行に失敗してるか
if(is_string($this->user->access_token)) {
// JSONを連想配列に
$ass_arr = json_decode($this->user->access_token, true);
// 失敗してたらG認証画面へ
if ($ass_arr && array_key_exists('error', $ass_arr)) return Redirect::to($this->googleClient->createAuthUrl())->send();
}
try {
// アクセストークンの有効期限をチェック。切れてたらrefreshトークンを使って再取得
if ($this->googleClient->isAccessTokenExpired()) {
if (!empty($this->user->refresh_token)) {
$access_token = $this->googleClient->fetchAccessTokenWithRefreshToken($this->user->refresh_token);
$access_token_json = json_encode($access_token);
// トークン更新
$this->user->fill(['access_token' => $access_token_json])->save();
$this->googleClient->setAccessToken($access_token);
}
}
// 無効なトークンはG認証画面へ
} catch(Google_Service_Exception $e ) {
Redirect::to($this->googleClient->createAuthUrl())->send();
}
// DBにトークンがなかったらG認証画面へ
} else {
Redirect::to($this->googleClient->createAuthUrl())->send();
}
}
// GoogleAuth()でGoogleの認証に行った後に動かすメソッド
public function oauth(Request $request)
{
try {
$this->_getUser($request);
// キャンセルされた場合
if ($request->has('error') && $request->error === 'access_denied') {
return Redirect::to($this->app_uri)->send();
}
$data = $this->googleClient->fetchAccessTokenWithAuthCode($request->input('code'));
$refresh_token = $data['refresh_token'];
// JSONごと保存(isAccessTokenExpiredで必要となるため)
$this->googleClient->setAccessToken(json_encode($data));
$user = User::find($this->user->id);
$user->fill([
'access_token' => $data,
'refresh_token' => $refresh_token,
])->save();
// チャンネル作成
// スケジュールの監視をする。ユーザー毎作成?
$this->create_channel();
// GoogleカレンダーとDBの同期
// TODOここもメソッドで分ける
$result_arr = array();
// 7日前までのデータを取得
$timeMin = (new \DateTime(date("Y-m-d H:i:s",strtotime(-7." day"))))->format(DATE_RFC3339);
// 7日後までのデータを取得
$timeMax = (new \DateTime(date("Y-m-d H:i:s",strtotime(7." day"))))->format(DATE_RFC3339);
$optParams = [
'timeMax' => $timeMax, // イベントの開始時間の上限
'timeMin' => $timeMin, // イベントの終了時間の下限
'timeZone' => 'Asia/Tokyo',
'singleEvents' => true, // 定期イベントを展開
];
DB::beginTransaction();
try {
$client_user_client = $this->getOAuth($client_user);
$client_user_service = new Google_Service_Calendar($client_user_client);
$client_user_events = $client_user_service->events->listEvents('primary', $optParams); //カレンダー情報一覧取得
$exists_calendar_id = [];
while (true) {
foreach ($client_user_events->getItems() as $key => $event) {
// この中でカレンダー情報をごにょごにょ
}
$pageToken = $client_user_events->getNextPageToken();
// スケジュール情報の次のページがあるとき
if ($pageToken) {
$optParams['pageToken'] = $pageToken;
$client_user_events = $client_user_service->events->listEvents('primary', $optParams);
// ないとき
} else {
$nextSyncToken = $client_user_events->getNextSyncToken();
$channel_model = Channel::where('user_id', $client_user->id)->first();
if ($channel_model && !empty($nextSyncToken)) {
$channel_model->fill(['nextSyncToken' => $nextSyncToken]);
$channel_model->save();
}
// なかったら終わり
break;
}
}
} catch (Exception $e) {
DB::rollback();
Log::error($e->getMessage());
}
return Redirect::to($this->app_uri)->send();
} catch (Exception $e) {
Log::error('oauth2: '.$e->getMessage());
}
}
// チャンネル作成
public function create_channel()
{
DB::beginTransaction();
try {
$user = $this->user;
$service = new Google_Service_Calendar($this->googleClient);
$calendarListEntry = $service->calendarList->get('primary');
$primary_id = $calendarListEntry->getId();
$primary_channel_model = Channel::where('calendar_id', $primary_id)->first();
// プライマリチャンネルが存在している場合
if ($primary_channel_model) {
// 有効期限チェック(24時間以内の場合、チャンネルの更新)
// expiration = 有効期限(ミリ秒)
$channel_expiration = $primary_channel_model->expiration / 1000;
$timestamp = time();
$hours = 1 * 60 * 60;
$diff_hours = ($channel_expiration - $timestamp) / $hours;
DB::rollback();
if ($diff_hours <= 25) {
$this->delete_channel($user, $primary_channel_model); // チャンネル削除
$this->create_channel(); // チャンネル追加
}
return;
}
// チャンネル登録
$channel = new Google_Service_Calendar_Channel($this->googleClient);
$channel->setId(time());
$channel->setType('web_hook');
// スケジュールを更新などしたときにwebhookが動く
// そのときに投げられるURIを設定する
$channel->setAddress($this->app_uri . 'api/webhook');
$watchEvent = $service->events->watch('primary', $channel);
// DB登録
$channel_model = new Channel;
foreach ($watchEvent as $key => $data) {
//リネーム id → channel_id
if ($key === 'id') {
$key = 'channel_id';
}
$channel_model->fill([$key => $data]);
}
$channel_model->fill([
'calendar_id' => $primary_id,
'user_id' => $user->id
]);
$channel_model->save();
DB::commit();
} catch (InvalidArgumentException $e) {
DB::rollback();
} catch (Google_Service_Exception $e) {
DB::rollback();
return false;
} catch (Exception $e) {
DB::rollback();
Log::error($e->getMessage());
}
}
}
コメント