GoogelCalendarに連携してFullCalendarでエベントを表示する手順

#FullCalendarとは
　FullCalendarはオプンソースでエベントを表示するため作られたJavaScriptプラグインです。イメージは以下のようになります。見た目はGoogleカレンダーと似ているものです。

![スクリーンショット 2016-10-05 13.12.56.png](https://qiita-image-store.s3.amazonaws.com/0/139068/f3805cfa-087e-e4ef-9199-8741c332b94e.png)

導入する手順は以下のリンクに参照してください。

＞[FullCalendar Download](https://fullcalendar.io/download/)

　FullCalendarはすでにGoogleCalendarに連携してエベントを表示するモジュールを持っていますが試してみたらそれはあくまでも自分の公開されているカレンダーのみの表示をサポートしているのは可能です。そういうわけで皆に共有してもらったエベントはGoogleCalendarのサイトでのように表示できないようです。

＞[FullCalendar - Google Calendar](https://fullcalendar.io/docs/google_calendar/)

　僕はやりたいのはGmailのシステムアカウントは一つあって皆がこのシステムアカウントに自分のカレンダーを共有してくれて、それでシステムにアクセスすれば共有したカレンダーを統合１画面で全て表示できるようになるのです。インターネットで見つけたソリューションを幾つか試してみましたけれどもやっぱり自ら開発した方がいいと思いますのでGoogleAPIのPHP番を用いていくことにしました

＞[Google Calendar API](https://developers.google.com/google-apps/calendar/quickstart/php)

#Google Calendar APIを用いる策

##事前準備
- GoogleCalendarAPIのPHP番の導入

```bash
$php composer.phar require google/apiclient:^2.0
``` 
- 持っているシステムアカウントのGoogle Calendar APIを有効にする
  1. この[ウィザード](https://console.developers.google.com/start/api?id=calendar)に従ってプロジェクトを作成してAPIを有効にする
   ![スクリーンショット 2016-10-05 13.58.05.png](https://qiita-image-store.s3.amazonaws.com/0/139068/d5b4ac10-7c5a-9b1f-89de-bc3976467dde.png)
  2. 認証情報でOAuth ClientIDの認証情報を作成する
  ![スクリーンショット 2016-10-05 14.02.22.png](https://qiita-image-store.s3.amazonaws.com/0/139068/159942c5-92be-cdbe-5f2b-1f13518786a4.png)
  3. Web Applicationをアプリケーション種類として指定する
　![スクリーンショット 2016-10-05 14.03.57.png](https://qiita-image-store.s3.amazonaws.com/0/139068/12427f1c-9f92-3e95-791e-393cca07fc95.png)
**Authorized redirect URIs**は認証した後成功した場合の認証コードあるいは失敗したのエラーメッセージを送る場所を指定するところです。
例：
![スクリーンショット 2016-10-05 15.27.53.png](https://qiita-image-store.s3.amazonaws.com/0/139068/adc0b463-514e-86e3-dbfc-2f43376222bb.png)
  4. Download JSONを押して認証するに必要な情報を一ファイルでまとめてダウンロードする。(例えば：calendar-php-globalhrm.jsonという名前でダウンロードしてProjectのConfigフォルダーの下に置いておいてください）

## サーバーサイドのソース

```config\ooglecalendar.php
return [
    'application_name' => 'global_hrm',
	'scope' => [
		\Google_Service_Calendar::CALENDAR_READONLY
	],
	'auth'=> [
		'config' => config_path().'/'.'calendar-php-globalhrm.json',
	]
];
```

```route.php
	Route::get('calendar/google' , ['as'=>'api.calendar.google', 'uses'=>'GoogleCalendarController@googleCalendar']);
	
        /*
         * Google API Consoleで指定したURLと一緒
         */
	Route::get('calendar/access_token' , ['as'=>'api.calendar.access_token', 'uses'=>'GoogleCalendarController@accessToken']);
```

```App\Http\Controllers\GoogleCalendarController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Config;
class GoogleCalendarController extends Controller
{
	private static $client = null;
	
	private static $service = null;
	
        /*
         *  認証された後GoogleAPIサービスが認証結果を指定したリダイレクトURIの後ろにつけて返す
         *  成功の場合：認証コードを返す
         *  失敗の場合：失敗した理由をメッセージで返す
         */
	public function accessToken(Request $request){
		//ログアウトの場合
		if ($request->has('logout')){
			
			$request->session()->forget('google_access_token');
			
			return json_encode(['succcess'=>true,'message'=>'User has been logged out.']);
		}
　　　　　　　　　//認証は成功でしたのでcodeをSessionに保存しておく
		if ($request->has('code')){
			
			$authCode = $request->input('code');
			
			$request->session()->put('authentication_code', $authCode);
			
                        /*
                         *  route("api.calendar.google")
                         */
			return redirect()->route("api.calendar.google");
		
		}else{
			//失敗の場合は失敗理由を受け取ってCallerへ返す
			return json_encode(['succcess'=>true,'message'=>$request->input('error')]);
			
		}
	}
	/* 
         * Clientのインスタンスを生成する
         */
	private function getGoogleCalendarClient(Request $request) {
		//初期化でアクセス情報を指定する
		if (null === self::$client) {
			self::$client = new \Google_Client();
			self::$client->setApplicationName(Config::get('googlecalendar.application_name'));
			$scope = implode(' ', Config::get('googlecalendar.scope'));
			self::$client->setScopes($scope);
			
			self::$client->setAuthConfig(Config::get('googlecalendar.auth.config')); //GoogleConsoleで生成したファイルを指定する
			self::$client->setRedirectUri(route('api.calendar.access_token'));
			self::$client->setAccessType('offline');
			self::$client->setApprovalPrompt('force');
				
		}
		$client = self::$client;
		
                //AccessTokenを持っている場合に
		if ($request->session()->has('google_access_token')) {
			//有効期限は切られたかどうかの確認
			if ($client->isAccessTokenExpired()) {
				//google_refresh_tokenは一回目の認証で返してもらえる。二回目からは返したaccesstokenに入れないのでSessionに保存するのは必須
				$refreshToken = $request->session()->get('google_refresh_token');
				$client->fetchAccessTokenWithRefreshToken($refreshToken);				
				$request->session()->put('google_access_token', json_encode($client->getAccessToken()));
			}
			return array('auth'=>true,'client'=>$client);
		}else{
                        //authentication_codeのみを持っている時コードからaccesstokenに変換するのは必要です
			if($request->session()->has('authentication_code')){
				
				$authCode= $request->session()->get('authentication_code');
				
				$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
				
				$refreshToken = $accessToken['refresh_token'];
				
　　　　　　　　　　　　　　　　　 //ここだけでrefresh_tokenを取れるので保存しておく。
				$request->session()->put('google_access_token', json_encode($accessToken));
				
				$request->session()->put('google_refresh_token', $refreshToken);
				
				$client->setAccessToken($accessToken);
				
				$client->refreshToken($refreshToken);
				
				$request->session()->forget('authentication_code');
				
			}else{
				//認証されていない場合は認証するページを生成して返す
				$authUrl = $client->createAuthUrl();
				
				return array('auth'=>false,'url'=>$authUrl);
			}
		}
	}
	public function googleCalendar(Request $request){
		
		try{
			
			$result = $this->getGoogleCalendarClient($request);
			// Everything is ok
			if ($result['auth'] == true){
				
				if (null === self::$service) {
					self::$service = new \Google_Service_Calendar($result['client']);
				}
				$service = self::$service;
				
				if($request->has('calendar_id')){
					$calendarId = $request->input('calendar_id');
				}else{
					$calendarId = 'primary';
				}
				
				$optParams = array(
						'maxResults' => 10,
						'orderBy' => 'startTime',
						'singleEvents' => TRUE,
						'timeMin' => date('c'),
				);
				$results = $service->events->listEvents($calendarId, $optParams);
				if (count($results->getItems()) == 0) {
					$events = array();
				} else {
					$events = array();
                                        //FullCalendarがわかる形に変換する
					foreach ($results->getItems() as $item) {
							
						$event = array();
						$event['id']    =   $item->getID();
						$event['title'] =   $item->getSummary();
						/*
						 * Start Date
						 */
						$start = $item->start->dateTime;
						if (empty($start)) {
							$start = $item->start->date;
						}
						$event['start'] =   $start;
						/*
						 * End Date
						 */
						$end = $item->end->dateTime;
						if (empty($start)) {
							$end = $item->end->date;
						}
						if($start==$end)
							$event['allDay'] =  true;
							else
								$event['allDay'] =  false;
								$event['start'] =   $start;
								$event['end'  ] =   $end;
								$event['backgroundColor'] =  "#f56954";//red
								$event['borderColor'] =  "#f56954";    //red
								$event['url'] = $item->gethtmlLink();
								$events[] = $event;
					}
					//return redirect()->to(self::$sourceUrl)->with('events', $events);
				}
                                //eventsをそのままFullCalendarに渡せば表示してもらうはず
				return json_encode(['success'=>true,'redirect'=>false, 'events'=>$events]);
			}else{
				//return redirect()->to($result['url']);
                                //認証するページへの移動は必要
				return json_encode(['success'=>true,'redirect'=>true,'url'=>$result['url']]);
			}
		}catch(Exception $e){
			return json_encode(['success'=>false, 'message'=>$e->getMessage()]);
		}
		
	}
}
```

以上、