33namespace Http \Adapter \React ;
44
55use React \EventLoop \LoopInterface ;
6- use React \Promise \PromiseInterface as ReactPromise ;
76use Http \Client \Exception ;
87use Http \Promise \Promise as HttpPromise ;
98use Psr \Http \Message \ResponseInterface ;
1211 * React promise adapter implementation.
1312 *
1413 * @author Stéphane Hulard <stephane@hlrd.me>
14+ *
15+ * @internal
1516 */
16- class Promise implements HttpPromise
17+ final class Promise implements HttpPromise
1718{
1819 /**
1920 * Promise status.
@@ -22,13 +23,6 @@ class Promise implements HttpPromise
2223 */
2324 private $ state = HttpPromise::PENDING ;
2425
25- /**
26- * Adapted React promise.
27- *
28- * @var ReactPromise
29- */
30- private $ promise ;
31-
3226 /**
3327 * PSR7 received response.
3428 *
@@ -43,31 +37,26 @@ class Promise implements HttpPromise
4337 */
4438 private $ exception ;
4539
40+ /**
41+ * @var callable|null
42+ */
43+ private $ onFulfilled ;
44+
45+ /**
46+ * @var callable|null
47+ */
48+ private $ onRejected ;
49+
4650 /**
4751 * React Event Loop used for synchronous processing.
4852 *
4953 * @var LoopInterface
5054 */
5155 private $ loop ;
5256
53- /**
54- * Initialize the promise.
55- *
56- * @param ReactPromise $promise
57- */
58- public function __construct (ReactPromise $ promise )
57+ public function __construct (LoopInterface $ loop )
5958 {
60- $ promise ->then (
61- function (ResponseInterface $ response ) {
62- $ this ->state = HttpPromise::FULFILLED ;
63- $ this ->response = $ response ;
64- },
65- function (Exception $ error ) {
66- $ this ->state = HttpPromise::REJECTED ;
67- $ this ->exception = $ error ;
68- }
69- );
70- $ this ->promise = $ promise ;
59+ $ this ->loop = $ loop ;
7160 }
7261
7362 /**
@@ -80,49 +69,110 @@ function (Exception $error) {
8069 */
8170 public function then (callable $ onFulfilled = null , callable $ onRejected = null )
8271 {
83- $ this ->promise ->then (function () use ($ onFulfilled ) {
84- if (null !== $ onFulfilled ) {
85- call_user_func ($ onFulfilled , $ this ->response );
72+ $ newPromise = new self ($ this ->loop );
73+
74+ $ onFulfilled = $ onFulfilled !== null ? $ onFulfilled : function (ResponseInterface $ response ) {
75+ return $ response ;
76+ };
77+
78+ $ onRejected = $ onRejected !== null ? $ onRejected : function (Exception $ exception ) {
79+ throw $ exception ;
80+ };
81+
82+ $ this ->onFulfilled = function (ResponseInterface $ response ) use ($ onFulfilled , $ newPromise ) {
83+ try {
84+ $ newPromise ->resolve ($ onFulfilled ($ response ));
85+ } catch (Exception $ exception ) {
86+ $ newPromise ->reject ($ exception );
8687 }
87- }, function () use ($ onRejected ) {
88- if (null !== $ onRejected ) {
89- call_user_func ($ onRejected , $ this ->exception );
88+ };
89+
90+ $ this ->onRejected = function (Exception $ exception ) use ($ onRejected , $ newPromise ) {
91+ try {
92+ $ newPromise ->resolve ($ onRejected ($ exception ));
93+ } catch (Exception $ exception ) {
94+ $ newPromise ->reject ($ exception );
9095 }
91- }) ;
96+ };
9297
93- return $ this ;
98+ if ($ this ->state === HttpPromise::FULFILLED ) {
99+ $ this ->doResolve ($ this ->response );
100+ }
101+
102+ if ($ this ->state === HttpPromise::REJECTED ) {
103+ $ this ->doReject ($ this ->exception );
104+ }
105+
106+ return $ newPromise ;
94107 }
95108
96109 /**
97- * {@inheritdoc}
110+ * Resolve this promise.
111+ *
112+ * @param ResponseInterface $response
113+ *
114+ * @internal
98115 */
99- public function getState ( )
116+ public function resolve ( ResponseInterface $ response )
100117 {
101- return $ this ->state ;
118+ if ($ this ->state !== HttpPromise::PENDING ) {
119+ throw new \RuntimeException ('Promise is already resolved ' );
120+ }
121+
122+ $ this ->state = HttpPromise::FULFILLED ;
123+ $ this ->response = $ response ;
124+ $ this ->doResolve ($ response );
125+ }
126+
127+ private function doResolve (ResponseInterface $ response )
128+ {
129+ $ onFulfilled = $ this ->onFulfilled ;
130+
131+ if (null !== $ onFulfilled ) {
132+ $ onFulfilled ($ response );
133+ }
102134 }
103135
104136 /**
105- * Set EventLoop used for synchronous processing .
137+ * Reject this promise .
106138 *
107- * @param LoopInterface $loop
139+ * @param Exception $exception
108140 *
109- * @return Promise
141+ * @internal
110142 */
111- public function setLoop ( LoopInterface $ loop )
143+ public function reject ( Exception $ exception )
112144 {
113- $ this ->loop = $ loop ;
145+ if ($ this ->state !== HttpPromise::PENDING ) {
146+ throw new \RuntimeException ('Promise is already resolved ' );
147+ }
148+
149+ $ this ->state = HttpPromise::REJECTED ;
150+ $ this ->exception = $ exception ;
151+ $ this ->doReject ($ exception );
152+ }
153+
154+ private function doReject (Exception $ exception )
155+ {
156+ $ onRejected = $ this ->onRejected ;
114157
115- return $ this ;
158+ if (null !== $ onRejected ) {
159+ $ onRejected ($ exception );
160+ }
161+ }
162+
163+ /**
164+ * {@inheritdoc}
165+ */
166+ public function getState ()
167+ {
168+ return $ this ->state ;
116169 }
117170
118171 /**
119172 * {@inheritdoc}
120173 */
121174 public function wait ($ unwrap = true )
122175 {
123- if (null === $ this ->loop ) {
124- throw new \LogicException ('You must set the loop before wait! ' );
125- }
126176 while (HttpPromise::PENDING === $ this ->getState ()) {
127177 $ this ->loop ->tick ();
128178 }
0 commit comments