Promise::then()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Http\Adapter\Guzzle6;
6
7
use GuzzleHttp\Exception as GuzzleExceptions;
8
use GuzzleHttp\Promise\PromiseInterface;
9
use Http\Adapter\Guzzle6\Exception\UnexpectedValueException;
10
use Http\Client\Exception as HttplugException;
11
use Http\Promise\Promise as HttpPromise;
12
use Psr\Http\Message\RequestInterface;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * Wrapper around Guzzle promises.
17
 *
18
 * @author Joel Wurtz <[email protected]>
19
 */
20
final class Promise implements HttpPromise
21
{
22
    /**
23
     * @var PromiseInterface
24
     */
25
    private $promise;
26
27
    /**
28
     * @var string State of the promise
29
     */
30
    private $state;
31
32
    /**
33
     * @var ResponseInterface
34
     */
35
    private $response;
36
37
    /**
38
     * @var HttplugException
39
     */
40
    private $exception;
41
42
    /**
43
     * @var RequestInterface
44
     */
45
    private $request;
46
47 378
    public function __construct(PromiseInterface $promise, RequestInterface $request)
48
    {
49 378
        $this->request = $request;
50 378
        $this->state = self::PENDING;
51
        $this->promise = $promise->then(function ($response) {
52 353
            $this->response = $response;
53 353
            $this->state = self::FULFILLED;
54
55 353
            return $response;
56
        }, function ($reason) use ($request) {
57 25
            $this->state = self::REJECTED;
58
59 25
            if ($reason instanceof HttplugException) {
60 6
                $this->exception = $reason;
61 25
            } elseif ($reason instanceof GuzzleExceptions\GuzzleException) {
62 21
                $this->exception = $this->handleException($reason, $request);
63 4
            } elseif ($reason instanceof \Throwable) {
64 3
                $this->exception = new HttplugException\TransferException('Invalid exception returned from Guzzle6', 0, $reason);
65
            } else {
66 1
                $this->exception = new UnexpectedValueException('Reason returned from Guzzle6 must be an Exception');
67
            }
68
69 25
            throw $this->exception;
70 378
        });
71 378
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 159
    public function then(callable $onFulfilled = null, callable $onRejected = null)
77
    {
78 159
        return new static($this->promise->then($onFulfilled, $onRejected), $this->request);
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 369
    public function getState()
85
    {
86 369
        return $this->state;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92 378
    public function wait($unwrap = true)
93
    {
94 378
        $this->promise->wait(false);
95
96 378
        if ($unwrap) {
97 369
            if (self::REJECTED == $this->getState()) {
98 19
                throw $this->exception;
99
            }
100
101 350
            return $this->response;
102
        }
103 9
    }
104
105
    /**
106
     * Converts a Guzzle exception into an Httplug exception.
107
     */
108 21
    private function handleException(GuzzleExceptions\GuzzleException $exception, RequestInterface $request): HttplugException
109
    {
110 21
        if ($exception instanceof GuzzleExceptions\SeekException) {
111
            return new HttplugException\RequestException($exception->getMessage(), $request, $exception);
112
        }
113
114 21
        if ($exception instanceof GuzzleExceptions\ConnectException) {
115 11
            return new HttplugException\NetworkException($exception->getMessage(), $exception->getRequest(), $exception);
116
        }
117
118 10
        if ($exception instanceof GuzzleExceptions\RequestException) {
119
            // Make sure we have a response for the HttpException
120 9
            if ($exception->hasResponse()) {
121 4
                return new HttplugException\HttpException(
122 4
                    $exception->getMessage(),
123 4
                    $exception->getRequest(),
124 4
                    $exception->getResponse(),
0 ignored issues
show
Bug introduced by
It seems like $exception->getResponse() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
125 4
                    $exception
126
                );
127
            }
128
129 5
            return new HttplugException\RequestException($exception->getMessage(), $exception->getRequest(), $exception);
130
        }
131
132 1
        return new HttplugException\TransferException($exception->getMessage(), 0, $exception);
133
    }
134
}
135