mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2025-03-05 22:49:48 +01:00
238 lines
7.4 KiB
PHP
238 lines
7.4 KiB
PHP
<?php
|
|
namespace Aws\S3;
|
|
|
|
use Aws\AwsClientInterface;
|
|
use Aws\S3\Exception\DeleteMultipleObjectsException;
|
|
use GuzzleHttp\Promise;
|
|
use GuzzleHttp\Promise\PromisorInterface;
|
|
use GuzzleHttp\Promise\PromiseInterface;
|
|
|
|
/**
|
|
* Efficiently deletes many objects from a single Amazon S3 bucket using an
|
|
* iterator that yields keys. Deletes are made using the DeleteObjects API
|
|
* operation.
|
|
*
|
|
* $s3 = new Aws\S3\Client([
|
|
* 'region' => 'us-west-2',
|
|
* 'version' => 'latest'
|
|
* ]);
|
|
*
|
|
* $listObjectsParams = ['Bucket' => 'foo', 'Prefix' => 'starts/with/'];
|
|
* $delete = Aws\S3\BatchDelete::fromListObjects($s3, $listObjectsParams);
|
|
* // Asynchronously delete
|
|
* $promise = $delete->promise();
|
|
* // Force synchronous completion
|
|
* $delete->delete();
|
|
*
|
|
* When using one of the batch delete creational static methods, you can supply
|
|
* an associative array of options:
|
|
*
|
|
* - before: Function invoked before executing a command. The function is
|
|
* passed the command that is about to be executed. This can be useful
|
|
* for logging, adding custom request headers, etc.
|
|
* - batch_size: The size of each delete batch. Defaults to 1000.
|
|
*
|
|
* @link http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html
|
|
*/
|
|
class BatchDelete implements PromisorInterface
|
|
{
|
|
private $bucket;
|
|
/** @var AwsClientInterface */
|
|
private $client;
|
|
/** @var callable */
|
|
private $before;
|
|
/** @var PromiseInterface */
|
|
private $cachedPromise;
|
|
/** @var callable */
|
|
private $promiseCreator;
|
|
private $batchSize = 1000;
|
|
private $queue = [];
|
|
|
|
/**
|
|
* Creates a BatchDelete object from all of the paginated results of a
|
|
* ListObjects operation. Each result that is returned by the ListObjects
|
|
* operation will be deleted.
|
|
*
|
|
* @param AwsClientInterface $client AWS Client to use.
|
|
* @param array $listObjectsParams ListObjects API parameters
|
|
* @param array $options BatchDelete options.
|
|
*
|
|
* @return BatchDelete
|
|
*/
|
|
public static function fromListObjects(
|
|
AwsClientInterface $client,
|
|
array $listObjectsParams,
|
|
array $options = []
|
|
) {
|
|
$iter = $client->getPaginator('ListObjects', $listObjectsParams);
|
|
$bucket = $listObjectsParams['Bucket'];
|
|
$fn = function (BatchDelete $that) use ($iter) {
|
|
return $iter->each(function ($result) use ($that) {
|
|
$promises = [];
|
|
if (is_array($result['Contents'])) {
|
|
foreach ($result['Contents'] as $object) {
|
|
if ($promise = $that->enqueue($object)) {
|
|
$promises[] = $promise;
|
|
}
|
|
}
|
|
}
|
|
return $promises ? Promise\all($promises) : null;
|
|
});
|
|
};
|
|
|
|
return new self($client, $bucket, $fn, $options);
|
|
}
|
|
|
|
/**
|
|
* Creates a BatchDelete object from an iterator that yields results.
|
|
*
|
|
* @param AwsClientInterface $client AWS Client to use to execute commands
|
|
* @param string $bucket Bucket where the objects are stored
|
|
* @param \Iterator $iter Iterator that yields assoc arrays
|
|
* @param array $options BatchDelete options
|
|
*
|
|
* @return BatchDelete
|
|
*/
|
|
public static function fromIterator(
|
|
AwsClientInterface $client,
|
|
$bucket,
|
|
\Iterator $iter,
|
|
array $options = []
|
|
) {
|
|
$fn = function (BatchDelete $that) use ($iter) {
|
|
return Promise\coroutine(function () use ($that, $iter) {
|
|
foreach ($iter as $obj) {
|
|
if ($promise = $that->enqueue($obj)) {
|
|
yield $promise;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
return new self($client, $bucket, $fn, $options);
|
|
}
|
|
|
|
public function promise()
|
|
{
|
|
if (!$this->cachedPromise) {
|
|
$this->cachedPromise = $this->createPromise();
|
|
}
|
|
|
|
return $this->cachedPromise;
|
|
}
|
|
|
|
/**
|
|
* Synchronously deletes all of the objects.
|
|
*
|
|
* @throws DeleteMultipleObjectsException on error.
|
|
*/
|
|
public function delete()
|
|
{
|
|
$this->promise()->wait();
|
|
}
|
|
|
|
/**
|
|
* @param AwsClientInterface $client Client used to transfer the requests
|
|
* @param string $bucket Bucket to delete from.
|
|
* @param callable $promiseFn Creates a promise.
|
|
* @param array $options Hash of options used with the batch
|
|
*
|
|
* @throws \InvalidArgumentException if the provided batch_size is <= 0
|
|
*/
|
|
private function __construct(
|
|
AwsClientInterface $client,
|
|
$bucket,
|
|
callable $promiseFn,
|
|
array $options = []
|
|
) {
|
|
$this->client = $client;
|
|
$this->bucket = $bucket;
|
|
$this->promiseCreator = $promiseFn;
|
|
|
|
if (isset($options['before'])) {
|
|
if (!is_callable($options['before'])) {
|
|
throw new \InvalidArgumentException('before must be callable');
|
|
}
|
|
$this->before = $options['before'];
|
|
}
|
|
|
|
if (isset($options['batch_size'])) {
|
|
if ($options['batch_size'] <= 0) {
|
|
throw new \InvalidArgumentException('batch_size is not > 0');
|
|
}
|
|
$this->batchSize = min($options['batch_size'], 1000);
|
|
}
|
|
}
|
|
|
|
private function enqueue(array $obj)
|
|
{
|
|
$this->queue[] = $obj;
|
|
return count($this->queue) >= $this->batchSize
|
|
? $this->flushQueue()
|
|
: null;
|
|
}
|
|
|
|
private function flushQueue()
|
|
{
|
|
static $validKeys = ['Key' => true, 'VersionId' => true];
|
|
|
|
if (count($this->queue) === 0) {
|
|
return null;
|
|
}
|
|
|
|
$batch = [];
|
|
while ($obj = array_shift($this->queue)) {
|
|
$batch[] = array_intersect_key($obj, $validKeys);
|
|
}
|
|
|
|
$command = $this->client->getCommand('DeleteObjects', [
|
|
'Bucket' => $this->bucket,
|
|
'Delete' => ['Objects' => $batch]
|
|
]);
|
|
|
|
if ($this->before) {
|
|
call_user_func($this->before, $command);
|
|
}
|
|
|
|
return $this->client->executeAsync($command)
|
|
->then(function ($result) {
|
|
if (!empty($result['Errors'])) {
|
|
throw new DeleteMultipleObjectsException(
|
|
$result['Deleted'] ?: [],
|
|
$result['Errors']
|
|
);
|
|
}
|
|
return $result;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns a promise that will clean up any references when it completes.
|
|
*
|
|
* @return PromiseInterface
|
|
*/
|
|
private function createPromise()
|
|
{
|
|
// Create the promise
|
|
$promise = call_user_func($this->promiseCreator, $this);
|
|
$this->promiseCreator = null;
|
|
|
|
// Cleans up the promise state and references.
|
|
$cleanup = function () {
|
|
$this->before = $this->client = $this->queue = null;
|
|
};
|
|
|
|
// When done, ensure cleanup and that any remaining are processed.
|
|
return $promise->then(
|
|
function () use ($cleanup) {
|
|
return Promise\promise_for($this->flushQueue())
|
|
->then($cleanup);
|
|
},
|
|
function ($reason) use ($cleanup) {
|
|
$cleanup();
|
|
return Promise\rejection_for($reason);
|
|
}
|
|
);
|
|
}
|
|
}
|