omnilog/psr6-dynamo-db-bundle

PSR-6 and PSR-16 cache implementation using AWS DynamoDB for Symfony

0.0.1 2021-05-26 10:11 UTC

This package is auto-updated.

Last update: 2024-04-26 21:31:31 UTC


README

Tests Coverage Status

Don't use Symfony? Use the standalone library.

Installation

composer require omnilog/psr6-dynamo-db-bundle

Configuration

Create the file config/packages/dynamo_db_cache.yaml and put at least the table name there:

omnilog_dynamo_db_cache:
    table: myCacheTableName

Everything else has default values, though you probably want to also configure the dynamo db client.

Configuration options:

  • replace_default_adapter - set to true to replace the default AdapterInterface and CacheInterface implementation with the adapter from this bundle (default: false)
  • table - the table which will be used for storing the cache (required)
  • client_service - The service that will be used as DynamoDB client, if not set this bundle will try to create one (more details in client_config option below) but the use is limited
  • client_config - If no client_service is configured, it will be created from the values of this config. It contains two subkeys:
    • region - the AWS region (default: us-east-1)
    • version - the service version (default: latest)
    • no other options are available, if you need to configure more, please create and assign custom client_service
  • encoder - contains the settings for encoders:
    • service - the service which will be used as the encoder
      • can be one of built-in services (omnilog.dynamo_cache.encoder.serialize, omnilog.dynamo_cache.encoder.json)
      • can be a custom service implementing the \Omnilog\DynamoDbCache\Encoder\CacheItemEncoderInterface interface
      • default value: omnilog.dynamo_cache.encoder.serialize
    • json_options - settings for the json encoder, ignored if another encoder is used
      • encode_flags - the same flags you would pass to json_encode()
      • decode_flags - the same flags you would pass to json_decode()
      • depth - the depth argument for both json_encode() and json_decode()
  • primary_key_field - the name of the field that will be used as the primary key (default: id)
  • ttl_field - the name of the field that will be used as the ttl field (default: ttl)
  • value_field - the name of the field that will be used as the value field (default: value)
  • key_prefix - the prefix used in front of the item keys (default: null which means none)

Autogenerated default config (via bin/console config:dump omnilog_dynamo_db_cache):

# Default configuration for extension with alias: "omnilog_dynamo_db_cache"
omnilog_dynamo_db_cache:

    # Replace default cache adapter with this one
    replace_default_adapter: false

    # The DynamoDB table to use as cache
    table:                null

    # The service to use as the Dynamo DB client
    client_service:       null

    # The Dynamo DB client configuration. If you need finer tuning, create the service yourself and assign it in client_service
    client_config:

        # The AWS region
        region:               us-east-1

        # The service version
        version:              latest
    encoder:

        # The service to be used as the encoder/decoder
        service:              omnilog.dynamo_cache.encoder.serialize

        # Settings for the json encoder
        json_options:

            # The flags that will be passed when encoding
            encode_flags:         0

            # The flags that will be passed when decoding
            decode_flags:         0

            # The depth of the JSON parsing for encoding/decoding
            depth:                512

    # Session related configuration
    session:

        # The ttl for the session, defaults to ini setting session.gc_maxlifetime
        ttl:                  null

        # The prefix for sessions
        prefix:               session_

    # The field to be used as primary key
    primary_key_field:    id

    # The field to be used as ttl
    ttl_field:            ttl

    # The field to be used as value
    value_field:          value

    # The prefix used in front of keys when storing
    key_prefix:           null

Usage

You can use one of the two available services:

  • Omnilog\DynamoDbCache\DynamoDbCache - this one doesn't implement the Symfony AdapterInterface nor CacheInterface
  • Omnilog\DynamoDbCacheBundle\Cache\DynamoDbCacheAdapter - this one implements the Symfony AdapterInterface and CacheInterface

If you set the replace_default_adapter to true you can also use these interfaces as services:

  • Symfony\Component\Cache\Adapter\AdapterInterface - the Symfony interface for PSR-6 cache
  • Symfony\Contracts\Cache\CacheInterface - the Symfony interface for simple cache
  • Psr\Cache\CacheItemPoolInterface - the PSR-6 interface
  • Psr\SimpleCache\CacheInterface - the PSR-16 interface

Example

<?php

use Omnilog\DynamoDbCacheBundle\Cache\DynamoDbCacheAdapter;
use Omnilog\DynamoDbCache\DynamoDbCache;
use Symfony\Contracts\Cache\ItemInterface;

class MyService
{
    public function __construct(DynamoDbCache $cache, DynamoDbCacheAdapter $adapter)
    {
        // it doesn't matter whether you use the adapter or not, the usage for PSR-6 is the same, the
        // only difference is that adapter implements the Symfony interface and thus you can
        // use it to replace the default AdapterInterface implementation
        $item = $cache->getItem('test');
        $item2 = $adapter->getItem('test');
    
        $item->set('some value');
        $adapter->save($item);

        // or using the CacheInterface api
        $value = $adapter->get('test', function (ItemInterface $item) {
            $item->expiresAfter(3600);
            return 'new-cache-value';
        });

        $cache->delete('test');
    }
}

While using the replace_default_adapter option:

<?php

use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

class MyService
{
    public function __construct(AdapterInterface $cache)
    {
        $item = $cache->getItem('test');
        // do stuff with cache item
        $cache->save($item);
    }
}

class MyService2
{
    public function __construct(CacheInterface $cache)
    {
        $cache->get('test', function (ItemInterface $item) {
            return 'new-value';
        });
    }
}

Or using the PSR interfaces:

<?php

use Psr\Cache\CacheItemPoolInterface;
use Psr\SimpleCache\CacheInterface;

class MyService
{
    public function __construct(CacheItemPoolInterface $psr6cache, CacheInterface $psr16cache)
    {
        $item = $psr6cache->getItem('test');
        $value = $item->get();
        $item->set('newValue');
        $item->expiresAfter(120);
        $psr6cache->save($item);
    
        $value = $psr16cache->get('test');
        $psr16cache->set('test', 'newValue', 120);
    }
}

Converters

This bundle supports all instances of \Psr\Cache\CacheItemInterface with the use of converters which convert the object to \Omnilog\DynamoDbCache\DynamoCacheItem. Note that some information may be lost in the conversion, notably expiration date.

This bundle has a handler for the default Symfony \Symfony\Component\Cache\CacheItem where it retains also the information about expiration date.

If you use any other CacheItemInterface implementation, you may need to write your custom handler:

<?php

use Omnilog\DynamoDbCache\Converter\CacheItemConverterInterface;
use Psr\Cache\CacheItemInterface;
use Omnilog\DynamoDbCache\DynamoCacheItem;

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
        );
    }
}

Your converter is now automatically registered in the converter system and will be used whenever you try to save an instance of MyCacheItem.

If you don't use autoconfiguration, tag your service with omnilog.dynamo_cache.converter

The default converter which will be used as last option can convert all CacheItemInterface objects but has no way to get the expiration date since the interface doesn't provide such information.