Passed
Pull Request — master (#88)
by Adam
02:20
created

Client::getUserAgent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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 Query strings to be applied to the request.
24
     */
25
    protected $query = [];
26
27
    /**
28
     * @var array Guzzle options to be applied to the request.
29
     */
30
    protected $options = [];
31
32
    /**
33
     * Client constructor.
34
     *
35
     * @param ConnectorInterface $connector
36
     */
37
    public function __construct(ConnectorInterface $connector)
38
    {
39
        $this->connector = $connector;
40
41
        $this->setUserAgent(
42
            sprintf(
43
                "%s/%s (https://github.com/typhonius/acquia-php-sdk-v2)",
44
                'acquia-php-sdk-v2',
45
                $this->getVersion()
46
            )
47
        );
48
    }
49
50
    /**
51
     * Client factory method for instantiating.
52
     *
53
     * @param ConnectorInterface $connector
54
     *
55
     * @return static
56
     */
57
    public static function factory(ConnectorInterface $connector)
58
    {
59
        $client = new static(
60
            $connector
61
        );
62
63
        return $client;
64
    }
65
66
    /**
67
     * Returns the current version of the library.
68
     *
69
     * @return string
70
     * @throws \Exception
71
     */
72
    public function getVersion()
73
    {
74
        if ($file = @file_get_contents(dirname(dirname(__DIR__)) . '/VERSION')) {
75
            return trim($file);
76
        } else {
77
            throw new \Exception('No VERSION file');
78
        }
79
    }
80
81
    /**
82
     * Allows the library to modify the request prior to making the call to the API.
83
     */
84
    public function modifyOptions($options = []): array
85
    {
86
        // Combine options set globally e.g. headers with options set by individual API calls e.g. form_params.
87
        $options = $this->options + $options;
88
89
        // This library can be standalone or as a dependency. Dependent libraries may also set their own user agent
90
        // which will make $options['headers']['User-Agent'] an array.
91
        // We need to array_unique() the array of User-Agent headers as multiple calls may include multiple of the same header.
92
        // 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.
93
        // As Guzzle joins arrays with a comma, we must implode with a space here to pass Guzzle a string.
94
        $userAgent = sprintf(
95
            "%s/%s (https://github.com/typhonius/acquia-php-sdk-v2)",
96
            'acquia-php-sdk-v2',
97
            $this->getVersion()
98
        );
99
        if (isset($options['headers']['User-Agent']) && is_array($options['headers']['User-Agent'])) {
100
            array_unshift($options['headers']['User-Agent'], $userAgent);
101
            $options['headers']['User-Agent'] = implode(' ', array_unique($options['headers']['User-Agent']));
102
        } else {
103
            $options['headers']['User-Agent'] = $userAgent;
104
        }
105
106
        $options['query'] = $this->query;
107
        if (!empty($options['query']['filter']) && is_array($options['query']['filter'])) {
108
            // Default to an OR filter to increase returned responses.
109
            $options['query']['filter'] = implode(',', $options['query']['filter']);
110
        }
111
112
        return $options;
113
    }
114
115
    /**
116
     * @inheritdoc
117
     */
118
    public function request(string $verb, string $path, array $options = [])
119
    {
120
        // @TODO follow this up by removing $options from the parameters able
121
        // to be passed into this function and instead solely relying on the
122
        // addOption() method as this can then be tested.
123
        $options = $this->modifyOptions($options);
124
125
        $response = $this->makeRequest($verb, $path, $options);
126
127
        return $this->processResponse($response);
128
    }
129
130
    /**
131
     * @inheritdoc
132
     */
133
    public function makeRequest(string $verb, string $path, array $options = []): ResponseInterface
134
    {
135
        try {
136
            $response = $this->connector->sendRequest($verb, $path, $options);
137
        } catch (BadResponseException $e) {
138
            $response = $e->getResponse();
139
        }
140
141
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response could return the type null which is incompatible with the type-hinted return Psr\Http\Message\ResponseInterface. Consider adding an additional type-check to rule them out.
Loading history...
142
    }
143
144
    /**
145
     * @inheritdoc
146
     */
147
    public function processResponse(ResponseInterface $response)
148
    {
149
150
        $body_json = $response->getBody();
151
        $body = json_decode($body_json);
152
        if (json_last_error() !== JSON_ERROR_NONE) {
153
            return $body_json;
154
        }
155
156
        if (property_exists($body, '_embedded') && property_exists($body->_embedded, 'items')) {
157
            return $body->_embedded->items;
158
        }
159
160
        if (property_exists($body, 'error') && property_exists($body, 'message')) {
161
            throw new ApiErrorException($body);
162
        }
163
164
        return $body;
165
    }
166
167
    /**
168
     * @inheritdoc
169
     */
170
    public function getQuery(): array
171
    {
172
        return $this->query;
173
    }
174
175
    /**
176
     * @inheritdoc
177
     */
178
    public function clearQuery(): void
179
    {
180
        $this->query = [];
181
    }
182
183
    /**
184
     * @inheritdoc
185
     */
186
    public function addQuery($name, $value): void
187
    {
188
        $this->query = array_merge_recursive($this->query, [$name => $value]);
189
    }
190
191
    /**
192
     * @inheritdoc
193
     */
194
    public function getOptions(): array
195
    {
196
        return $this->options;
197
    }
198
199
    /**
200
     * @inheritdoc
201
     */
202
    public function clearOptions(): void
203
    {
204
        $this->options = [];
205
    }
206
207
    /**
208
     * @inheritdoc
209
     */
210
    public function addOption($name, $value): void
211
    {
212
        $this->options = array_merge_recursive($this->options, [$name => $value]);
213
    }
214
215
    /**
216
     * @inheritdoc
217
     */
218
    public function setUserAgent($name): void
219
    {
220
        $this->userAgent[] = $name;
0 ignored issues
show
Bug Best Practice introduced by
The property userAgent does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
221
    }
222
223
    /**
224
     * @inheritdoc
225
     */
226
    public function getUserAgent(): array
227
    {
228
        return array_unique($this->userAgent);
229
    }
230
}
231