Completed
Push — master ( 447a25...10a6bf )
by Márk
09:31
created

ReactHttpAdapter::buildReactRequest()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 2
Bugs 2 Features 0
Metric Value
c 2
b 2
f 0
dl 0
loc 19
ccs 15
cts 15
cp 1
rs 9.2
cc 4
eloc 12
nc 6
nop 1
crap 4
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\Exception\HttpException;
13
use Http\Client\Exception\RequestException;
14
use Http\Promise\Promise;
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
66 53
        return $promise->wait();
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 108
    public function sendAsyncRequest(RequestInterface $request)
73
    {
74 108
        $requestStream = $this->buildReactRequest($request);
75 108
        $deferred = new Deferred();
76
77
        $requestStream->on('error', function (\Exception $error) use ($deferred, $request) {
78 3
            $deferred->reject(new RequestException(
79 3
                $error->getMessage(),
80 3
                $request,
81
                $error
82 3
            ));
83 108
        });
84
        $requestStream->on('response', function (ReactResponse $response = null) use ($deferred, $requestStream, $request) {
85 105
            $bodyStream = null;
86
            $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...
87 105
                if ($data instanceof StreamInterface) {
88 105
                    $bodyStream = $data;
89 105
                } else {
90
                    $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...
91
                }
92 105
            });
93
94 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...
95 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...
96 105
                $psr7Response = $this->messageFactory->buildResponse(
97 105
                    $response,
98
                    $bodyStream
99 105
                );
100 105
                if (null !== $error) {
101
                    $deferred->reject(new HttpException(
102
                        $error->getMessage(),
103
                        $request,
104
                        $psr7Response,
105
                        $error
106
                    ));
107
                } else {
108 105
                    $deferred->resolve($psr7Response);
109
                }
110 105
            });
111 108
        });
112
113 108
        $requestStream->end((string)$request->getBody());
114
115 108
        $promise = new ReactPromiseAdapter($deferred->promise());
116 108
        $promise->setLoop($this->loop);
117 108
        return $promise;
118
    }
119
120
    /**
121
     * Build a React request from the PSR7 RequestInterface
122
     * @param  RequestInterface $request
123
     * @return ReactRequest
124
     */
125 108
    private function buildReactRequest(RequestInterface $request)
126
    {
127 108
        $headers = [];
128 108
        foreach ($request->getHeaders() as $name => $value) {
129 108
            $headers[$name] = (is_array($value)?$value[0]:$value);
130 108
        }
131 108
        if ($request->getBody()->getSize() > 0) {
132 40
            $headers['Content-Length'] = $request->getBody()->getSize();
133 40
        }
134
135 108
        $reactRequest = $this->client->request(
136 108
            $request->getMethod(),
137 108
            (string)$request->getUri(),
138 108
            $headers,
139 108
            $request->getProtocolVersion()
140 108
        );
141
142 108
        return $reactRequest;
143
    }
144
}
145