v2: Updates

* Simplifies & beautifies everything
* Introduces a new Class system.
* Errors are defaulted to AWS's handler.
* New function names & more efficient handling.
* Should fix a majority of the errors.

Please read the README for more!
This commit is contained in:
Devang Srivastava 2020-09-28 15:32:51 +05:30
commit e6d7753dc8
1095 changed files with 45088 additions and 2911 deletions

View file

@ -4,9 +4,11 @@ namespace Aws\DynamoDb;
use Aws\Api\Parser\Crc32ValidatingParser;
use Aws\AwsClient;
use Aws\ClientResolver;
use Aws\Exception\AwsException;
use Aws\HandlerList;
use Aws\Middleware;
use Aws\RetryMiddleware;
use Aws\RetryMiddlewareV2;
/**
* This client is used to interact with the **Amazon DynamoDB** service.
@ -47,26 +49,50 @@ use Aws\RetryMiddleware;
* @method \GuzzleHttp\Promise\Promise describeBackupAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeContinuousBackups(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeContinuousBackupsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeContributorInsights(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeContributorInsightsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeEndpoints(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeEndpointsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeGlobalTable(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeGlobalTableAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeGlobalTableSettings(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeGlobalTableSettingsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeLimits(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeLimitsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeTableReplicaAutoScaling(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeTableReplicaAutoScalingAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result describeTimeToLive(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise describeTimeToLiveAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result listBackups(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise listBackupsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result listContributorInsights(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise listContributorInsightsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result listGlobalTables(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise listGlobalTablesAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result listTagsOfResource(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise listTagsOfResourceAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result restoreTableFromBackup(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise restoreTableFromBackupAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result restoreTableToPointInTime(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise restoreTableToPointInTimeAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result tagResource(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result transactGetItems(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise transactGetItemsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result transactWriteItems(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise transactWriteItemsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result untagResource(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateContinuousBackups(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateContinuousBackupsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateContributorInsights(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateContributorInsightsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateGlobalTable(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateGlobalTableAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateGlobalTableSettings(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateGlobalTableSettingsAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateTableReplicaAutoScaling(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateTableReplicaAutoScalingAsync(array $args = []) (supported in versions 2012-08-10)
* @method \Aws\Result updateTimeToLive(array $args = []) (supported in versions 2012-08-10)
* @method \GuzzleHttp\Promise\Promise updateTimeToLiveAsync(array $args = []) (supported in versions 2012-08-10)
*/
@ -101,30 +127,46 @@ class DynamoDbClient extends AwsClient
/** @internal */
public static function _applyRetryConfig($value, array &$args, HandlerList $list)
{
if (!$value) {
return;
}
if ($value) {
$config = \Aws\Retry\ConfigurationProvider::unwrap($value);
$list->appendSign(
Middleware::retry(
RetryMiddleware::createDefaultDecider($value),
function ($retries) {
return $retries
? RetryMiddleware::exponentialDelay($retries) / 2
: 0;
},
isset($args['stats']['retries'])
? (bool) $args['stats']['retries']
: false
),
'retry'
);
if ($config->getMode() === 'legacy') {
$list->appendSign(
Middleware::retry(
RetryMiddleware::createDefaultDecider(
$config->getMaxAttempts() - 1,
['error_codes' => ['TransactionInProgressException']]
),
function ($retries) {
return $retries
? RetryMiddleware::exponentialDelay($retries) / 2
: 0;
},
isset($args['stats']['retries'])
? (bool)$args['stats']['retries']
: false
),
'retry'
);
} else {
$list->appendSign(
RetryMiddlewareV2::wrap(
$config,
[
'collect_stats' => $args['stats']['retries'],
'transient_error_codes' => ['TransactionInProgressException']
]
),
'retry'
);
}
}
}
/** @internal */
public static function _applyApiProvider($value, array &$args, HandlerList $list)
{
ClientResolver::_apply_api_provider($value, $args, $list);
ClientResolver::_apply_api_provider($value, $args);
$args['parser'] = new Crc32ValidatingParser($args['parser']);
}
}

View file

