Completed
Pull Request — master (#24)
by Chad
03:04
created

GuzzleAdapter   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 134
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 10
c 3
b 0
f 0
lcom 1
cbo 5
dl 0
loc 134
rs 10

4 Methods

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