Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
69 / 69
100.00% covered (success)
100.00%
26 / 26
CRAP
100.00% covered (success)
100.00%
1 / 1
AbstractPromise
100.00% covered (success)
100.00%
69 / 69
100.00% covered (success)
100.00%
26 / 26
54
100.00% covered (success)
100.00%
1 / 1
 setPromiser
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getPromiser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasPromiser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSuccess
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 getSuccess
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 hasSuccess
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setFailure
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 getFailure
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasFailure
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setCancel
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 getCancel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasCancel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setFinally
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
5
 getFinally
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasFinally
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setState
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
5
 getState
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasState
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isPending
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isFulfilled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isRejected
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isCancelled
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 then
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 catch
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 finally
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 forward
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 wait
n/a
0 / 0
n/a
0 / 0
0
 resolve
n/a
0 / 0
n/a
0 / 0
0
 cancel
n/a
0 / 0
n/a
0 / 0
0
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Http\Promise;
15
16use Pop\Http\Client;
17use Pop\Http\Client\Response;
18use Pop\Http\Client\Handler\CurlMulti;
19use Pop\Utils\CallableObject;
20
21/**
22 * Abstract HTTP promise class
23 *
24 * @category   Pop
25 * @package    Pop\Http
26 * @author     Nick Sagona, III <dev@nolainteractive.com>
27 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
28 * @license    http://www.popphp.org/license     New BSD License
29 * @version    5.0.0
30 */
31abstract class AbstractPromise implements PromiseInterface
32{
33
34    /**
35     * Status constants
36     * @var string
37     */
38    const PENDING   = 'PENDING';
39    const FULFILLED = 'FULFILLED';
40    const REJECTED  = 'REJECTED';
41    const CANCELLED = 'CANCELLED';
42
43    /**
44     * Client Promiser
45     * @var Client|CurlMulti|null
46     */
47    protected Client|CurlMulti|null $promiser = null;
48
49    /**
50     * Success callables
51     * @var array
52     */
53    protected array $success = [];
54
55    /**
56     * Failure callable
57     * @var ?CallableObject
58     */
59    protected ?CallableObject $failure = null;
60
61    /**
62     * Cancel callable
63     * @var ?CallableObject
64     */
65    protected ?CallableObject $cancel = null;
66
67    /**
68     * Cancel callable
69     * @var ?CallableObject
70     */
71    protected ?CallableObject $finally = null;
72
73    /**
74     * Current state
75     * @var string
76     */
77    protected string $state = self::PENDING;
78
79    /**
80     * Method to set client promiser
81     *
82     * @param  Client|CurlMulti $promiser
83     * @return PromiseInterface
84     */
85    public function setPromiser(Client|CurlMulti $promiser): AbstractPromise
86    {
87        $this->promiser = $promiser;
88        return $this;
89    }
90
91    /**
92     * Method to get client promiser
93     *
94     * @return Client|CurlMulti
95     */
96    public function getPromiser(): Client|CurlMulti
97    {
98        return $this->promiser;
99    }
100
101    /**
102     * Method to check client promiser
103     *
104     * @return bool
105     */
106    public function hasPromiser(): bool
107    {
108        return ($this->promiser !== null);
109    }
110
111    /**
112     * Method to set success callable
113     *
114     * @param  mixed $success
115     * @throws Exception
116     * @return AbstractPromise
117     */
118    public function setSuccess(mixed $success): AbstractPromise
119    {
120        if (!($success instanceof CallableObject) && !is_callable($success)) {
121            throw new Exception('Error: The success callback must be an instance of CallableObject or a callable');
122        }
123        if (!($success instanceof CallableObject) && is_callable($success)) {
124            $success = new CallableObject($success);
125        }
126
127        $this->success[] = $success;
128        return $this;
129    }
130
131    /**
132     * Method to get success callable
133     *
134     * @param  ?int $i
135     * @return array|CallableObject|null
136     */
137    public function getSuccess(?int $i = null): array|CallableObject|null
138    {
139        if ($i !== null) {
140            return $this->success[$i] ?? null;
141        } else {
142            return $this->success;
143        }
144    }
145
146    /**
147     * Method to check success callable
148     *
149     * @param  ?int $i
150     * @return bool
151     */
152    public function hasSuccess(?int $i = null): bool
153    {
154        if ($i !== null) {
155            return (isset($this->success[$i]));
156        } else {
157            return (!empty($this->success));
158        }
159    }
160
161    /**
162     * Method to set failure callable
163     *
164     * @param  mixed $failure
165     * @return AbstractPromise
166     */
167    public function setFailure(mixed $failure): AbstractPromise
168    {
169        if (!($failure instanceof CallableObject) && !is_callable($failure)) {
170            throw new Exception('Error: The failure callback must be an instance of CallableObject or a callable');
171        }
172        if (!($failure instanceof CallableObject) && is_callable($failure)) {
173            $failure = new CallableObject($failure);
174        }
175
176        $this->failure = $failure;
177        return $this;
178    }
179
180    /**
181     * Method to get failure callable
182     *
183     * @return CallableObject|null
184     */
185    public function getFailure(): CallableObject|null
186    {
187        return $this->failure;
188    }
189
190    /**
191     * Method to check failure callable
192     *
193     * @return bool
194     */
195    public function hasFailure(): bool
196    {
197        return ($this->failure !== null);
198    }
199
200    /**
201     * Method to set cancel callable
202     *
203     * @param  mixed $cancel
204     * @return AbstractPromise
205     */
206    public function setCancel(mixed $cancel): AbstractPromise
207    {
208        if (!($cancel instanceof CallableObject) && !is_callable($cancel)) {
209            throw new Exception('Error: The cancel callback must be an instance of CallableObject or a callable');
210        }
211        if (!($cancel instanceof CallableObject) && is_callable($cancel)) {
212            $cancel = new CallableObject($cancel);
213        }
214
215        $this->cancel = $cancel;
216        return $this;
217    }
218
219    /**
220     * Method to get cancel callable
221     *
222     * @return CallableObject|null
223     */
224    public function getCancel(): CallableObject|null
225    {
226        return $this->cancel;
227    }
228
229    /**
230     * Method to check cancel callable
231     *
232     * @return bool
233     */
234    public function hasCancel(): bool
235    {
236        return ($this->cancel !== null);
237    }
238
239    /**
240     * Method to set finally callable
241     *
242     * @param  mixed $finally
243     * @return PromiseInterface
244     */
245    public function setFinally(mixed $finally): AbstractPromise
246    {
247        if (!($finally instanceof CallableObject) && !is_callable($finally)) {
248            throw new Exception('Error: The cancel callback must be an instance of CallableObject or a callable');
249        }
250        if (!($finally instanceof CallableObject) && is_callable($finally)) {
251            $finally = new CallableObject($finally);
252        }
253
254        $this->finally = $finally;
255        return $this;
256    }
257
258    /**
259     * Method to get finally callable
260     *
261     * @return CallableObject|null
262     */
263    public function getFinally(): CallableObject|null
264    {
265        return $this->finally;
266    }
267
268    /**
269     * Method to check finally callable
270     *
271     * @return bool
272     */
273    public function hasFinally(): bool
274    {
275        return ($this->finally !== null);
276    }
277
278    /**
279     * Method to set current state
280     *
281     * @param  string $state
282     * @throws Exception
283     * @return AbstractPromise
284     */
285    public function setState(string $state): AbstractPromise
286    {
287        if (($state !== static::PENDING) && ($state !== static::FULFILLED) && ($state !== static::REJECTED) && ($state !== static::CANCELLED)) {
288            throw new Exception('Error: That state is not allowed.');
289        }
290        $this->state = $state;
291        return $this;
292    }
293
294    /**
295     * Method to get current state
296     *
297     * @return string
298     */
299    public function getState(): string
300    {
301        return $this->state;
302    }
303
304    /**
305     * Method to check current state
306     *
307     * @return bool
308     */
309    public function hasState(): bool
310    {
311        return ($this->state !== null);
312    }
313
314    /**
315     * Determine is the promise is pending
316     *
317     * @return bool
318     */
319    public function isPending(): bool
320    {
321        return ($this->state == static::PENDING);
322    }
323
324    /**
325     * Determine is the promise is fulfilled
326     *
327     * @return bool
328     */
329    public function isFulfilled(): bool
330    {
331        return ($this->state == static::FULFILLED);
332    }
333
334    /**
335     * Determine is the promise is rejected
336     *
337     * @return bool
338     */
339    public function isRejected(): bool
340    {
341        return ($this->state == static::REJECTED);
342    }
343
344    /**
345     * Determine is the promise is cancelled
346     *
347     * @return bool
348     */
349    public function isCancelled(): bool
350    {
351        return ($this->state == static::CANCELLED);
352    }
353
354    /**
355     * Then method
356     *
357     * @param  mixed $success
358     * @param  bool  $resolve
359     * @return AbstractPromise
360     */
361    public function then(mixed $success, bool $resolve = false): AbstractPromise
362    {
363        $this->setSuccess($success);
364
365        if ($resolve) {
366            $this->resolve();
367        }
368
369        return $this;
370    }
371
372    /**
373     * Method to set failure callable (alias)
374     *
375     * @param  mixed $failure
376     * @param  bool $resolve
377     * @return AbstractPromise
378     */
379    public function catch(mixed $failure, bool $resolve = false): AbstractPromise
380    {
381        $this->setFailure($failure);
382
383        if ($resolve) {
384            $this->resolve();
385        }
386
387        return $this;
388    }
389
390    /**
391     * Method to set finally callable (alias)
392     *
393     * @param  mixed $finally
394     * @return AbstractPromise
395     */
396    public function finally(mixed $finally, bool $resolve = false): AbstractPromise
397    {
398        $this->setFinally($finally);
399
400        if ($resolve) {
401            $this->resolve();
402        }
403
404        return $this;
405    }
406
407    /**
408     * Forward method
409     *
410     * @param  PromiseInterface $nextPromise
411     * @param  int              $i
412     * @return AbstractPromise
413     */
414    public function forward(PromiseInterface $nextPromise, int $i = 0): AbstractPromise
415    {
416        for ($j = $i; $j < count($this->success); $j++) {
417            $nextPromise->then($this->success[$j]);
418        }
419        if ($this->hasFailure()) {
420            $nextPromise->setFailure($this->failure);
421        }
422        if ($this->hasCancel()) {
423            $nextPromise->setCancel($this->cancel);
424        }
425
426        return $nextPromise;
427    }
428
429    /**
430     * Wait method
431     *
432     * @param  bool $unwrap
433     * @return Response|array|null
434     */
435    abstract public function wait(bool $unwrap = true): Response|array|null;
436
437    /**
438     * Resolve method
439     *
440     * @return void
441     */
442    abstract public function resolve(): void;
443
444    /**
445     * Cancel method
446     *
447     * @return void
448     */
449    abstract public function cancel(): void;
450
451}