@ -10,11 +10,7 @@ class LockingSessionConnection extends StandardSessionConnection
{
public function __construct(DynamoDbClient $client, array $config = [])
{
parent::__construct($client, $config + [
'max_lock_wait_time' => 10,
'min_lock_retry_microtime' => 10000,
'max_lock_retry_microtime' => 50000,
]);
parent::__construct($client, $config);
}
/**
@ -26,7 +22,7 @@ class LockingSessionConnection extends StandardSessionConnection
// Create the params for the UpdateItem operation so that a lock can be
// set and item returned (via ReturnValues) in a one, atomic operation.
$params = [
'TableName' => $this->config['table_name'],
'TableName' => $this->getTableName(),
'Key' => $this->formatKey($id),
'Expected' => ['lock' => ['Exists' => false]],
'AttributeUpdates' => ['lock' => ['Value' => ['N' => '1']]],
@ -34,7 +30,7 @@ class LockingSessionConnection extends StandardSessionConnection
];
// Acquire the lock and fetch the item data.
$timeout = time() + $this->config['max_lock_wait_time'];
$timeout = time() + $this->getMaxLockWaitTime();
while (true) {
try {
$item = [];
@ -50,8 +46,8 @@ class LockingSessionConnection extends StandardSessionConnection
&& time() < $timeout
) {
usleep(rand(
$this->config['min_lock_retry_microtime'],
$this->config['max_lock_retry_microtime']
$this->getMinLockRetryMicrotime(),
$this->getMaxLockRetryMicrotime()
));
} else {
break;

View file

@ -136,10 +136,6 @@ class Marshaler
// Handle string values.
if ($type === 'string') {
if ($value === '') {
return $this->handleInvalid('empty strings are invalid');
}
return ['S' => $value];
}
@ -270,10 +266,10 @@ class Marshaler
case 'N':
if ($this->options['wrap_numbers']) {
return new NumberValue($value);
} else {
// Use type coercion to unmarshal numbers to int/float.
return $value + 0;
}
// Use type coercion to unmarshal numbers to int/float.
return $value + 0;
case 'M':
if ($mapAsObject) {
$data = new \stdClass;
@ -313,7 +309,9 @@ class Marshaler
{
if ($this->options['ignore_invalid']) {
return null;
} elseif ($this->options['nullify_invalid']) {
}
if ($this->options['nullify_invalid']) {
return ['NULL' => true];
}

View file

@ -0,0 +1,262 @@
<?php
namespace Aws\DynamoDb;
trait SessionConnectionConfigTrait
{
/** @var string Name of table to store the sessions */
protected $tableName = 'sessions';
/** @var string Name of hash key in table. Default: "id" */
protected $hashKey = 'id';
/** @var string Name of the data attribute in table. Default: "data" */
protected $dataAttribute = 'data';
/** @var string Type of the data attribute in table. Default: "string" */
protected $dataAttributeType = 'string';
/** @var integer Lifetime of inactive sessions expiration */
protected $sessionLifetime;
/** @var string Name of the session life time attribute in table. Default: "expires" */
protected $sessionLifetimeAttribute = 'expires';
/** @var string Whether or not to use consistent reads */
protected $consistentRead = true;
/** @var string Batch options used for garbage collection */
protected $batchConfig = [];
/** @var boolean Whether or not to use session locking */
protected $locking = false;
/** @var integer Max time (s) to wait for lock acquisition */
protected $maxLockWaitTime = 10;
/** @var integer Min time (µs) to wait between lock attempts */
protected $minLockRetryMicrotime = 10000;
/** @var integer Max time (µs) to wait between lock attempts */
protected $maxLockRetryMicrotime = 50000;
/**
* It initialize the Config class and
* it sets values in case of valid configurations.
*
* It transforms parameters underscore separated in camelcase "this_is_a_test" => ThisIsATest
* and it uses it in order to set the values.
*
* @param array $config
*/
public function initConfig( array $config = [] )
{
if (!empty($config))
{
foreach ($config as $key => $value)
{
$method = 'set' . str_replace('_', '', ucwords($key, '_'));
if(method_exists($this,$method))
{
call_user_func_array(array($this, $method), array($value));
}
}
}
// It applies the default PHP session lifetime, if no session lifetime config is provided
if(!isset($config['session_lifetime']))
{
$this->setSessionLifetime((int) ini_get('session.gc_maxlifetime'));
}
}
/**
* @return string
*/
public function getTableName()
{
return $this->tableName;
}
/**
* @param string $tableName
*/
public function setTableName($tableName)
{
$this->tableName = $tableName;
}
/**
* @return string
*/
public function getHashKey()
{
return $this->hashKey;
}
/**
* @param string $hashKey
*/
public function setHashKey($hashKey)
{
$this->hashKey = $hashKey;
}
/**
* @return string
*/
public function getDataAttribute()
{
return $this->dataAttribute;
}
/**
* @param string $dataAttribute
*/
public function setDataAttribute($dataAttribute)
{
$this->dataAttribute = $dataAttribute;
}
/**
* @return string
*/
public function getDataAttributeType()
{
return $this->dataAttributeType;
}
/**
* @param string $dataAttributeType
*/
public function setDataAttributeType($dataAttributeType)
{
$this->dataAttributeType = $dataAttributeType;
}
/**
* @return number
*/
public function getSessionLifetime()
{
return $this->sessionLifetime;
}
/**
* @param number $sessionLifetime
*/
public function setSessionLifetime($sessionLifetime)
{
$this->sessionLifetime = $sessionLifetime;
}
/**
* @return string
*/
public function getSessionLifetimeAttribute()
{
return $this->sessionLifetimeAttribute;
}
/**
* @param string $sessionLifetimeAttribute
*/
public function setSessionLifetimeAttribute($sessionLifetimeAttribute)
{
$this->sessionLifetimeAttribute = $sessionLifetimeAttribute;
}
/**
* @return boolean
*/
public function isConsistentRead()
{
return $this->consistentRead;
}
/**
* @param boolean $consistentRead
*/
public function setConsistentRead($consistentRead)
{
$this->consistentRead = $consistentRead;
}
/**
* @return mixed
*/
public function getBatchConfig()
{
return $this->batchConfig;
}
/**
* @param mixed $batchConfig
*/
public function setBatchConfig($batchConfig)
{
$this->batchConfig = $batchConfig;
}
/**
* @return boolean
*/
public function isLocking()
{
return $this->locking;
}
/**
* @param boolean $locking
*/
public function setLocking($locking)
{
$this->locking = $locking;
}
/**
* @return number
*/
public function getMaxLockWaitTime()
{
return $this->maxLockWaitTime;
}
/**
* @param number $maxLockWaitTime
*/
public function setMaxLockWaitTime($maxLockWaitTime)
{
$this->maxLockWaitTime = $maxLockWaitTime;
}
/**
* @return number
*/
public function getMinLockRetryMicrotime()
{
return $this->minLockRetryMicrotime;
}
/**
* @param number $minLockRetryMicrotime
*/
public function setMinLockRetryMicrotime($minLockRetryMicrotime)
{
$this->minLockRetryMicrotime = $minLockRetryMicrotime;
}
/**
* @return number
*/
public function getMaxLockRetryMicrotime()
{
return $this->maxLockRetryMicrotime;
}
/**
* @param number $maxLockRetryMicrotime
*/
public function setMaxLockRetryMicrotime($maxLockRetryMicrotime)
{
$this->maxLockRetryMicrotime = $maxLockRetryMicrotime;
}
}

