【PHP + Google Drive API】アプリケーションから自動で共有ドライブにアクセスしてファイル操作する

# 実現すること
アプリケーション側からGoogleDriveの共有ドライブへ自動でファイルアップロードや検索を行いたい:nerd:

なお、共有ドライブを外部に公開する必要があるため、所属する組織の運営方針等を確認してから行いましょう。
わたしは外部公開しないで直接共有ドライブへファイル操作を行う方法は見つけられませんでした。

# GoogleDriveを操作する準備
やることは3つです。
1. GCPでサービスアカウントを作成
2. GoogleDrive側の設定
3. 共有ドライブにアクセスするためのパラメーター付与(アプリケーション側)

## GCPでサービスアカウントを作成
GCPへアクセスします。
共有ドライブを所有する当該組織とプロジェクトを作成または選択します。
ナビゲーションメニューより「APIとサービス」からGoogleDriveAPIの有効化しておきます。
サイドメニューより「IAMと管理」よりサービスアカウントを作成します。
その後、作成したサービスカウントに対して、JSONのcredental keyも作成しておきます。

## GoogleDrive側の設定
### 共有ドライブを許可された組織外のメンバーへの共有設定
:computer: Google Adminより
[アプリ] 次に [G Suite] 次に [ドライブとドキュメント] にアクセスします。
その後、[組織名] 以外のユーザーからのファイル受信を [組織名] のユーザーに許可するを選択します。
つまりアクセス権限をゆるくします。

:computer: GoogleDriveより
操作したい共有ドライブへアクセスします。
その後、`共有ドライブ名▼` より `共有ドライブの設定` を選択します。
ここからメンバー外ともファイルを共有できるように設定しておきます。
そして、先程作成したサービスアカウントのメールアドレスを共有ドライブのメンバーとして登録します。



## 共有ドライブにアクセスするためのパラメーター付与
環境はPHP 7.1.*, google/apiclient 2.0です。

### GoogleDriveを操作するための準備
```php:

class GoogleApiDrive
{
    private $service;

    public function __construct($credentials, $allow_scope_list)
    {
        $google_client = new Google_Client();
        $google_client->useApplicationDefaultCredentials();
        $google_client->setAuthConfig($credentials);
        $google_client->addScope($allow_scope_list);
    
        $this->service = new Google_Service_Drive($google_client);
     }
}
```

Google Drive を操作するためのインスタンスを生成します。
このあたりは他の記事でもよく紹介されていますね。

### 共有ドライブへリクエストするときの専用パラメーターが存在する
[Implement shared drive support](https://developers.google.com/drive/api/v3/enable-shareddrives)
公式ドキュメントによると `supportsAllDrives=true` を付与することで共有ドライブへアクセスを前提としたアプリケーションであることをGoogleDrive側へ通知できるようです。
このパラメーターをApiClientの各メソッドのリクエスト時に付与してあげれば共有ドライブを操作できるようになるわけです。

### 共有ドライブへファイル検索メソッドの実装
```php

    public function getDriveFilesByFolderIdFromSharedDrive(string $drive_id, string $folder_id)
    {
        $query =  "'" . $folder_id . "' in parents";
        $result = $this->service->files->listFiles([
            "corpora" => "drive",
            "includeTeamDriveItems" => true,
            "supportsTeamDrives" => true,
            "teamDriveId" => $drive_id,
            "q" => $query,
        ]);
        return $result->getFiles();
    }
```
`supportsTeamDrives`が`supportsAllDrives`に該当するパラメーターになります。
ほかのパラメーターは検索順位をどうするか？といった設定になり、こちらも必須になります。たぶん実行結果が変わるんじゃないでしょうか:nerd:
マイドライブにアクセスするときとは違い`teamDriveId`が必須になります。
なぜならフォルダーに対してのメンバーになったわけではなく、共有ドライブのメンバーであり、そのメンバーとなったドライブのIDを特定してあげる必要があるからです。

### 共有ドライブへフォルダ・ファイル作成メソッドの実装
フォルダ作成は以下のようなメソッドになります。

```php
    $file_metadata = new Google_Service_Drive_DriveFile([
        'name' => 'folder name',
        'mimeType' => 'application/vnd.google-apps.folder',
        'parents' => [$folder_id],
    ]);
    $options = [
        'fields' => 'id',
        'supportsTeamDrives' => true,
    ];

    public function createFile(Google_Service_Drive_DriveFile $file_metadata, array $options)
    {
        $file = $this->service->files->create($file_metadata, $options);
        return $file;
    }
```
`$options`の方に検索でお馴染みの`supportsTeamDrives`をセットします。

つぎはファイル作成、CSVファイルを作成する想定のメソッドになります。

```php
    $file_metadata_csv = new Google_Service_Drive_DriveFile([
        'name' => $csv_name . '.csv',
        'parents' => [$folder_id],
    ]);
    $options = [
        'data' => $content,
        'mimeType' => 'text/csv',
        'uploadType' => 'resumable',
        'fields' => 'id',
        'supportsTeamDrives' => true,
    ];

    public function createFile(Google_Service_Drive_DriveFile $file_metadata, array $options)
    {
        $file = $this->service->files->create($file_metadata, $options);
        return $file;
    }
```
ほぼ同じです。`mimeType`をいじることでアップロードするファイルの種別を変更していきます。
`resumable`はアップロードするファイルが巨大な場合必要になります。

以上、どなたかの助けになりましたら幸いです。:nerd: