3
3
namespace Http \Adapter \React ;
4
4
5
5
use React \EventLoop \LoopInterface ;
6
- use React \Promise \PromiseInterface as ReactPromise ;
7
6
use Http \Client \Exception ;
8
7
use Http \Promise \Promise as HttpPromise ;
9
8
use Psr \Http \Message \ResponseInterface ;
12
11
* React promise adapter implementation.
13
12
*
14
13
* @author Stéphane Hulard <[email protected] >
14
+ *
15
+ * @internal
15
16
*/
16
- class Promise implements HttpPromise
17
+ final class Promise implements HttpPromise
17
18
{
18
19
/**
19
20
* Promise status.
@@ -22,13 +23,6 @@ class Promise implements HttpPromise
22
23
*/
23
24
private $ state = HttpPromise::PENDING ;
24
25
25
- /**
26
- * Adapted React promise.
27
- *
28
- * @var ReactPromise
29
- */
30
- private $ promise ;
31
-
32
26
/**
33
27
* PSR7 received response.
34
28
*
@@ -43,31 +37,26 @@ class Promise implements HttpPromise
43
37
*/
44
38
private $ exception ;
45
39
40
+ /**
41
+ * @var callable|null
42
+ */
43
+ private $ onFulfilled ;
44
+
45
+ /**
46
+ * @var callable|null
47
+ */
48
+ private $ onRejected ;
49
+
46
50
/**
47
51
* React Event Loop used for synchronous processing.
48
52
*
49
53
* @var LoopInterface
50
54
*/
51
55
private $ loop ;
52
56
53
- /**
54
- * Initialize the promise.
55
- *
56
- * @param ReactPromise $promise
57
- */
58
- public function __construct (ReactPromise $ promise )
57
+ public function __construct (LoopInterface $ loop )
59
58
{
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 ;
71
60
}
72
61
73
62
/**
@@ -80,49 +69,110 @@ function (Exception $error) {
80
69
*/
81
70
public function then (callable $ onFulfilled = null , callable $ onRejected = null )
82
71
{
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 );
86
87
}
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 );
90
95
}
91
- }) ;
96
+ };
92
97
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 ;
94
107
}
95
108
96
109
/**
97
- * {@inheritdoc}
110
+ * Resolve this promise.
111
+ *
112
+ * @param ResponseInterface $response
113
+ *
114
+ * @internal
98
115
*/
99
- public function getState ( )
116
+ public function resolve ( ResponseInterface $ response )
100
117
{
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
+ }
102
134
}
103
135
104
136
/**
105
- * Set EventLoop used for synchronous processing .
137
+ * Reject this promise .
106
138
*
107
- * @param LoopInterface $loop
139
+ * @param Exception $exception
108
140
*
109
- * @return Promise
141
+ * @internal
110
142
*/
111
- public function setLoop ( LoopInterface $ loop )
143
+ public function reject ( Exception $ exception )
112
144
{
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 ;
114
157
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 ;
116
169
}
117
170
118
171
/**
119
172
* {@inheritdoc}
120
173
*/
121
174
public function wait ($ unwrap = true )
122
175
{
123
- if (null === $ this ->loop ) {
124
- throw new \LogicException ('You must set the loop before wait! ' );
125
- }
126
176
while (HttpPromise::PENDING === $ this ->getState ()) {
127
177
$ this ->loop ->tick ();
128
178
}
0 commit comments