View file

@ -42,15 +42,20 @@ class SessionHandler implements \SessionHandlerInterface
* Creates a new DynamoDB Session Handler.
*
* The configuration array accepts the following array keys and values:
* - table_name: Name of table to store the sessions.
* - hash_key: Name of hash key in table. Default: "id".
* - session_lifetime: Lifetime of inactive sessions expiration.
* - consistent_read: Whether or not to use consistent reads.
* - batch_config: Batch options used for garbage collection.
* - locking: Whether or not to use session locking.
* - max_lock_wait_time: Max time (s) to wait for lock acquisition.
* - min_lock_retry_microtime: Min time (µs) to wait between lock attempts.
* - max_lock_retry_microtime: Max time (µs) to wait between lock attempts.
* - table_name: Name of table to store the sessions.
* - hash_key: Name of hash key in table. Default: "id".
* - data_attribute: Name of the data attribute in table. Default: "data".
* - session_lifetime: Lifetime of inactive sessions expiration.
* - session_lifetime_attribute: Name of the session life time attribute in table. Default: "expires".
* - consistent_read: Whether or not to use consistent reads.
* - batch_config: Batch options used for garbage collection.
* - locking: Whether or not to use session locking.
* - max_lock_wait_time: Max time (s) to wait for lock acquisition.
* - min_lock_retry_microtime: Min time (µs) to wait between lock attempts.
* - max_lock_retry_microtime: Max time (µs) to wait between lock attempts.
*
* You can find the full list of parameters and defaults within the trait
* Aws\DynamoDb\SessionConnectionConfigTrait
*
* @param DynamoDbClient $client Client for doing DynamoDB operations
* @param array $config Configuration for the Session Handler
@ -139,10 +144,13 @@ class SessionHandler implements \SessionHandlerInterface
// Get session data using the selected locking strategy
$item = $this->connection->read($this->formatId($id));
$dataAttribute = $this->connection->getDataAttribute();
$sessionLifetimeAttribute = $this->connection->getSessionLifetimeAttribute();
// Return the data if it is not expired. If it is expired, remove it
if (isset($item['expires']) && isset($item['data'])) {
$this->dataRead = $item['data'];
if ($item['expires'] <= time()) {
if (isset($item[$sessionLifetimeAttribute]) && isset($item[$dataAttribute])) {
$this->dataRead = $item[$dataAttribute];
if ($item[$sessionLifetimeAttribute] <= time()) {
$this->dataRead = '';
$this->destroy($id);
}

View file

@ -8,26 +8,19 @@ use Aws\DynamoDb\Exception\DynamoDbException;
*/
class StandardSessionConnection implements SessionConnectionInterface
{
use SessionConnectionConfigTrait;
/** @var DynamoDbClient The DynamoDB client */
protected $client;
/** @var array The session handler config options */
protected $config;
/**
* @param DynamoDbClient $client DynamoDB client
* @param array $config Session handler config
* @param DynamoDbClient $client DynamoDB client
* @param array $config Session handler config
*/
public function __construct(DynamoDbClient $client, array $config = [])
{
$this->client = $client;
$this->config = $config + [
'table_name' => 'sessions',
'hash_key' => 'id',
'session_lifetime' => (int) ini_get('session.gc_maxlifetime'),
'consistent_read' => true,
'batch_config' => [],
];
$this->initConfig($config);
}
public function read($id)
@ -36,9 +29,9 @@ class StandardSessionConnection implements SessionConnectionInterface
try {
// Execute a GetItem command to retrieve the item.
$result = $this->client->getItem([
'TableName' => $this->config['table_name'],
'TableName' => $this->getTableName(),
'Key' => $this->formatKey($id),
'ConsistentRead' => (bool) $this->config['consistent_read'],
'ConsistentRead' => $this->isConsistentRead(),
]);
// Get the item values
@ -56,23 +49,29 @@ class StandardSessionConnection implements SessionConnectionInterface
public function write($id, $data, $isChanged)
{
// Prepare the attributes
$expires = time() + $this->config['session_lifetime'];
$expires = time() + $this->getSessionLifetime();
$attributes = [
'expires' => ['Value' => ['N' => (string) $expires]],
$this->getSessionLifetimeAttribute() => ['Value' => ['N' => (string) $expires]],
'lock' => ['Action' => 'DELETE'],
];
if ($isChanged) {
if ($data != '') {
$attributes['data'] = ['Value' => ['S' => $data]];
$type = $this->getDataAttributeType();
if ($type == 'binary') {
$attributes[$this->getDataAttribute()] = ['Value' => ['B' => $data]];
} else {
$attributes[$this->getDataAttribute()] = ['Value' => ['S' => $data]];
}
} else {
$attributes['data'] = ['Action' => 'DELETE'];
$attributes[$this->getDataAttribute()] = ['Action' => 'DELETE'];
}
}
// Perform the UpdateItem command
try {
return (bool) $this->client->updateItem([
'TableName' => $this->config['table_name'],
'TableName' => $this->getTableName(),
'Key' => $this->formatKey($id),
'AttributeUpdates' => $attributes,
]);
@ -85,7 +84,7 @@ class StandardSessionConnection implements SessionConnectionInterface
{
try {
return (bool) $this->client->deleteItem([
'TableName' => $this->config['table_name'],
'TableName' => $this->getTableName(),
'Key' => $this->formatKey($id),
]);
} catch (DynamoDbException $e) {
@ -97,10 +96,10 @@ class StandardSessionConnection implements SessionConnectionInterface
{
// Create a Scan iterator for finding expired session items
$scan = $this->client->getPaginator('Scan', [
'TableName' => $this->config['table_name'],
'AttributesToGet' => [$this->config['hash_key']],
'TableName' => $this->getTableName(),
'AttributesToGet' => [$this->getHashKey()],
'ScanFilter' => [
'expires' => [
$this->getSessionLifetimeAttribute() => [
'ComparisonOperator' => 'LT',
'AttributeValueList' => [['N' => (string) time()]],
],
@ -111,13 +110,13 @@ class StandardSessionConnection implements SessionConnectionInterface
]);
// Create a WriteRequestBatch for deleting the expired items
$batch = new WriteRequestBatch($this->client, $this->config['batch_config']);
$batch = new WriteRequestBatch($this->client, $this->getBatchConfig());
// Perform Scan and BatchWriteItem (delete) operations as needed
foreach ($scan->search('Items') as $item) {
$batch->delete(
[$this->config['hash_key'] => $item[$this->config['hash_key']]],
$this->config['table_name']
[$this->getHashKey() => $item[$this->getHashKey()]],
$this->getTableName()
);
}
@ -132,7 +131,7 @@ class StandardSessionConnection implements SessionConnectionInterface
*/
protected function formatKey($key)
{
return [$this->config['hash_key'] => ['S' => $key]];
return [$this->getHashKey() => ['S' => $key]];
}
/**

View file

@ -1,7 +1,6 @@
<?php
namespace Aws\DynamoDb;
use Aws\AwsClientInterface;
use Aws\CommandInterface;
use Aws\CommandPool;
use Aws\Exception\AwsException;