PluginProbe
Media Cloud Sync / 1.4.1
Media Cloud Sync v1.4.1
1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 All 35 releases
media-cloud-sync / includes / sdk / s3 / Aws / ResultPaginator.php

ResultPaginator.php in Media Cloud Sync 1.4.1, at includes/sdk/s3/Aws/ResultPaginator.php

167 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\Aws;
4
5 use Dudlewebs\WPMCS\s3\GuzzleHttp\Promise;
6 /**
7 * Iterator that yields each page of results of a pageable operation.
8 */
9 class ResultPaginator implements \Iterator
10 {
11 /** @var AwsClientInterface Client performing operations. */
12 private $client;
13 /** @var string Name of the operation being paginated. */
14 private $operation;
15 /** @var array Args for the operation. */
16 private $args;
17 /** @var array Configuration for the paginator. */
18 private $config;
19 /** @var Result Most recent result from the client. */
20 private $result;
21 /** @var string|array Next token to use for pagination. */
22 private $nextToken;
23 /** @var int Number of operations/requests performed. */
24 private $requestCount = 0;
25 /**
26 * @param AwsClientInterface $client
27 * @param string $operation
28 * @param array $args
29 * @param array $config
30 */
31 public function __construct(AwsClientInterface $client, $operation, array $args, array $config)
32 {
33 $this->client = $client;
34 $this->operation = $operation;
35 $this->args = $args;
36 $this->config = $config;
37 MetricsBuilder::appendMetricsCaptureMiddleware($this->client->getHandlerList(), MetricsBuilder::PAGINATOR);
38 }
39 /**
40 * Runs a paginator asynchronously and uses a callback to handle results.
41 *
42 * The callback should have the signature: function (Aws\Result $result).
43 * A non-null return value from the callback will be yielded by the
44 * promise. This means that you can return promises from the callback that
45 * will need to be resolved before continuing iteration over the remaining
46 * items, essentially merging in other promises to the iteration. The last
47 * non-null value returned by the callback will be the result that fulfills
48 * the promise to any downstream promises.
49 *
50 * @param callable $handleResult Callback for handling each page of results.
51 * The callback accepts the result that was
52 * yielded as a single argument. If the
53 * callback returns a promise, the promise
54 * will be merged into the coroutine.
55 *
56 * @return Promise\Promise
57 */
58 public function each(callable $handleResult)
59 {
60 return Promise\Coroutine::of(function () use($handleResult) {
61 $nextToken = null;
62 do {
63 $command = $this->createNextCommand($this->args, $nextToken);
64 $result = (yield $this->client->executeAsync($command));
65 $nextToken = $this->determineNextToken($result);
66 $retVal = $handleResult($result);
67 if ($retVal !== null) {
68 (yield Promise\Create::promiseFor($retVal));
69 }
70 } while ($nextToken);
71 });
72 }
73 /**
74 * Returns an iterator that iterates over the values of applying a JMESPath
75 * search to each result yielded by the iterator as a flat sequence.
76 *
77 * @param string $expression JMESPath expression to apply to each result.
78 *
79 * @return \Iterator
80 */
81 public function search($expression)
82 {
83 // Apply JMESPath expression on each result, but as a flat sequence.
84 return flatmap($this, function (Result $result) use($expression) {
85 return (array) $result->search($expression);
86 });
87 }
88 /**
89 * @return Result
90 */
91 #[\ReturnTypeWillChange]
92 public function current()
93 {
94 return $this->valid() ? $this->result : \false;
95 }
96 /**
97 * @return mixed
98 */
99 #[\ReturnTypeWillChange]
100 public function key()
101 {
102 return $this->valid() ? $this->requestCount - 1 : null;
103 }
104 /**
105 * @return void
106 */
107 #[\ReturnTypeWillChange]
108 public function next()
109 {
110 $this->result = null;
111 }
112 /**
113 * @return bool
114 */
115 #[\ReturnTypeWillChange]
116 public function valid()
117 {
118 if ($this->result) {
119 return \true;
120 }
121 if ($this->nextToken || !$this->requestCount) {
122 //Forward/backward paging can result in a case where the last page's nextforwardtoken
123 //is the same as the one that came before it. This can cause an infinite loop.
124 $hasBidirectionalPaging = $this->config['output_token'] === 'nextForwardToken';
125 if ($hasBidirectionalPaging && $this->nextToken) {
126 $tokenKey = $this->config['input_token'];
127 $previousToken = $this->nextToken[$tokenKey];
128 }
129 $this->result = $this->client->execute($this->createNextCommand($this->args, $this->nextToken));
130 $this->nextToken = $this->determineNextToken($this->result);
131 if (isset($previousToken) && $previousToken === $this->nextToken[$tokenKey]) {
132 return \false;
133 }
134 $this->requestCount++;
135 return \true;
136 }
137 return \false;
138 }
139 /**
140 * @return void
141 */
142 #[\ReturnTypeWillChange]
143 public function rewind()
144 {
145 $this->requestCount = 0;
146 $this->nextToken = null;
147 $this->result = null;
148 }
149 private function createNextCommand(array $args, ?array $nextToken = null)
150 {
151 return $this->client->getCommand($this->operation, \array_merge($args, $nextToken ?: []));
152 }
153 private function determineNextToken(Result $result)
154 {
155 if (!$this->config['output_token']) {
156 return null;
157 }
158 if ($this->config['more_results'] && !$result->search($this->config['more_results'])) {
159 return null;
160 }
161 $nextToken = \is_scalar($this->config['output_token']) ? [$this->config['input_token'] => $this->config['output_token']] : \array_combine($this->config['input_token'], $this->config['output_token']);
162 return \array_filter(\array_map(function ($outputToken) use($result) {
163 return $result->search($outputToken);
164 }, $nextToken));
165 }
166 }
167