rikudou / psr6-dynamo-db
使用 AWS DynamoDB 实现的 PSR-6 和 PSR-16 缓存实现
Requires
- php: ^8.0
- async-aws/dynamo-db: ^1.0
- psr/cache: ^2.0 | ^3.0
- psr/simple-cache: ^1.0
- rikudou/clock: ^1.0
Requires (Dev)
- ext-json: *
- friendsofphp/php-cs-fixer: ^2.16
- jetbrains/phpstorm-attributes: ^1.0
- phpstan/phpstan: ^1.8
- phpunit/phpunit: ^9.3
Provides
README
用于在 DynamoDB 中存储缓存的库,实现了 PSR-6 和 PSR-16 接口。另请参阅该库的 Symfony 扩展包。
从版本 2 开始,该库使用轻量级的 async-aws/dynamo-db,而不是完整的 AWS SDK。
安装
composer require rikudou/psr6-dynamo-db
用法
用法非常简单,你只需要在构造函数中定义详细信息,然后像使用任何其他 PSR-6 或 PSR-16 实现一样使用它
<?php use Rikudou\DynamoDbCache\DynamoDbCache; use Rikudou\DynamoDbCache\DynamoDbCacheBuilder; use AsyncAws\DynamoDb\DynamoDbClient; $cache = new DynamoDbCache('dynamoTableName', new DynamoDbClient([])); // with custom field names $cache = new DynamoDbCache('dynamoTableName', new DynamoDbClient([]), 'customPrimaryKeyField', 'customTtlField', 'customValueField'); // using builder $cache = DynamoDbCacheBuilder::create('dynamoTableName', new DynamoDbClient([])) ->withPrimaryField('customPrimaryKeyField') ->withTtlField('customTtlField') ->withValueField('customValueField') ->build();
建议使用构建器来创建新实例。构建器是不可变的,每个方法都返回一个新的实例。
字段的默认值如下
- 主键 -
id
(字符串) - ttl 字段 -
ttl
(数字) - 值字段 -
value
(字符串)
在使用此库之前,你必须创建 DynamoDB 表。
基本示例
<?php use AsyncAws\DynamoDb\DynamoDbClient; use Rikudou\DynamoDbCache\DynamoDbCache; function get(string $key): string { $dynamoDbClient = new DynamoDbClient([ 'region' => 'eu-central-1', ]); $cache = new DynamoDbCache('cache', $dynamoDbClient); // the default field names are used - id, ttl and value $item = $cache->getItem($key); if ($item->isHit()) { return $item->get(); } // do something to fetch the item $result = '...'; $item->set($result); $item->expiresAfter(3600); // expire after one hour if (!$cache->save($item)) { throw new RuntimeException('Could not save cache'); } return $result; }
使用 PSR-16 接口的示例
<?php use AsyncAws\DynamoDb\DynamoDbClient; use Rikudou\DynamoDbCache\DynamoDbCache; function get(string $key): string { $dynamoDbClient = new DynamoDbClient([ 'region' => 'eu-central-1', ]); $cache = new DynamoDbCache('cache', $dynamoDbClient); // the default field names are used - id, ttl and value $value = $cache->get($key); if ($value !== null) { return $value; } // do something to fetch the item $result = '...'; if (!$cache->set($key, $result, 3600)) { throw new RuntimeException('Could not save cache'); } return $result; }
前缀
你可以使用前缀配置自动为 DynamoDB 中的所有键添加前缀,如下所示
<?php use Rikudou\DynamoDbCache\DynamoDbCacheBuilder; use AsyncAws\DynamoDb\DynamoDbClient; $cache = DynamoDbCacheBuilder::create('myTable', new DynamoDbClient([])) ->withPrefix('myCustomPrefix#') ->build(); $item = $cache->getItem('key1'); // fetches an item with key myCustomPrefix#key1 $key = $item->getKey(); // $key holds the full key including prefix, myCustomPrefix#key1
转换器
此实现通过使用转换器支持所有 \Psr\Cache\CacheItemInterface
实例,这些转换器将对象转换为 \Rikudou\DynamoDbCache\DynamoCacheItem
。请注意,转换过程中可能会丢失一些信息,特别是过期日期。
你可以为你的特定类编写自己的转换器,并包括对过期日期的支持,如下所示
<?php use Rikudou\DynamoDbCache\Converter\CacheItemConverterInterface; use Psr\Cache\CacheItemInterface; use Rikudou\DynamoDbCache\DynamoCacheItem; use Rikudou\Clock\Clock; use Rikudou\DynamoDbCache\Encoder\SerializeItemEncoder; class MyCacheItemConverter implements CacheItemConverterInterface { /** * If this methods returns true, the converter will be used */ public function supports(CacheItemInterface $cacheItem): bool { return $cacheItem instanceof MyCacheItem; } public function convert(CacheItemInterface $cacheItem): DynamoCacheItem { assert($cacheItem instanceof MyCacheItem); return new DynamoCacheItem( $cacheItem->getKey(), $cacheItem->isHit(), $cacheItem->get(), $cacheItem->getExpirationDate(), // this is a custom method from the hypothetical MyCacheItem new Clock(), new SerializeItemEncoder() ); } }
然后你需要将其注册到转换器中,并将转换器分配给缓存
<?php use Rikudou\DynamoDbCache\Converter\CacheItemConverterRegistry; use Rikudou\DynamoDbCache\DynamoDbCache; use AsyncAws\DynamoDb\DynamoDbClient; use Rikudou\DynamoDbCache\DynamoDbCacheBuilder; // you don't need to add the default one as well, it will be added automatically if it's missing $converter = new CacheItemConverterRegistry(new MyCacheItemConverter()); $dynamoClient = new DynamoDbClient([]); $cache = DynamoDbCacheBuilder::create('myTable', $dynamoClient) ->withConverterRegistry($converter) ->build(); $myOldCache = new MyCacheImplementation(); $cacheItem = $myOldCache->getItem('test'); // this is now an instance of MyCacheItem // your custom converter will get used to convert it to DynamoCacheItem // if you didn't supply your own converter, the \Rikudou\DynamoDbCache\Converter\DefaultCacheItemConverter // would be used and the information about expiration date would be lost $cache->save($cacheItem);
编码器
默认情况下,值使用 PHP 序列化器进行序列化。如果你想与其他语言的程序(或不同 PHP 程序,这些程序没有相同的类)共享缓存,你可以使用 \Rikudou\DynamoDbCache\Encoder\JsonItemEncoder
或编写自己的。
注意:JsonItemEncoder 在处理对象时会丢失信息,如果你需要存储对象信息,这个编码器可能不适合你。另一方面,如果你只存储标量数据或数组,JsonItemEncoder 就足够了。
使用 JsonItemEncoder
的示例
<?php use Rikudou\DynamoDbCache\DynamoDbCache; use Rikudou\DynamoDbCache\DynamoDbCacheBuilder; use AsyncAws\DynamoDb\DynamoDbClient; use Rikudou\DynamoDbCache\Encoder\JsonItemEncoder; $encoder = new JsonItemEncoder(); // with default flags and depth $encoder = new JsonItemEncoder(JSON_PRETTY_PRINT, JSON_THROW_ON_ERROR, 100); // with custom encode and decode flags and depth $cache = DynamoDbCacheBuilder::create('myTable', new DynamoDbClient([])) ->withEncoder($encoder) ->build();
现在你的值将以 JSON 编码的形式保存到 DynamoDB 中。
编写自己的编码器很简单,你只需要实现 \Rikudou\DynamoDbCache\Encoder\CacheItemEncoderInterface
接口
<?php use Rikudou\DynamoDbCache\Encoder\CacheItemEncoderInterface; class MyEncoder implements CacheItemEncoderInterface { /** * @param mixed $input * @return string */ public function encode($input) : string { // TODO: Implement encode() method. } /** * @param string $input * @return mixed */ public function decode(string $input) { // TODO: Implement decode() method. } }