DynamoDB + CakePHP3でデータを保存してみる

はじめに

RSSリーダーだの記事解析だのいろいろやってみたい&AWSのお勉強をしてみたいツマ・ヨーコです。こんばんわ。

なるべく疎結合な設計を目指して、

この辺は分離したくて、RSSフィードを何も考えずにぶち込む先としてDynamoDBとして採用してみました。

ただ、DynamoDB + CakePHP3でやりたいのだけれど、AWS SDK for PHPの情報が古いバージョンのものだったりして、てこずったのでメモ残します。

環境

コード

設定ファイル

    /**
     *
     * AWS SDK Setting
     *
     */
    'Aws' => [
        'includes' => ['_aws'],
        'services' => [
            'default_settings' => [
                'params' => [
                    'version' => '2012-08-10',//dynamo DBの場合はこの日付
                    'region' => 'us-east-1', //利用しているリージョン
                    'credentials' => [
                        'secret' => '<AWSコンソールから取得したもの>',
                        'key'    => '<AWSコンソールから取得したもの>',
                    ]
                ]
            ]
        ]
    ]

これをAPPROOT/config/app.phpに追加します。

ラッパークラス

<?php
namespace App\Model\Table; //これは各自の設計思想に応じて決めてください

use Cake\Core\Configure;
use Aws\Sdk;
use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\DynamoDbException;
use Aws\DynamoDb\Marshaler;


//Exceptionは何使うか見直した方がいいかも
use \Exception;

class AwsDynamoDb{

    protected $_table_name = null;
    protected $_pk_name = null;
    protected $_pk_type = null; //"int" or "string"
    protected $_sdk = null;
    protected $_dynamodb = null;
    protected $_marshaler = null;

    const TYPE_NAME_INT = 'int';
    const TYPE_NAME_STRING = 'string';

    public function __construct(String $table_name, String $pk_name, String $pk_type){
        $this->_table_name = $table_name;
        $this->_pk_name = $pk_name;
        
        //Dynamo DBへのリクエストJSONは、PKの型が間違ってるとエラーとなるため、
        //あらかじめはじいておきたい。
        if($pk_type != self::TYPE_NAME_INT && $pk_type != self::TYPE_NAME_STRING){
            throw new Exception('Invalid Dynamo DB Primary Key Type Setting.');
        }else{
            $this->_pk_type = $pk_type;
        }

        try{
            //SDKのセッティング
            $this->_sdk = new Sdk(Configure::read('Aws.services.default_settings.params'));

            //DynamoDBのセッティング
            $this->_dynamodb = $this->_sdk->createDynamoDb();

            //Mashalerのnew。このクラスを使って、jsonをDynamoDBでいい感じに格納するオブジェクトにする。
            $this->_marshaler = new Marshaler();

        }catch(DynamoDbException $e1){
            //とりあえず呼び出し元にぶん投げ。あとで考える。
            throw $e1;
        }catch(Exception $e2){
            //とりあえず呼び出し元にぶん投げ。あとで考える。            
            throw $e2;
        }
    }

    /**
     * putItemのラッパー
     */
    public function put($pk, $body){
        if(!$this->_check_pk_type($pk)) throw new Exception('Invalid Dynamo DB Primary Key Type.');

        $item_array = array_merge([$this->_pk_name => $pk],$body);
      
        //文字コードについてはあとで考える
        $item_json = json_encode($item_array);

        //DynamoDBテーブル名と格納データをセット
        //
        $item = [
            'TableName' => $this->_table_name,
            'Item' => $this->_marshaler->marshalJson($item_json)
        ];

        //putItem実行
        $result = $this->_dynamodb->putItem($item);
    }

    //Dynamo DBへのリクエストJSONは、PKの型が間違ってるとエラーとなるため        
    private function _check_pk_type($pk){
        if($this->_pk_type==self::TYPE_NAME_INT){
            if(!is_int($pk)){
                return false;
            }
        }elseif($this->_pk_type==self::TYPE_NAME_STRING){
            if(!is_string($pk)){
                return false;
            }
        }else{
            //通常ありえない
            throw new Exception('Invalid Dynamo DB Primary Key Type Setting.');
        }

        return true;
    }
}

呼び出し方

         $dynamo = new AwsDynamoDb('<AWSコンソールで作ったテーブル名>','<AWSコンソールで作ったPrimary Key>',AwsDynamoDb::TYPE_NAME_INT);
         $dynamo->put(10,['info'=>'aaa']);

結果

上手く入りました。 f:id:yoko_yoji:20180422225230p:plain f:id:yoko_yoji:20180422225324p:plain

ハマったところ

設定ファイルの構造

古いSDKだと

                'params' => [
                    'version' => 'latest',
                    'region' => 'us-east-1', //利用しているリージョン
                    'secret' => '<AWSコンソールから取得したもの>',
                    'key'    => '<AWSコンソールから取得したもの>',
               ]

こういう書き方らしく、

  • secetとkeyが認識されなくて困った。credentialsの下に入れないといけないらしい。
  • versionが日付じゃないとダメと怒られた

ちなみに、versionは

AWS SDK for PHP 3.x

こちらで確認できます。DynamoDBは2012-08-10 とこのと。

Amazon DynamoDB Aws\DynamoDb\DynamoDbClient 2012-08-10

と書いてあります。

Aws/Sdkを使え

古いSDKAws/Common/Awsクラスからクライアントを生成していたようで、参考ブログのマネしてuse Aws/Common/Awsとかしてもnot foundくらって悲しい思いをしていた。

Aws/Common/Awsは廃止されて、Aws/Sdkクラスを使えってことになってたみたいですね。

stackoverflow.com