Passed
Push — master ( 53d7ac...d02665 )
by Dane
02:56 queued 29s
created

Client::makeRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
3
namespace AcquiaCloudApi\Connector;
4
5
use Psr\Http\Message\ResponseInterface;
6
use GuzzleHttp\Exception\BadResponseException;
7
use AcquiaCloudApi\Exception\ApiErrorException;
8
use Psr\Http\Message\StreamInterface;
9
10
/**
11
 * Class Client
12
 *
13
 * @package AcquiaCloudApi\CloudApi
14
 */
15
class Client implements ClientInterface
16
{
17
    /**
18
     * @var ConnectorInterface The API connector.
19
     */
20
    protected $connector;
21
22
    /**
23
     * @var array<string, mixed> Query strings to be applied to the request.
24
     */
25
    protected $query = [];
26
27
    /**
28
     * @var array<string, mixed> Guzzle options to be applied to the request.
29
     */
30
    protected $options = [];
31
32
    /**
33
     * @var array<string, mixed> Request options from each individual API call.
34
     */
35
    private $requestOptions = [];
36
37
    /**
38
     * Client constructor.
39
     *
40
     * @param ConnectorInterface $connector
41
     */
42
    final public function __construct(ConnectorInterface $connector)
43
    {
44
        $this->connector = $connector;
45
    }
46
47
    /**
48
     * Client factory method for instantiating.
49
     *
50
     * @param ConnectorInterface $connector
51
     *
52
     * @return static
53
     */
54
    public static function factory(ConnectorInterface $connector)
55
    {
56
        $client = new static(
57
            $connector
58
        );
59
60
        return $client;
61
    }
62
63
    /**
64
     * @inheritdoc
65
     */
66
    public function getVersion(): string
67
    {
68
        return self::VERSION;
69
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74
    public function modifyOptions(): array
75
    {
76
        // Combine options set globally e.g. headers with options set by individual API calls e.g. form_params.
77
        $options = $this->options + $this->requestOptions;
78
79
        // This library can be standalone or as a dependency. Dependent libraries may also set their own user agent
80
        // which will make $options['headers']['User-Agent'] an array.
81
        // We need to array_unique() the array of User-Agent headers as multiple calls may include multiple of the same header.
82
        // We also use array_unshift() to place this library's user agent first to order to have it appear at the beginning of log files.
83
        // As Guzzle joins arrays with a comma, we must implode with a space here to pass Guzzle a string.
84
        $userAgent = sprintf(
85
            "%s/%s (https://github.com/typhonius/acquia-php-sdk-v2)",
86
            'acquia-php-sdk-v2',
87
            $this->getVersion()
88
        );
89
        if (isset($options['headers']['User-Agent']) && is_array($options['headers']['User-Agent'])) {
90
            array_unshift($options['headers']['User-Agent'], $userAgent);
91
            $options['headers']['User-Agent'] = implode(' ', array_unique($options['headers']['User-Agent']));
92
        } else {
93
            $options['headers']['User-Agent'] = $userAgent;
94
        }
95
96
        $options['query'] = $this->query;
97
        if (!empty($options['query']['filter']) && is_array($options['query']['filter'])) {
98
            // Default to an OR filter to increase returned responses.
99
            $options['query']['filter'] = implode(',', $options['query']['filter']);
100
        }
101
102
        return $options;
103
    }
104
105
    /**
106
     * @inheritdoc
107
     */
108
    public function request(string $verb, string $path, array $options = [])
109
    {
110
        // Put options sent with API calls into a property so they can be accessed
111
        // and therefore tested in tests.
112
        $this->requestOptions = $options;
113
114
        // Modify the options to combine options set as part of the API call as well
115
        // as those set by tools extending this library.
116
        $modifiedOptions = $this->modifyOptions();
117
118
        $response = $this->makeRequest($verb, $path, $modifiedOptions);
119
120
        return $this->processResponse($response);
121
    }
122
123
    /**
124
     * @inheritdoc
125
     */
126
    public function stream(string $verb, string $path, array $options = [])
127
    {
128
        // Put options sent with API calls into a property so they can be accessed
129
        // and therefore tested in tests.
130
        $this->requestOptions = $options;
131
132
        // Modify the options to combine options set as part of the API call as well
133
        // as those set by tools extending this library.
134
        $modifiedOptions = $this->modifyOptions();
135
136
        $response = $this->makeRequest($verb, $path, $modifiedOptions);
137
138
        return $response->getBody();
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144
    public function makeRequest(string $verb, string $path, array $options = []): ResponseInterface
145
    {
146
        try {
147
            $response = $this->connector->sendRequest($verb, $path, $options);
148
        } catch (BadResponseException $e) {
149
            $response = $e->getResponse();
150
        }
151
152
        return $response;
153
    }
154
155
    /**
156
     * @inheritdoc
157
     */
158
    public function processResponse(ResponseInterface $response)
159
    {
160
161
        $body_json = $response->getBody();
162
        $body = json_decode($body_json);
163
164
        if (property_exists($body, '_embedded') && property_exists($body->_embedded, 'items')) {
165
            return $body->_embedded->items;
166
        }
167
168
        if (property_exists($body, 'error') && property_exists($body, 'message')) {
169
            throw new ApiErrorException($body);
170
        }
171
172
        return $body;
173
    }
174
175
    /**
176
     * @inheritdoc
177
     */
178
    public function getQuery(): array
179
    {
180
        return $this->query;
181
    }
182
183
    /**
184
     * @inheritdoc
185
     */
186
    public function clearQuery(): void
187
    {
188
        $this->query = [];
189
    }
190
191
    /**
192
     * @inheritdoc
193
     */
194
    public function addQuery($name, $value): void
195
    {
196
        $this->query = array_merge_recursive($this->query, [$name => $value]);
197
    }
198
199
    /**
200
     * @inheritdoc
201
     */
202
    public function getOptions(): array
203
    {
204
        return $this->options;
205
    }
206
207
    /**
208
     * @inheritdoc
209
     */
210
    public function clearOptions(): void
211
    {
212
        $this->options = [];
213
    }
214
215
    /**
216
     * @inheritdoc
217
     */
218
    public function addOption($name, $value): void
219
    {
220
        $this->options = array_merge_recursive($this->options, [$name => $value]);
221
    }
222
}
223