| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | namespace GuzzleHttp\Promise;
 | 
        
           |  |  | 4 |   | 
        
           |  |  | 5 | final class Utils
 | 
        
           |  |  | 6 | {
 | 
        
           |  |  | 7 |     /**
 | 
        
           |  |  | 8 |      * Get the global task queue used for promise resolution.
 | 
        
           |  |  | 9 |      *
 | 
        
           |  |  | 10 |      * This task queue MUST be run in an event loop in order for promises to be
 | 
        
           |  |  | 11 |      * settled asynchronously. It will be automatically run when synchronously
 | 
        
           |  |  | 12 |      * waiting on a promise.
 | 
        
           |  |  | 13 |      *
 | 
        
           |  |  | 14 |      * <code>
 | 
        
           |  |  | 15 |      * while ($eventLoop->isRunning()) {
 | 
        
           |  |  | 16 |      *     GuzzleHttp\Promise\Utils::queue()->run();
 | 
        
           |  |  | 17 |      * }
 | 
        
           |  |  | 18 |      * </code>
 | 
        
           |  |  | 19 |      *
 | 
        
           |  |  | 20 |      * @param TaskQueueInterface $assign Optionally specify a new queue instance.
 | 
        
           |  |  | 21 |      *
 | 
        
           |  |  | 22 |      * @return TaskQueueInterface
 | 
        
           |  |  | 23 |      */
 | 
        
           |  |  | 24 |     public static function queue(TaskQueueInterface $assign = null)
 | 
        
           |  |  | 25 |     {
 | 
        
           |  |  | 26 |         static $queue;
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 |         if ($assign) {
 | 
        
           |  |  | 29 |             $queue = $assign;
 | 
        
           |  |  | 30 |         } elseif (!$queue) {
 | 
        
           |  |  | 31 |             $queue = new TaskQueue();
 | 
        
           |  |  | 32 |         }
 | 
        
           |  |  | 33 |   | 
        
           |  |  | 34 |         return $queue;
 | 
        
           |  |  | 35 |     }
 | 
        
           |  |  | 36 |   | 
        
           |  |  | 37 |     /**
 | 
        
           |  |  | 38 |      * Adds a function to run in the task queue when it is next `run()` and
 | 
        
           |  |  | 39 |      * returns a promise that is fulfilled or rejected with the result.
 | 
        
           |  |  | 40 |      *
 | 
        
           |  |  | 41 |      * @param callable $task Task function to run.
 | 
        
           |  |  | 42 |      *
 | 
        
           |  |  | 43 |      * @return PromiseInterface
 | 
        
           |  |  | 44 |      */
 | 
        
           |  |  | 45 |     public static function task(callable $task)
 | 
        
           |  |  | 46 |     {
 | 
        
           |  |  | 47 |         $queue = self::queue();
 | 
        
           |  |  | 48 |         $promise = new Promise([$queue, 'run']);
 | 
        
           |  |  | 49 |         $queue->add(function () use ($task, $promise) {
 | 
        
           |  |  | 50 |             try {
 | 
        
           |  |  | 51 |                 if (Is::pending($promise)) {
 | 
        
           |  |  | 52 |                     $promise->resolve($task());
 | 
        
           |  |  | 53 |                 }
 | 
        
           |  |  | 54 |             } catch (\Throwable $e) {
 | 
        
           |  |  | 55 |                 $promise->reject($e);
 | 
        
           |  |  | 56 |             } catch (\Exception $e) {
 | 
        
           |  |  | 57 |                 $promise->reject($e);
 | 
        
           |  |  | 58 |             }
 | 
        
           |  |  | 59 |         });
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |         return $promise;
 | 
        
           |  |  | 62 |     }
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |     /**
 | 
        
           |  |  | 65 |      * Synchronously waits on a promise to resolve and returns an inspection
 | 
        
           |  |  | 66 |      * state array.
 | 
        
           |  |  | 67 |      *
 | 
        
           |  |  | 68 |      * Returns a state associative array containing a "state" key mapping to a
 | 
        
           |  |  | 69 |      * valid promise state. If the state of the promise is "fulfilled", the
 | 
        
           |  |  | 70 |      * array will contain a "value" key mapping to the fulfilled value of the
 | 
        
           |  |  | 71 |      * promise. If the promise is rejected, the array will contain a "reason"
 | 
        
           |  |  | 72 |      * key mapping to the rejection reason of the promise.
 | 
        
           |  |  | 73 |      *
 | 
        
           |  |  | 74 |      * @param PromiseInterface $promise Promise or value.
 | 
        
           |  |  | 75 |      *
 | 
        
           |  |  | 76 |      * @return array
 | 
        
           |  |  | 77 |      */
 | 
        
           |  |  | 78 |     public static function inspect(PromiseInterface $promise)
 | 
        
           |  |  | 79 |     {
 | 
        
           |  |  | 80 |         try {
 | 
        
           |  |  | 81 |             return [
 | 
        
           |  |  | 82 |                 'state' => PromiseInterface::FULFILLED,
 | 
        
           |  |  | 83 |                 'value' => $promise->wait()
 | 
        
           |  |  | 84 |             ];
 | 
        
           |  |  | 85 |         } catch (RejectionException $e) {
 | 
        
           |  |  | 86 |             return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
 | 
        
           |  |  | 87 |         } catch (\Throwable $e) {
 | 
        
           |  |  | 88 |             return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
 | 
        
           |  |  | 89 |         } catch (\Exception $e) {
 | 
        
           |  |  | 90 |             return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
 | 
        
           |  |  | 91 |         }
 | 
        
           |  |  | 92 |     }
 | 
        
           |  |  | 93 |   | 
        
           |  |  | 94 |     /**
 | 
        
           |  |  | 95 |      * Waits on all of the provided promises, but does not unwrap rejected
 | 
        
           |  |  | 96 |      * promises as thrown exception.
 | 
        
           |  |  | 97 |      *
 | 
        
           |  |  | 98 |      * Returns an array of inspection state arrays.
 | 
        
           |  |  | 99 |      *
 | 
        
           |  |  | 100 |      * @see inspect for the inspection state array format.
 | 
        
           |  |  | 101 |      *
 | 
        
           |  |  | 102 |      * @param PromiseInterface[] $promises Traversable of promises to wait upon.
 | 
        
           |  |  | 103 |      *
 | 
        
           |  |  | 104 |      * @return array
 | 
        
           |  |  | 105 |      */
 | 
        
           |  |  | 106 |     public static function inspectAll($promises)
 | 
        
           |  |  | 107 |     {
 | 
        
           |  |  | 108 |         $results = [];
 | 
        
           |  |  | 109 |         foreach ($promises as $key => $promise) {
 | 
        
           |  |  | 110 |             $results[$key] = inspect($promise);
 | 
        
           |  |  | 111 |         }
 | 
        
           |  |  | 112 |   | 
        
           |  |  | 113 |         return $results;
 | 
        
           |  |  | 114 |     }
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |     /**
 | 
        
           |  |  | 117 |      * Waits on all of the provided promises and returns the fulfilled values.
 | 
        
           |  |  | 118 |      *
 | 
        
           |  |  | 119 |      * Returns an array that contains the value of each promise (in the same
 | 
        
           |  |  | 120 |      * order the promises were provided). An exception is thrown if any of the
 | 
        
           |  |  | 121 |      * promises are rejected.
 | 
        
           |  |  | 122 |      *
 | 
        
           |  |  | 123 |      * @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
 | 
        
           |  |  | 124 |      *
 | 
        
           |  |  | 125 |      * @return array
 | 
        
           |  |  | 126 |      *
 | 
        
           |  |  | 127 |      * @throws \Exception on error
 | 
        
           |  |  | 128 |      * @throws \Throwable on error in PHP >=7
 | 
        
           |  |  | 129 |      */
 | 
        
           |  |  | 130 |     public static function unwrap($promises)
 | 
        
           |  |  | 131 |     {
 | 
        
           |  |  | 132 |         $results = [];
 | 
        
           |  |  | 133 |         foreach ($promises as $key => $promise) {
 | 
        
           |  |  | 134 |             $results[$key] = $promise->wait();
 | 
        
           |  |  | 135 |         }
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 |         return $results;
 | 
        
           |  |  | 138 |     }
 | 
        
           |  |  | 139 |   | 
        
           |  |  | 140 |     /**
 | 
        
           |  |  | 141 |      * Given an array of promises, return a promise that is fulfilled when all
 | 
        
           |  |  | 142 |      * the items in the array are fulfilled.
 | 
        
           |  |  | 143 |      *
 | 
        
           |  |  | 144 |      * The promise's fulfillment value is an array with fulfillment values at
 | 
        
           |  |  | 145 |      * respective positions to the original array. If any promise in the array
 | 
        
           |  |  | 146 |      * rejects, the returned promise is rejected with the rejection reason.
 | 
        
           |  |  | 147 |      *
 | 
        
           |  |  | 148 |      * @param mixed $promises  Promises or values.
 | 
        
           |  |  | 149 |      * @param bool  $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
 | 
        
           |  |  | 150 |      *
 | 
        
           |  |  | 151 |      * @return PromiseInterface
 | 
        
           |  |  | 152 |      */
 | 
        
           |  |  | 153 |     public static function all($promises, $recursive = false)
 | 
        
           |  |  | 154 |     {
 | 
        
           |  |  | 155 |         $results = [];
 | 
        
           |  |  | 156 |         $promise = Each::of(
 | 
        
           |  |  | 157 |             $promises,
 | 
        
           |  |  | 158 |             function ($value, $idx) use (&$results) {
 | 
        
           |  |  | 159 |                 $results[$idx] = $value;
 | 
        
           |  |  | 160 |             },
 | 
        
           |  |  | 161 |             function ($reason, $idx, Promise $aggregate) {
 | 
        
           |  |  | 162 |                 $aggregate->reject($reason);
 | 
        
           |  |  | 163 |             }
 | 
        
           |  |  | 164 |         )->then(function () use (&$results) {
 | 
        
           |  |  | 165 |             ksort($results);
 | 
        
           |  |  | 166 |             return $results;
 | 
        
           |  |  | 167 |         });
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 |         if (true === $recursive) {
 | 
        
           |  |  | 170 |             $promise = $promise->then(function ($results) use ($recursive, &$promises) {
 | 
        
           |  |  | 171 |                 foreach ($promises as $promise) {
 | 
        
           |  |  | 172 |                     if (Is::pending($promise)) {
 | 
        
           |  |  | 173 |                         return self::all($promises, $recursive);
 | 
        
           |  |  | 174 |                     }
 | 
        
           |  |  | 175 |                 }
 | 
        
           |  |  | 176 |                 return $results;
 | 
        
           |  |  | 177 |             });
 | 
        
           |  |  | 178 |         }
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |         return $promise;
 | 
        
           |  |  | 181 |     }
 | 
        
           |  |  | 182 |   | 
        
           |  |  | 183 |     /**
 | 
        
           |  |  | 184 |      * Initiate a competitive race between multiple promises or values (values
 | 
        
           |  |  | 185 |      * will become immediately fulfilled promises).
 | 
        
           |  |  | 186 |      *
 | 
        
           |  |  | 187 |      * When count amount of promises have been fulfilled, the returned promise
 | 
        
           |  |  | 188 |      * is fulfilled with an array that contains the fulfillment values of the
 | 
        
           |  |  | 189 |      * winners in order of resolution.
 | 
        
           |  |  | 190 |      *
 | 
        
           |  |  | 191 |      * This promise is rejected with a {@see AggregateException} if the number
 | 
        
           |  |  | 192 |      * of fulfilled promises is less than the desired $count.
 | 
        
           |  |  | 193 |      *
 | 
        
           |  |  | 194 |      * @param int   $count    Total number of promises.
 | 
        
           |  |  | 195 |      * @param mixed $promises Promises or values.
 | 
        
           |  |  | 196 |      *
 | 
        
           |  |  | 197 |      * @return PromiseInterface
 | 
        
           |  |  | 198 |      */
 | 
        
           |  |  | 199 |     public static function some($count, $promises)
 | 
        
           |  |  | 200 |     {
 | 
        
           |  |  | 201 |         $results = [];
 | 
        
           |  |  | 202 |         $rejections = [];
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 |         return Each::of(
 | 
        
           |  |  | 205 |             $promises,
 | 
        
           |  |  | 206 |             function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
 | 
        
           |  |  | 207 |                 if (Is::settled($p)) {
 | 
        
           |  |  | 208 |                     return;
 | 
        
           |  |  | 209 |                 }
 | 
        
           |  |  | 210 |                 $results[$idx] = $value;
 | 
        
           |  |  | 211 |                 if (count($results) >= $count) {
 | 
        
           |  |  | 212 |                     $p->resolve(null);
 | 
        
           |  |  | 213 |                 }
 | 
        
           |  |  | 214 |             },
 | 
        
           |  |  | 215 |             function ($reason) use (&$rejections) {
 | 
        
           |  |  | 216 |                 $rejections[] = $reason;
 | 
        
           |  |  | 217 |             }
 | 
        
           |  |  | 218 |         )->then(
 | 
        
           |  |  | 219 |             function () use (&$results, &$rejections, $count) {
 | 
        
           |  |  | 220 |                 if (count($results) !== $count) {
 | 
        
           |  |  | 221 |                     throw new AggregateException(
 | 
        
           |  |  | 222 |                         'Not enough promises to fulfill count',
 | 
        
           |  |  | 223 |                         $rejections
 | 
        
           |  |  | 224 |                     );
 | 
        
           |  |  | 225 |                 }
 | 
        
           |  |  | 226 |                 ksort($results);
 | 
        
           |  |  | 227 |                 return array_values($results);
 | 
        
           |  |  | 228 |             }
 | 
        
           |  |  | 229 |         );
 | 
        
           |  |  | 230 |     }
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |     /**
 | 
        
           |  |  | 233 |      * Like some(), with 1 as count. However, if the promise fulfills, the
 | 
        
           |  |  | 234 |      * fulfillment value is not an array of 1 but the value directly.
 | 
        
           |  |  | 235 |      *
 | 
        
           |  |  | 236 |      * @param mixed $promises Promises or values.
 | 
        
           |  |  | 237 |      *
 | 
        
           |  |  | 238 |      * @return PromiseInterface
 | 
        
           |  |  | 239 |      */
 | 
        
           |  |  | 240 |     public static function any($promises)
 | 
        
           |  |  | 241 |     {
 | 
        
           |  |  | 242 |         return self::some(1, $promises)->then(function ($values) {
 | 
        
           |  |  | 243 |             return $values[0];
 | 
        
           |  |  | 244 |         });
 | 
        
           |  |  | 245 |     }
 | 
        
           |  |  | 246 |   | 
        
           |  |  | 247 |     /**
 | 
        
           |  |  | 248 |      * Returns a promise that is fulfilled when all of the provided promises have
 | 
        
           |  |  | 249 |      * been fulfilled or rejected.
 | 
        
           |  |  | 250 |      *
 | 
        
           |  |  | 251 |      * The returned promise is fulfilled with an array of inspection state arrays.
 | 
        
           |  |  | 252 |      *
 | 
        
           |  |  | 253 |      * @see inspect for the inspection state array format.
 | 
        
           |  |  | 254 |      *
 | 
        
           |  |  | 255 |      * @param mixed $promises Promises or values.
 | 
        
           |  |  | 256 |      *
 | 
        
           |  |  | 257 |      * @return PromiseInterface
 | 
        
           |  |  | 258 |      */
 | 
        
           |  |  | 259 |     public static function settle($promises)
 | 
        
           |  |  | 260 |     {
 | 
        
           |  |  | 261 |         $results = [];
 | 
        
           |  |  | 262 |   | 
        
           |  |  | 263 |         return Each::of(
 | 
        
           |  |  | 264 |             $promises,
 | 
        
           |  |  | 265 |             function ($value, $idx) use (&$results) {
 | 
        
           |  |  | 266 |                 $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
 | 
        
           |  |  | 267 |             },
 | 
        
           |  |  | 268 |             function ($reason, $idx) use (&$results) {
 | 
        
           |  |  | 269 |                 $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
 | 
        
           |  |  | 270 |             }
 | 
        
           |  |  | 271 |         )->then(function () use (&$results) {
 | 
        
           |  |  | 272 |             ksort($results);
 | 
        
           |  |  | 273 |             return $results;
 | 
        
           |  |  | 274 |         });
 | 
        
           |  |  | 275 |     }
 | 
        
           |  |  | 276 | }
 |