Completed
Pull Request — master (#42)
by Chad
01:29
created

GuzzleAdapter   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 129
c 0
b 0
f 0
wmc 10
lcom 1
cbo 5
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A start() 0 14 1
B end() 0 39 6
A fulfillPromises() 0 19 2
1
<?php
2
3
namespace TraderInteractive\Api;
4
5
use ArrayObject;
6
use DominionEnterprises\Util;
7
use GuzzleHttp\Client as GuzzleClient;
8
use GuzzleHttp\Exception\RequestException;
9
use GuzzleHttp\Promise;
10
use Psr\Http\Message\ResponseInterface;
11
12
/**
13
 * Concrete implentation of Adapter interface
14
 */
15
final class GuzzleAdapter implements Adapter
16
{
17
    /**
18
     * Collection of Promise\PromiseInterface instances with keys matching what was given from start().
19
     *
20
     * @var array
21
     */
22
    private $promises = [];
23
24
    /**
25
     * Collection of Api\Response with keys matching what was given from start().
26
     *
27
     * @var array
28
     */
29
    private $responses = [];
30
31
    /**
32
     * Collection of \Exception with keys matching what was given from start().
33
     *
34
     * @var array
35
     */
36
    private $exceptions = [];
37
38
    /**
39
     * @var \Guzzle\Http\Client
40
     */
41
    private $client;
42
43
    public function __construct()
44
    {
45
        $this->client = new GuzzleClient(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \GuzzleHttp\Client(a...http_errors' => false)) of type object<GuzzleHttp\Client> is incompatible with the declared type object<Guzzle\Http\Client> of property $client.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
46
            [
47
                'allow_redirects' => false, //stop guzzle from following redirects
48
                'http_errors' => false, //only for 400/500 error codes, actual exceptions can still happen
49
            ]
50
        );
51
    }
52
53
    /**
54
     * @see Adapter::start()
55
     */
56
    public function start(Request $request)
57
    {
58
        $handle = uniqid();
59
        $this->promises[$handle] = $this->client->requestAsync(
0 ignored issues
show
Bug introduced by
The method requestAsync() does not seem to exist on object<Guzzle\Http\Client>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
60
            $request->getMethod(),
61
            $request->getUrl(),
62
            [
63
                'headers' => $request->getHeaders(),
64
                'body' => $request->getBody(),
65
            ]
66
        );
67
68
        return $handle;
69
    }
70
71
    /**
72
     * @see Adapter::end()
73
     *
74
     * @throws \InvalidArgumentException
75
     */
76
    public function end($endHandle)
77
    {
78
        $results = $this->fulfillPromises($this->promises, $this->exceptions);
79
        foreach ($results as $handle => $response) {
80
            try {
81
                $body = []; //default to empty body
82
                $contents = (string)$response->getBody();
83
                if (trim($contents) !== '') {
84
                    $body = json_decode($contents, true);
85
                    Util::ensure(
86
                        JSON_ERROR_NONE,
87
                        json_last_error(),
88
                        '\UnexpectedValueException',
89
                        [json_last_error_msg()]
90
                    );
91
                }
92
93
                $this->responses[$handle] = new Response($response->getStatusCode(), $response->getHeaders(), $body);
94
            } catch (\Exception $e) {
95
                $this->exceptions[$handle] = $e;
96
            }
97
        }
98
99
        $this->promises = [];
100
101
        if (array_key_exists($endHandle, $this->exceptions)) {
102
            $exception = $this->exceptions[$endHandle];
103
            unset($this->exceptions[$endHandle]);
104
            throw $exception;
105
        }
106
107
        if (array_key_exists($endHandle, $this->responses)) {
108
            $response = $this->responses[$endHandle];
109
            unset($this->responses[$endHandle]);
110
            return $response;
111
        }
112
113
        throw new \InvalidArgumentException('$endHandle not found');
114
    }
115
116
    /**
117
     * Helper method to execute all guzzle promises.
118
     *
119
     * @param array $promises
120
     * @param array $exceptions
121
     *
122
     * @return array Array of fulfilled PSR7 responses.
123
     */
124
    private function fulfillPromises(array $promises, array &$exceptions)
125
    {
126
        if (empty($promises)) {
127
            return [];
128
        }
129
130
        $results = [];
131
        Promise\each(
132
            $this->promises,
133
            function (ResponseInterface $response, $index) use (&$results) {
134
                $results[$index] = $response;
135
            },
136
            function (RequestException $e, $index) use (&$exceptions) {
137
                $exceptions[$index] = $e;
138
            }
139
        )->wait();
140
141
        return $results;
142
    }
143
}
144