24
15

More than 3 years have passed since last update.

Laravel 6.x(またはLumen 6.x)でDynamoDBに接続する

Last updated at Posted at 2019-11-15

SDKのインストール

AWS SDK for PHPをLaravelに取り込みましょう。
プロジェクトルートで下記コマンドを実行します。

$ composer require aws/aws-sdk-php

これでvendor配下にSDKがインストールされます。

DynamoDBに接続する

AWS SDK for PHPでつなぐにはこのようにします。

下記の例ではクレデンシャルを含めていますが、この方法は推奨されていないので注意してください
ハードコードされた認証情報の使用

use Aws\Sdk;

$awsSdk = new Sdk([
    'credentials' => [
        'key' => アクセスキー,
        'secret' => シークレットキー,
    ],
    'endpoint' => 'エンドポイント',
    'region'   => 'リージョン',
    'version'  => 'バージョン'
]);
$dynamo = $awsSdk->createDynamoDb();

以上。

Laravelらしくしよう

と、まあこれじゃあちょっとLaravelらしくないよね、ってことでDIしてみます。new禁止。

envに登録

dotEnv便利ですよね。

.env
AWS_DYNAMO_KEY=アクセスキー
AWS_DYNAMO_SECRET=シークレットキー
AWS_DYNAMO_ENDPOINT=エンドポイント
AWS_DYNAMO_REGION=リージョン
AWS_DYNAMO_VERION=バージョン

ServiceProviderを記述

LaravelでDIといえばServiceProviderですよね。

app/Providers/DynamoDbServiceProvider.php
<?php
declare(strict_types=1);

namespace App\Providers;

use Aws\DynamoDb\DynamoDbClient;
use Aws\Sdk;
use Illuminate\Support\ServiceProvider;

class DynamoServiceProvider extends ServiceProvider
{
    /**
     * Dynamo AWS-SDK接続
     */
    public function register()
    {
        $this->app->singleton(DynamoDbClient::class, function () {
            $awsSdk = new Sdk([
                'credentials' => [
                    'key' => env('AWS_DYNAMO_KEY'),
                    'secret' => env('AWS_DYNAMO_SECRET'),
                ],
                'endpoint' => env('AWS_DYNAMO_ENDPOINT'),
                'region' => env('AWS_DYNAMO_REGION'),
                'version' => env('AWS_DYNAMO_VERSION')
            ]);
            return $awsSdk->createDynamoDb();
        });
    }
}

Laravelなら config/app.phpのproviders に登録。

config/app.php
    'providers' => [
                App\Providers\DynamoServiceProvider::class,

Lumenならbootstrap/app.phpに登録します。

bootstrap/app.php
    $app->register(App\Providers\DynamoServiceProvider::class);

コンストラクタインジェクション

ここまでできたら、お好きな場所でインジェクションできます。Facadeにしてもいいかもですね。

    /**
     * @var DynamoDbClient
     */
    private $client;

    /**
     * constructor.
     * @param DynamoDbClient $client
     */
    public function __construct(DynamoDbClient $client)
    {
        $this->client = $client;
    }

Eloquentっぽくしよう

Dynamoにアクセスするのに毎回

$this->client->putItem($paramertes);

とかって書くのめんどいですよね。
普段使い慣れているEloquentやQueryBuilderっぽく、find()とかsave()とかdestory()とか使いたいです。

じゃあ、EloqentModelに変わる基底クラスを作っちゃいましょう。

DynamoModelを作る

たとえばこんな感じでしょうか。

<?php
declare(strict_types=1);

namespace App\Models\Dynamo;

use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\DynamoDbException;
use Aws\DynamoDb\Marshaler;
use Aws\Result;
use Illuminate\Support\Str;

/**
 * Class DynamoModel
 * @package App\Models\Dynamo
 */
class DynamoModel
{
    /**
     * @var string
     */
    protected $primaryKey = 'id';

    /**
     * @var string|null
     */
    protected $table = null;

    /**
     * @var DynamoDbClient
     */
    private $client;

    /**
     * @var Marshaler
     */
    private $marshaler;

    /**
     * DynamoModel constructor.
     * @param DynamoDbClient $client
     * @param Marshaler $marshaler
     */
    public function __construct(DynamoDbClient $client, Marshaler $marshaler)
    {
        $this->client = $client;
        $this->marshaler = $marshaler;
    }

    /**
     * @return string
     */
    public function getTable(): string
    {
        $tableName = $this->table ?? Str::snake(Str::pluralStudly(class_basename($this)));
        return env('APP_ENV', 'local') . '_' . $tableName;
    }

    /**
     * DynamoにINSERT
     * @param array $attributes
     * @return Result
     */
    public function save(array $attributes): Result
    {
        $marshalItem = $this->marshaler->marshalItem($attributes);
        $dynamoParameters = [
            'TableName' => $this->getTable(),
            'Item' => $marshalItem
        ];

        try {
            return $this->client->putItem($dynamoParameters);
        } catch (DynamoDbException $exception) {
            throw $exception;
        }
    }

    /**
     * Dynamoからレコード削除
     * @param array $ids
     */
    public function destroy(array $ids): void
    {
        foreach ($ids as $id) {
            $deleteParameter = [$this->primaryKey => $id];
            $marshalItem = $this->marshaler->marshalItem($deleteParameter);
            $dynamoParameters = [
                'TableName' => $this->getTable(),
                'Key' => $marshalItem
            ];
            try {
                $this->client->deleteItem($dynamoParameters);
            } catch (DynamoDbException $exception) {
                throw $exception;
            }
        }
    }

    /**
     * Dynamoから1件レコードを取得
     * @param int $id
     * @return array|null
     */
    public function find(int $id): ?array
    {
        $idParameter = [$this->primaryKey => $id];
        $marshalItem = $this->marshaler->marshalItem($idParameter);
        $dynamoParameters = [
            'TableName' => $this->getTable(),
            'Key' => $marshalItem
        ];
        try {
            $awsResult = $this->client->getItem($dynamoParameters)->get('Item');
            if (is_null($awsResult)) {
                return null;
            }
            return $this->marshaler->unmarshalItem($awsResult);
        } catch (DynamoDbException $exception) {
            throw $exception;
        }
    }
}

あとはこれを継承したModelをつかえば、EloquentみたいにDynamoにアクセスできるようになります。
必要に応じで、findOrFail()でもupdateOrCreate()でもはやしていけばいいのかなーと思います。

24
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
15