Completed
Push — master ( 175f97...21e55c )
by Joel
06:43
created

Promise   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 88.71%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 2
dl 0
loc 172
ccs 55
cts 62
cp 0.8871
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C then() 0 38 7
A resolve() 0 10 2
A doResolve() 0 8 2
A reject() 0 10 2
A doReject() 0 8 2
A getState() 0 4 1
A wait() 0 14 4
1
<?php
2
3
namespace Http\Adapter\React;
4
5
use React\EventLoop\LoopInterface;
6
use Http\Client\Exception;
7
use Http\Promise\Promise as HttpPromise;
8
use Psr\Http\Message\ResponseInterface;
9
10
/**
11
 * React promise adapter implementation.
12
 *
13
 * @author Stéphane Hulard <[email protected]>
14
 *
15
 * @internal
16
 */
17
final class Promise implements HttpPromise
18
{
19
    /**
20
     * Promise status.
21
     *
22
     * @var string
23
     */
24
    private $state = HttpPromise::PENDING;
25
26
    /**
27
     * PSR7 received response.
28
     *
29
     * @var ResponseInterface
30
     */
31
    private $response;
32
33
    /**
34
     * Execution error.
35
     *
36
     * @var Exception
37
     */
38
    private $exception;
39
40
    /**
41
     * @var callable|null
42
     */
43
    private $onFulfilled;
44
45
    /**
46
     * @var callable|null
47
     */
48
    private $onRejected;
49
50
    /**
51
     * React Event Loop used for synchronous processing.
52
     *
53
     * @var LoopInterface
54
     */
55
    private $loop;
56
57 109
    public function __construct(LoopInterface $loop)
58
    {
59 109
        $this->loop = $loop;
60 109
    }
61
62
    /**
63
     * Allow to apply callable when the promise resolve.
64
     *
65
     * @param callable|null $onFulfilled
66
     * @param callable|null $onRejected
67
     *
68
     * @return Promise
69
     */
70 56
    public function then(callable $onFulfilled = null, callable $onRejected = null)
71
    {
72 56
        $newPromise = new self($this->loop);
73
74
        $onFulfilled = $onFulfilled !== null ? $onFulfilled : function (ResponseInterface $response) {
75 1
            return $response;
76 56
        };
77
78
        $onRejected = $onRejected !== null ? $onRejected : function (Exception $exception) {
79 1
            throw $exception;
80 56
        };
81
82
        $this->onFulfilled = function (ResponseInterface $response) use ($onFulfilled, $newPromise) {
83
            try {
84 54
                $newPromise->resolve($onFulfilled($response));
85 54
            } catch (Exception $exception) {
86
                $newPromise->reject($exception);
87
            }
88 54
        };
89
90 2
        $this->onRejected = function (Exception $exception) use ($onRejected, $newPromise) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
91
            try {
92 2
                $newPromise->resolve($onRejected($exception));
93 2
            } catch (Exception $exception) {
94 2
                $newPromise->reject($exception);
95
            }
96 2
        };
97
98 56
        if ($this->state === HttpPromise::FULFILLED) {
99
            $this->doResolve($this->response);
100
        }
101
102 56
        if ($this->state === HttpPromise::REJECTED) {
103
            $this->doReject($this->exception);
104
        }
105
106 56
        return $newPromise;
107
    }
108
109
    /**
110
     * Resolve this promise.
111
     *
112
     * @param ResponseInterface $response
113
     *
114
     * @internal
115
     */
116 106
    public function resolve(ResponseInterface $response)
117
    {
118 106
        if ($this->state !== HttpPromise::PENDING) {
119
            throw new \RuntimeException('Promise is already resolved');
120
        }
121
122 106
        $this->state = HttpPromise::FULFILLED;
123 106
        $this->response = $response;
124 106
        $this->doResolve($response);
125 106
    }
126
127 106
    private function doResolve(ResponseInterface $response)
128
    {
129 106
        $onFulfilled = $this->onFulfilled;
130
131 106
        if (null !== $onFulfilled) {
132 54
            $onFulfilled($response);
133 54
        }
134 106
    }
135
136
    /**
137
     * Reject this promise.
138
     *
139
     * @param Exception $exception
140
     *
141
     * @internal
142
     */
143 3
    public function reject(Exception $exception)
144
    {
145 3
        if ($this->state !== HttpPromise::PENDING) {
146
            throw new \RuntimeException('Promise is already resolved');
147
        }
148
149 3
        $this->state = HttpPromise::REJECTED;
150 3
        $this->exception = $exception;
151 3
        $this->doReject($exception);
152 3
    }
153
154 3
    private function doReject(Exception $exception)
155
    {
156 3
        $onRejected = $this->onRejected;
157
158 3
        if (null !== $onRejected) {
159 2
            $onRejected($exception);
160 2
        }
161 3
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 109
    public function getState()
167
    {
168 109
        return $this->state;
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174 109
    public function wait($unwrap = true)
175
    {
176 109
        while (HttpPromise::PENDING === $this->getState()) {
177 108
            $this->loop->tick();
178 108
        }
179
180 109
        if ($unwrap) {
181 106
            if (HttpPromise::REJECTED == $this->getState()) {
182 1
                throw $this->exception;
183
            }
184
185 105
            return $this->response;
186
        }
187 3
    }
188
}
189