PHP / Laravel / API / サービスアカウントで簡単にスプレッドシートを作りたい
Laravelフレームワーク環境下で、簡単にスプレッドシートを作ったり、更新したりできないものかと思いまして作成しました。
きっかけはスプレッドシートを活用して業務改善を行いたいというクライアントの要望になります。
G Suiteにはマイドライブと共有ドライブ(旧:チームドライブ)がありまして、共有ドライブに作る作り方がわからなかったので試行錯誤しました。
業務環境
- GoogleのG Suite Businessエディションを利用中。
- 共有ドライブが存在する。
Webアプリ環境
- PHP 7.1
- Laravel 5.5
- Composerにて、google/apiclient:"^2.0" 導入
google/apiclient:"^2.0"
GoogleがPHPから簡単にAPIを利用できるように用意してくれているライブラリです。
https://github.com/googleapis/google-api-php-client
以下のコマンドで導入できます。
composer.phar require google/apiclient:"^2.0"
すでにPHPのパスが通っている場合は以下のコマンドだったり、
composer.phar require google/apiclient:"^2.0"
パスが通ってない場合は以下のコマンドだったり、
php ./composer.phar require google/apiclient:"^2.0"
Composerのbatがある場合は .phar を省略できたりと、様々です。
composer require google/apiclient:"^2.0"
本題
App\Services
以下にサービスとして実装します。
APIを呼び出すにはGoogle_Client
が必要なので親サービスを作成して実装しました。
Google API Consoleでプロジェクトを作成して、認証情報でサービスアカウントを作成します。
この解説はたくさんネット上に出てるので省略します。
サービスアカウントを作成した時にダウンロードできる認証情報jsonを定数CREDENTIALS_PATH
にセットしています。
ここではstorage
ディレクトリ以下にtest_api_credential
ディレクトリを作成してその中に設置しています。
あらかじめ共有ドライブ内にAPP_DATA
フォルダを作成し、フォルダIDを取得しておきます。
定数APP_DATA
に共有ドライブのフォルダIDをセットします。
AbstractGoogleService
API共通で使える親サービスを作成します。
<?php
namespace App\Services;
use Google_Client;
class AbstractGoogleService
{
/**
* @var Credentials json
*/
const CREDENTIALS_PATH = __DIR__ . '/../../storage/test_api_credential/test api-xxxxxxxxxxxx.json';
/**
* @var 共有ドライブのフォルダID
*/
const APP_DATA = '0BC0P_ZneDOxfUk9PVB';
/**
* @var Google_Client
*/
protected $client;
/**
* constructer
*/
public function __construct()
{
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . self::CREDENTIALS_PATH);
$this->client = new Google_Client();
$this->client->useApplicationDefaultCredentials();
}
}
色々やってみたのですが、直接、共有ドライブにスプレッドシートは作成できないようです。
ですので、マイドライブにスプレッドシートを作成し、
そのマイドライブのスプレッドシートを共有ドライブにコピーして、
マイドライブのスプレッドシートを削除します。
結果的に、共有ドライブにスプレッドシートを作成することができます。
なんとも手間のかかる、、、
GoogleSheetsService
以下は、スプレッドシートタイトルをセットして、マイドライブにスプレッドシートを作成し、
スプレッドシートIDを返すメソッドです。
Google Sheets APIで実現しています。
<?php
namespace App\Services;
use App\Services\AbstractGoogleService;
use Google_Service_Sheets;
use Google_Service_Sheets_Spreadsheet;
class GoogleSheetsService extends AbstractGoogleService
{
/**
* @var Google_Service_Sheets
*/
private $service;
/**
* constructer
*/
public function __construct()
{
parent::__construct();
$this->client->addScope(Google_Service_Sheets::SPREADSHEETS);
$this->service = new Google_Service_Sheets($this->client);
}
/**
* スプレッドシートをマイドライブに作成する
*
* @param string|null $title スプレッドシートタイトル
* @return string Spreadsheet ID
*/
public function create($title = null)
{
// スプレッドシートタイトルをセットする
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => $title
],
]);
// スプレッドシートをマイドライブに作成する
$spreadsheet = $this->service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId',
]);
return $spreadsheet->spreadsheetId;
}
}
GoogleDriveService
次はGoogle Drive APIです。
ここでコピーと削除を行っています。
<?php
namespace App\Services;
use App\Services\AbstractGoogleService;
use Google_Service_Drive;
use Google_Service_Drive_DriveFile;
class GoogleDriveService extends AbstractGoogleService
{
/**
* @var Google_Service_Drive
*/
private $service;
/**
* constructer
*/
public function __construct()
{
parent::__construct();
$this->client->addScope(Google_Service_Drive::DRIVE);
$this->service = new Google_Service_Drive($this->client);
}
/**
* 指定したファイルIDで共有ドライブに移動する
*
* @param $fileId ファイルID
* @param $folderId フォルダID
* @return string Move File
*/
public function move($fileId, $folderId)
{
// 削除用にマイドライブのファイルIDの親IDを取得
$file = $this->service->files->get($fileId, [
'supportsAllDrives' => true,
'fields' => 'parents',
]);
$previousParents = implode(',', $file->parents);
// 共有ドライブにファイルをコピーして、マイドライブにあるファイルを削除する
$emptyFileMetadata = new Google_Service_Drive_DriveFile();
$moveFile = $this->service->files->update($fileId, $emptyFileMetadata, [
'supportsAllDrives' => true,
'addParents' => $folderId,
'removeParents' => $previousParents,
'fields' => 'name, id, parents',
]);
return sprintf("Move File: %s (%s) Folder: %s", $moveFile->name, $moveFile->id, implode(',', $moveFile->parents));
}
}
ApiController
作成したサービスをコントローラーから呼び出します。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Services\GoogleDriveService;
use App\Services\GoogleSheetsService;
class ApiController extends Controller
{
/**
* G Suite APIサンプル
*
* @param
* @return
*/
public function api(
Request $request,
GoogleDriveService $googleDriveService,
GoogleSheetsService $googleSheetsService
) {
/**
* スプレッドシートを共有ドライブに作成する
*/
// スプレッドシートをマイドライブに作成する
$title = 'スプレッドシート' . date('Y-m-d H:i:s');
$spreadsheetId = $googleSheetsService->create($title);
// 指定したスプレッドシートIDで共有ドライブに移動する
$moveString = $googleDriveService->move($spreadsheetId, GoogleDriveService::APP_DATA);
}
}
ルーティング
Laravelのルーティングはroutes\web.php
ですね。
URLで呼び出せるようにルーティングします。
Route::get('/api', 'ApiController@api')->name('api');
動作確認
http://127.0.0.1/api
http://localhost/api
http://your_settei_sita_domain/api
など設定したドメインでアクセスします。
- マイドライブにスプレッドシートが作成されていないこと。
- 共有ドライブにスプレッドシートが作成されていること。
が確認できると思います。