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

Cake PHP3のphpunitでコードカバレッジ見たいのに見られない

まずやったこと

【CakePHP3】PHPUnitでテストの自動化 – INSIGHT

こちらのサイトを参考にとりあえずcoverage吐かせてみました。

そしたら失敗。

$ vendor/bin/phpunit --coverage-html webroot/coverage tests/TestCase
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.

Error:         No code coverage driver is available

.......                                                             7 / 7 (100%)

Time: 170 ms, Memory: 12.00MB

OK (7 tests, 37 assertions)

「No code coverage driver is available」だそうです。

Xdebugは別途自分でインストールする必要があるみたいですね。

PHPUnit マニュアル – 第11章 コードカバレッジ解析

XdebugPHPUnit 本体には組み込まれていません。 テストを実行したときに Xdebug がロードできないという notice が出る場合は、 Xdebug がインストールされていないかあるいはうまく設定できていないのでしょう。 PHPUnit のコードカバレッジ機能を使う前に、まずは Xdebug のインストールガイド を読んでみましょう。

Xdebugのインストール

www.hardworker.jp こちらのサイト参考にインストールしました。

peclは使える前提です。

再実行

成功しました。

$ vendor/bin/phpunit --coverage-html webroot/coverage tests/TestCase
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.

.......                                                             7 / 7 (100%)

Time: 1.57 seconds, Memory: 14.00MB

OK (7 tests, 37 assertions)

Generating code coverage report in HTML format ... done

f:id:yoko_yoji:20180421180036p:plain

余談

邪魔くさいのでwebroot/coverageはgit管理外にしています。

.gitignore

