Google Cloud Client Library for PHPを使ってDatastoreを操作

仕事でCloud Datastoreを使うことになったのでいろいろ調べていこうと思います。

今回はGoogle Compute Engine（GCE）上でインスタンスを作成し、PHPからDatastoreを操作するまでの流れを簡単にまとめました。

動作確認はGoogle Cloud Client Library for PHPのサンプルプログラムを使ってます。
（サンプルプログラムは https://github.com/GoogleCloudPlatform/google-cloud-php#google-cloud-datastore を参照）


## 前提条件
Google Cloud Platform（GCP）が利用出来る状態で１つ以上のプロジェクトを作成済み


## 環境構築
OS：Debian8
言語：PHP5.6
クライアントライブラリ：Google Cloud PHP v0.11.1

`Compute Engine > VMインスタンス > インスタンスを作成` からインスタンスを新規に作成します。
サンプルコードを動かすだけなので各項目は基本すべてデフォルトでいいのですが、「ID と API へのアクセス」のところは「各APIにアクセス権を設定」にチェックを入れてCloud Datastoreを有効にして下さい。

<img width="533" alt="スクリーンショット 2016-11-01 14.20.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/113045/89ec6b5d-95a5-31ed-c281-0ef66cf63345.png">

Datastoreを有効にしないとプログラム実行時に以下のようなエラーが出て処理が失敗するので注意して下さい。

```
PHP Fatal error:  Uncaught exception 'Google\Cloud\Exception\ServiceException' with message '{
  "error": {
    "code": 403,
    "message": "Request had insufficient authentication scopes.",
    "status": "PERMISSION_DENIED"
  }
}
```

## クライアントライブラリをインストール
作成したインスタンスへSSH接続して以下を実行して下さい。

PHPインストール

```
sudo apt-get update

sudo apt-get install -y php5

php -v
PHP 5.6.26-0+deb8u1 (cli) (built: Sep 21 2016 12:37:50) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
```
comporserインストール

```
curl -sS https://getcomposer.org/installer | php

sudo mv composer.phar /usr/local/bin/composer
```

PHPクライアントライブラリをインストール

```
composer require google/cloud
```


## サンプルプログラムを使って動作確認
https://github.com/GoogleCloudPlatform/google-cloud-php#google-cloud-datastore

こちらにあるサンプルプログラムを動かしてみます。

```php:test.php
require 'vendor/autoload.php';

use Google\Cloud\Datastore\DatastoreClient;

$datastore = new DatastoreClient([
    'projectId' => 'my_project' // ここは自分のプロジェクトIDに変更
]);

// Create an entity
$bob = $datastore->entity('Person');
$bob['firstName'] = 'Bob';
$bob['email'] = 'bob@example.com';
$datastore->insert($bob);

// Fetch an entity
$key = $datastore->key('Person', 'Bob');
$bob = $datastore->lookup($key);

// Update an entity
$bob['email'] = 'bobv2@example.com';
$datastore->update($bob);
```

プログラムが実行されると種類はPersonでプロパティはemailとfirstNameの２つを持つエンティティが作成され、その後emailの値をbob@example.comからbobv2@example.comへ変更されます。

それでは実行してみます。

```
php test.php
```

実行結果です。

```
PHP Catchable fatal error:  Argument 1 passed to Google\Cloud\Datastore\DatastoreClient::update() must be an instance of Google\Cloud\Datastore\Entity, array given ・・・・
```

サンプルプログラムを実行するとPHPのエラーが出てエンティティのupdateに失敗しました。
エラーメッセージにはupdate()の引数は「instance of Google\Cloud\Datastore\Entity」でないといけないところ、配列が渡されていると書かれています。

エンティティを見てみると、エンティティの作成は成功しているようでした。

<img width="804" alt="スクリーンショット 2016-11-01 16.35.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/113045/c5119daa-cf4a-6803-f839-98818e185df1.png">

エンティティのupdateの失敗の原因は以下の部分で、

```
// Fetch an entity
$key = $datastore->key('Person', 'Bob');
$bob = $datastore->lookup($key);
```

`$datastore->lookup($key)` の結果がNULLとなるためでした。
$keyの値がおかしいためかちゃんと結果が取得できないようです。

`$datastore->key('Person', 'Bob')`の部分を調べてみると、メソッドkeyの第1引数はkind（種類）、第２引数はID or nameとなってました。

詳細はこちらを参照して下さい。
http://googlecloudplatform.github.io/google-cloud-php/#/docs/v0.11.1/datastore/datastoreclient?method=key

先ほど動かしたプログラムでは第２引数は'Bob'となっているのでIDではなく、nameを指定していました。
しかし先ほど作成されたエンティティをよく見てみるとnameではなくID（ID=5685265389584384）で作成されています。
<img width="559" alt="スクリーンショット 2016-11-01 18.30.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/113045/a405b620-3325-3e0e-9c09-fdc2d363f04e.png">

`$datastore->key('Person', 'Bob')`の部分を`$datastore->key('Person', '5685265389584384')`とするとエラーはなくなるのですが、エンティティの作成部分を次のように修正すれば`$datastore->key('Person', 'Bob')`のままでうまくいきそうです。

```php
// Create an entity
// $bob = $datastore->entity('Person'); // ここはコメントアウト
$key = $datastore->key('Person', 'Bob'); // kind=Person、name=Bob
$bob = $datastore->entity($key);
$bob['firstName'] = 'Bob';
$bob['email'] = 'bob@example.com';
$datastore->insert($bob);
```

実行結果です。
名前=Bobでエンティティが作成され、emailの値を`bobv2@example.com`に変更することに成功しました。
<img width="589" alt="スクリーンショット 2016-11-01 18.42.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/113045/f3282161-3a30-a0da-275f-43bff2903f63.png">


最終的に実行したプログラムは以下のようになります。

```php:test.php
<?php
require 'vendor/autoload.php';

use Google\Cloud\Datastore\DatastoreClient;

$datastore = new DatastoreClient([
    'projectId' => 'my_project' // ここは自分のプロジェクトIDに変更
]);


// Create an entity
$key = $datastore->key('Person', 'Bob');
$bob = $datastore->entity($key);
$bob['firstName'] = 'Bob';
$bob['email'] = 'bob@example.com';
$datastore->insert($bob);


// Fetch an entity
$key = $datastore->key('Person', 'Bob');
$bob = $datastore->lookup($key);


// Update an entity
$bob['email'] = 'bobv2@example.com';
$datastore->update($bob);
```

## おわりに
サンプルプログラムを動かした程度ですが、GCE上ではPHPクライアントを使ってDatastoeの操作は簡単にできました。
今回はエンティティの作成と更新を行いましたが、次回はGQLの理解を深めていきたいと思います。