Completed
Push — master ( 6b8e31...cde88a )
by Stéphane
12:16
created

ReactHttpAdapter::__construct()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 16
ccs 7
cts 9
cp 0.7778
rs 9.2
cc 4
eloc 11
nc 6
nop 3
crap 4.1755
1
<?php
2
3
namespace Http\Adapter;
4
5
use React\EventLoop\LoopInterface;
6
use React\Promise\Deferred;
7
use React\HttpClient\Client;
8
use React\HttpClient\Request as ReactRequest;
9
use React\HttpClient\Response as ReactResponse;
10
use Http\Client\HttpClient;
11
use Http\Client\HttpAsyncClient;
12
use Http\Client\Promise;
13
use Http\Client\Exception\HttpException;
14
use Http\Client\Exception\RequestException;
15
use Http\Message\MessageFactory;
16
use Psr\Http\Message\RequestInterface;
17
use Psr\Http\Message\StreamInterface;
18
19
/**
20
 * Client for the React promise implementation
21
 * @author Stéphane Hulard <[email protected]>
22
 */
23
class ReactHttpAdapter implements HttpClient, HttpAsyncClient
24
{
25
    /**
26
     * React HTTP client
27
     * @var Client
28
     */
29
    private $client;
30
31
    /**
32
     * React event loop
33
     * @var LoopInterface
34
     */
35
    private $loop;
36
37
    /**
38
     * Initialize the React client
39
     * @param LoopInterface|null $loop     React Event loop
40
     * @param Resolver           $resolver React async DNS resolver
0 ignored issues
show
Bug introduced by
There is no parameter named $resolver. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
41
     */
42 108
    public function __construct(
43
        MessageFactory $messageFactory,
44
        LoopInterface $loop = null,
45
        Client $client = null
46
    ) {
47 108
        $this->loop = null === $loop?ReactFactory::buildEventLoop():$loop;
48 108
        if (null === $client) {
49 108
            $this->client = ReactFactory::buildHttpClient($this->loop);
50 108
        } elseif (null === $loop) {
51
            throw new \RuntimeException(
52
                "You must give a LoopInterface instance with the Client"
53
            );
54
        }
55
56 108
        $this->messageFactory = new ReactMessageFactory($messageFactory);
0 ignored issues
show
Bug introduced by
The property messageFactory does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
57 108
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 53
    public function sendRequest(RequestInterface $request)
63
    {
64 53
        $promise = $this->sendAsyncRequest($request);
65 53
        $promise->wait();
66
67 53
        if ($promise->getState() == Promise::REJECTED) {
68 1
            throw $promise->getException();
69
        }
70
71 52
        return $promise->getResponse();
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 108
    public function sendAsyncRequest(RequestInterface $request)
78
    {
79 108
        $requestStream = $this->buildReactRequest($request);
80 108
        $deferred = new Deferred();
81
82
        $requestStream->on('error', function (\Exception $error) use ($deferred, $request) {
83 3
            $deferred->reject(new RequestException(
84 3
                $error->getMessage(),
85 3
                $request,
86
                $error
87 3
            ));
88 108
        });
89
        $requestStream->on('response', function (ReactResponse $response = null) use ($deferred, $requestStream, $request) {
90 105
            $bodyStream = null;
91
            $response->on('data', function ($data) use (&$bodyStream) {
0 ignored issues
show
Bug introduced by
It seems like $response is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
92 105
                if ($data instanceof StreamInterface) {
93 105
                    $bodyStream = $data;
94 105
                } else {
95
                    $bodyStream->write($data);
0 ignored issues
show
Bug introduced by
The method write cannot be called on $bodyStream (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
96
                }
97 105
            });
98
99 105
            $response->on('end', function (\Exception $error = null) use ($deferred, $request, $response, &$bodyStream) {
0 ignored issues
show
Bug introduced by
It seems like $response is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
100 105
                $bodyStream->rewind();
0 ignored issues
show
Bug introduced by
The method rewind cannot be called on $bodyStream (of type null).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
101 105
                $psr7Response = $this->messageFactory->buildResponse(
102 105
                    $response,
103
                    $bodyStream
104 105
                );
105 105
                if (null !== $error) {
106
                    $deferred->reject(new HttpException(
107
                        $error->getMessage(),
108
                        $request,
109
                        $psr7Response,
110
                        $error
111
                    ));
112
                } else {
113 105
                    $deferred->resolve($psr7Response);
114
                }
115 105
            });
116 108
        });
117
118 108
        $requestStream->end((string)$request->getBody());
119
120 108
        $promise = new ReactPromiseAdapter($deferred->promise());
121 108
        $promise->setLoop($this->loop);
122 108
        return $promise;
123
    }
124
125
    /**
126
     * Build a React request from the PSR7 RequestInterface
127
     * @param  RequestInterface $request
128
     * @return ReactRequest
129
     */
130 108
    private function buildReactRequest(RequestInterface $request)
131
    {
132 108
        $headers = [];
133 108
        foreach ($request->getHeaders() as $name => $value) {
134 108
            $headers[$name] = (is_array($value)?$value[0]:$value);
135 108
        }
136 108
        if ($request->getBody()->getSize() > 0) {
137 40
            $headers['Content-Length'] = $request->getBody()->getSize();
138 40
        }
139
140 108
        $reactRequest = $this->client->request(
141 108
            $request->getMethod(),
142 108
            (string)$request->getUri(),
143 108
            $headers,
144 108
            $request->getProtocolVersion()
145 108
        );
146
147 108
        return $reactRequest;
148
    }
149
}
150