/webroot/coverage
/webroot/coverage/*

AWSアカウントで最初にやっておくこと IAMの設定

はじめに

以前mastdonを試そうと思ってAWSアカウント作ったけれど、そういやとりあえず版の設定のままだったなと思い、IAM管理真面目に見直すことにしました。

たまたま業務でAWS触れることもあったので、復習がてら何か作ってみようとしているというのもあります。

やったこと

qiita.com

ここ見てやりました。

なお、補足をいくつか

MFAデバイスの準備

読む前の前提として、お手持ちのスマホGoogle Authentictorインストールしておく必要があります。

Google Authenticator

Google Authenticator

  • Google, Inc.
  • ユーティリティ
  • 無料

play.google.com

ユーザーへの設定が微妙に画面変わってる?

あと、ユーザーへのMFAデバイス割り当て、微妙に画面変わってますが、 認証情報の、ここの鉛筆マークから同じことができます。 f:id:yoko_yoji:20180421134907p:plain

割と何でもできるユーザーを一個作ることになるとは思うので、 二段階認証は入れておきましょう。

Sublime Text 3をインストールしたらまず初めにやること

はじめに

はじめまして。 一応Web & アプリエンジニアの端くれとして、備忘録でも残してみることにしました。

とりあえず自宅の開発環境作り直しているところなので、 お気に入りエディタ"Sublime Text 3"の環境設定メモでも残しておきます。

あと私の環境も晒しておきますね

そしてこれは2014/10/12現在の最新情報です。

必要なのはそれくらいか…

Sublime Text 3を入れる

Sublime Text 3の好きなところ

ほかにもいろいろありますが、重要なのはこの3点です。 特にviキーバインド大事です。eclipseなんかもviプラグインありますけど、 既存キーバーインドとかち合って謎の挙動したりして好きになれませんでした。

願わくばブログサービスとかも書くときはvi化したいなー。

Sublime Text 3のインストール

こちらからダウンロードします Sublime Text - Download

私はWin8.1 64bitなのでWindows 64 bitを選びます。

Sublime Text 3 is currently in beta. なんて書いてあるけど、とりあえず私が使ってる分には今のところ目立った不都合はないです。「枯れたの使いたい」派でもなければ3にした方がいいかと。

インストールプログラムをダウンロードしたらexeを実行してインストールしましょう。

Package Controllのインストール

これを入れると、Sublimeプラグインをお手軽に入れられるようになります。必須。

簡単なのはネット経由でのインストールです。

使い方の元ネタはこちら Installation - Package Control

要は、「Ctrl + `」でコマンドラインを出して、"SublimeText3"のタブに書いてあるコードを張り付けて実行しなさい、ということです。

完了したら、Ctrl+Shift+pを押した後、入力欄に、"pack"と入力してみて、候補に"Package Controll:ほにゃらら"がならんでいれば成功です。

日本語環境を整える

メニューやらなんやらを日本語化することと、 あとSublimeってそのままだと日本語入力がインライン化されないのでそれも対処します。

こんな感じですね。

f:id:yoko_yoji:20141012115847p:plain

あとは文字コード対応。なんとSublimeはデフォルトだとShift-jis対応していないという。

日本語メニュー

まずは、Ctrl+Shift+p⇒"pack"と入力⇒Package Controll:install packageを選んで、 出てきた窓に"japanize"と入れてください。

f:id:yoko_yoji:20141012120142g:plain

で、japanizeを選択。

パッケージのインストールが完了すると、設定ファイルいじる手順が表示されますので、 その通りに作業しましょう。 一応、引用しておきますね。

※隠しフォルダ非表示になってたりすると設定ファイルの場所が見つからなくなるので、 フォルダオプションから表示にしておきましょうね。

Package Control Messages

Japanize:

Japanese menu for Sublime Text 3

Sublime Text 3の日本語化プラグインです。
ゆーがいぶろぐさんの日本語化ファイルがベ>ースです。

適用手順
1.C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Japanizeにインストールされている*.jpファイルを、
   C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Default
  にコピーします。※Defaultフォルダがない場合は作成してください。
2.コピーしたファイルをオリジナルのファイル(.jpが付かないファイル)と置き換えます。>(念のため、オリジナルのファイルが有る場合は.orgなどを付けて保管しておきましょう。)
3.C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\Japanize\Main.sublime-menu(.jpが付かない方)を、
   C:\Users\ユーザー名\AppData\Roaming\Sublime Text 3\Packages\User
  にコピーします。すると、他のプラグインで上書きされてしまっているトップメニューも日本語化されます。
以上です。

日本語入力インライン化

次にインライン化のために、Package Controllから"IMESupport"をインストールします。もうPackage Controllの使い方はいいよね。

文字コード対応

あとは文字コード対応ですね。 Package Controllから、"ConvertToUTF8"を入れてください。

viキーバインド設定

実はSublimeにはデフォルトでviキーバインドが入ってたりします。 試しに、上のメニューから基本設定(もう日本語化されてるよね?)⇒基本設定-ユーザーを開いてください。

ちなみにこのエディタは、設定ファイルをjson形式で記述します。 jsonって何?って方はこちらを。

JSONってなにもの? | Think IT(シンクイット)

話を戻すと、設定ファイルはこんな感じになってるはずです。

{
    "ignored_packages":
    [
        "Vintage"
    ]
}

意味としては「インストールされてるパッケージからVintageってやつを無視しますよ」ってことです。なので、これのVintageを無視から外せばいいんですが、、、いかんせんこのVintageがイマイチなので、別のviパッケージを入れます。

Package Controllから"vintageous"を入れます。なんというか、これでVintageよりもう少しvimっぽくなります。

また、Sublimeキー設定のほうも多少いじってあげないとそれらしくならないので、 私は下記のようにしてます。

マルチラインモードをviっぽくつかう(要は矢印じゃなくて、j,kで上下したい)

   { "keys": ["ctrl+alt+k"], "command": "select_lines", "args": {"forward": false} },
    { "keys": ["ctrl+alt+j"], "command": "select_lines", "args": {"forward": true} },

gt,gTでのタブ移動

 {
        "keys": ["g", "t"],
        "command": "next_view",
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },
    {
        "keys": ["g", "T"],
        "command": "prev_view",
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },

ctrl+rでリドゥ

 {
        "keys": ["super+r"],
        "command": "redo"
    },

他はvi使いのお好みでどうぞ

その他設定

基本設定⇒基本設定-ユーザーにいろいろ設定してあげます。

コピペ用

 "ignored_packages":
    [
        "Vintage"
    ]
    {
    "default_encoding": "UTF-8",
    "draw_indent_guides": true,
    "draw_white_space": "all",
    "fallback_encoding": "UTF-8",
    "font_size": 10,
    "hot_exit": false,
    "indent_guide_options":
    [
        "draw_normal",
        "draw_active"
    ],
    "remember_open_files": false,
    "show_encoding": true,
    "tab_size": 2,
    "translate_tabs_to_spaces": false
    }

解説つき(コメントアウトっぽくしてるけどそのまま貼るとエラーだよ)

 "ignored_packages": // vintageousがあるので外す
    [
        "Vintage"
    ]
    {
    "default_encoding": "UTF-8", //エンコード指定
    "draw_indent_guides": true, // 空白文字などを表示するか
    "draw_white_space": "all", //表示対象の空白文字
    "fallback_encoding": "UTF-8", //コード不明時の文字コード
    "font_size": 10, // フォントサイズ
    "hot_exit": false, // 終了時のタブ復元。うざいので切る
    "indent_guide_options": //どのインデントにいるか見やすくする
    [
        "draw_normal",
        "draw_active"
    ],
    "remember_open_files": false, // hot_exitとセットで設定
    "show_encoding": true, //ステータスバーにエンコーディングを出す
    "tab_size": 2, //私は2タブが好きです
    "translate_tabs_to_spaces": false //ソフトタブは嫌いです
    }

全角スペースハイライト

これもプログラマとしては重要ですね

パッケージコントロールで"TrailingSpaces"入れます。 あとは、基本設定-ユーザーに下記を追記

 "trailing_spaces_regexp": " |[ \t]+",
    "trailing_spaces_highlight_color" : "comment"

そしてSublimeを再起動。

とりあえず以上。