Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.90% covered (success)
93.90%
77 / 82
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Promise
93.90% covered (success)
93.90%
77 / 82
60.00% covered (warning)
60.00%
3 / 5
42.40
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 wait
87.50% covered (success)
87.50%
28 / 32
0.00% covered (danger)
0.00%
0 / 1
17.56
 resolve
97.62% covered (success)
97.62%
41 / 42
0.00% covered (danger)
0.00%
0 / 1
20
 cancel
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
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;
15
16use Pop\Http\Client\Handler\CurlMulti;
17use Pop\Http\Client\Response;
18use Pop\Http\Promise\Exception;
19use ReflectionException;
20
21/**
22 * 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 */
31class Promise extends Promise\AbstractPromise
32{
33
34    /**
35     * Constructor
36     *
37     * Instantiate the Promise object
38     *
39     * @param  Client|CurlMulti $promiser
40     */
41    public function __construct(Client|CurlMulti $promiser)
42    {
43        $this->setPromiser($promiser);
44    }
45
46    /**
47     * Factory to create a Promise object
48     *
49     * @param  Client|CurlMulti $promiser
50     * @return static
51     */
52    public static function create(Client|CurlMulti $promiser): static
53    {
54        return new static($promiser);
55    }
56
57    /**
58     * Wait method
59     *
60     * @param  bool $unwrap
61     * @throws Exception|Promise\Exception|ReflectionException|Client\Exception|\Pop\Utils\Exception|\Pop\Http\Exception
62     * @return Response|string|array|null
63     */
64    public function wait(bool $unwrap = true): Response|array|null
65    {
66        $multi = ($this->promiser instanceof CurlMulti);
67        $auto  = (!($multi) && ($this->promiser->hasOption('auto')) &&
68            ($this->promiser->getOption('auto')));
69
70        if (($this->isFulfilled()) && ($this->promiser->isComplete())) {
71            if ($multi) {
72                return $this->promiser->getAllResponses();
73            } else {
74                return (($auto) && ($this->promiser->hasResponse())) ?
75                    $this->promiser->getResponse()->getParsedResponse() : $this->promiser->getResponse();
76            }
77        }
78
79        $this->setState(self::PENDING);
80
81        if ($multi) {
82            $running = null;
83            do {
84                $this->promiser->send($running);
85            } while ($running);
86        } else {
87            $this->promiser->send();
88        }
89
90        if ($this->promiser->isComplete()) {
91            if ($this->promiser->isError()) {
92                $this->setState(self::REJECTED);
93                if ($unwrap) {
94                    if ($multi) {
95                        throw new Exception('Error: There was an error with one of the multiple requests.');
96                    } else {
97                        throw new Exception(
98                            'Error: ' . $this->promiser->getResponse()->getCode() . ' ' .
99                            $this->promiser->getResponse()->getMessage()
100                        );
101                    }
102                }
103            } else {
104                $this->setState(self::FULFILLED);
105                if ($multi) {
106                    return $this->promiser->getAllResponses();
107                } else {
108                    return (($auto) && ($this->promiser->hasResponse())) ?
109                        $this->promiser->getResponse()->getParsedResponse() : $this->promiser->getResponse();
110                }
111            }
112        } else if ($unwrap) {
113            throw new Exception('Error: Unable to complete request.');
114        }
115
116        return null;
117    }
118
119    /**
120     * Resolve method
121     *
122     * @throws Client\Exception|Exception|ReflectionException|\Pop\Utils\Exception|\Pop\Http\Exception
123     * @return void
124     */
125    public function resolve(): void
126    {
127        if ($this->getState() !== self::PENDING) {
128            return;
129        }
130
131        $multi = ($this->promiser instanceof CurlMulti);
132        $auto  = (!($multi) && ($this->promiser->hasOption('auto')) &&
133            ($this->promiser->getOption('auto')));
134
135        if ($multi) {
136            $running = null;
137            do {
138                $this->promiser->send($running);
139            } while ($running);
140        } else {
141            $this->promiser->send();
142        }
143
144        if ($this->promiser->isComplete()) {
145            if ($this->promiser->isSuccess()) {
146                if (!$this->hasSuccess()) {
147                    throw new Exception('Error: The success callback has not been set.');
148                }
149
150                $result = null;
151                foreach ($this->success as $i => $success) {
152                    // Forward success callbacks to next promise
153                    if ($result instanceof Promise) {
154                        $result = $this->forward($result, $i);
155                        break;
156                    // Else, execute callback
157                    } else {
158                        if ($multi) {
159                            $response = $this->promiser->getAllResponses();
160                        } else {
161                            $response = (($auto) && ($this->promiser->hasResponse())) ?
162                                $this->promiser->getResponse()->getParsedResponse() : $this->promiser->getResponse();
163                        }
164                        $result = $success->call([
165                            'response' => $response
166                        ]);
167                    }
168                }
169
170                $this->setState(self::FULFILLED);
171
172                if ($result instanceof Promise) {
173                    $result->resolve();
174                }
175            } else if ($this->promiser->isError()) {
176                if (!$this->hasFailure()) {
177                    throw new Exception('Error: The failure callback has not been set.');
178                }
179                $this->setState(self::REJECTED);
180                if ($multi) {
181                    $response = $this->promiser->getAllResponses();
182                } else {
183                    $response = (($auto) && ($this->promiser->hasResponse())) ?
184                        $this->promiser->getResponse()->getParsedResponse() : $this->promiser->getResponse();
185                }
186                $this->failure->call([
187                    'response' => $response
188                ]);
189            }
190        }
191
192        if ($this->hasFinally()) {
193            $this->finally->call(['promise' => $this]);
194        }
195    }
196
197    /**
198     * Cancel method
199     *
200     * @throws Exception|ReflectionException|\Pop\Utils\Exception
201     * @return void
202     */
203    public function cancel(): void
204    {
205        if ($this->getState() !== self::PENDING) {
206            return;
207        }
208        if (!$this->hasCancel()) {
209            throw new Exception('Error: The cancel callback has not been set.');
210        }
211        $this->setState(self::CANCELLED);
212        $this->cancel->call(['promise' => $this]);
213    }
214
215}