Completed
Pull Request — master (#88)
by Adam
08:54
created

Client::setUserAgent()   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 1
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
     * @var array User agent strings to be concatenated and added to each request.
34
     */
35
    protected $userAgent = [];
36
37
    /**
38
     * Client constructor.
39
     *
40
     * @param ConnectorInterface $connector
41
     */
42
    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
     * Returns the current version of the library.
65
     *
66
     * @return string
67
     * @throws \Exception
68
     */
69
    public function getVersion()
70
    {
71
        if ($file = @file_get_contents(dirname(dirname(__DIR__)) . '/VERSION')) {
72
            return trim($file);
73
        } else {
74
            throw new \Exception('No VERSION file');
75
        }
76
    }
77
78
    /**
79
     * Allows the library to modify the request prior to making the call to the API.
80
     */
81
    public function modifyOptions($options = []): array
82
    {
83
        // Add the user agent header here so it can't be removed by other libraries.
84
        $this->setUserAgent(
85
            sprintf(
86
                "%s/%s (https://github.com/typhonius/acquia-php-sdk-v2)",
87
                'acquia-php-sdk-v2',
88
                $this->getVersion()
89
            )
90
        );
91
92
        // Combine options set globally e.g. headers with options set by individual API calls e.g. form_params.
93
        $options = $this->options + $options;
94
95
        // This library can be standalone or as a dependency. Dependent libraries may also set their own user agent
96
        // which will make $options['headers']['User-Agent'] an array.
97
        // We need to reverse the array of User-Agent headers to order this library's header first in log files.
98
        // As Guzzle joins arrays with a comma, we must implode with a space here to pass Guzzle a string.
99
        $userAgent = $this->getUserAgent();
100
101
        if (is_array($userAgent)) {
0 ignored issues
show
introduced by
The condition is_array($userAgent) is always true.
Loading history...
102
            $options['headers']['User-Agent'] = implode(' ', array_reverse($userAgent));
103
        }
104
105
        $options['query'] = $this->query;
106
        if (!empty($options['query']['filter']) && is_array($options['query']['filter'])) {
107
            // Default to an AND filter.
108
            $options['query']['filter'] = implode(',', $options['query']['filter']);
109
        }
110
111
        return $options;
112
    }
113
114
    /**
115
     * @inheritdoc
116
     */
117
    public function request(string $verb, string $path, array $options = [])
118
    {
119
        // @TODO follow this up by removing $options from the parameters able
120
        // to be passed into this function and instead solely relying on the
121
        // addOption() method as this can then be tested.
122
        $options = $this->modifyOptions($options);
123
124
        $response = $this->makeRequest($verb, $path, $options);
125
126
        return $this->processResponse($response);
127
    }
128
129
    /**
130
     * @inheritdoc
131
     */
132
    public function makeRequest(string $verb, string $path, array $options = []): ResponseInterface
133
    {
134
        try {
135
            $response = $this->connector->sendRequest($verb, $path, $options);
136
        } catch (BadResponseException $e) {
137
            $response = $e->getResponse();
138
        }
139
140
        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...
141
    }
142
143
    /**
144
     * @inheritdoc
145
     */
146
    public function processResponse(ResponseInterface $response)
147
    {
148
149
        $body_json = $response->getBody();
150
        $body = json_decode($body_json);
151
        if (json_last_error() !== JSON_ERROR_NONE) {
152
            return $body_json;
153
        }
154
155
        if (property_exists($body, '_embedded') && property_exists($body->_embedded, 'items')) {
156
            return $body->_embedded->items;
157
        }
158
159
        if (property_exists($body, 'error') && property_exists($body, 'message')) {
160
            throw new ApiErrorException($body);
161
        }
162
163
        return $body;
164
    }
165
166
    /**
167
     * @inheritdoc
168
     */
169
    public function getQuery(): array
170
    {
171
        return $this->query;
172
    }
173
174
    /**
175
     * @inheritdoc
176
     */
177
    public function clearQuery(): void
178
    {
179
        $this->query = [];
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185
    public function addQuery($name, $value): void
186
    {
187
        $this->query = array_merge_recursive($this->query, [$name => $value]);
188
    }
189
190
    /**
191
     * @inheritdoc
192
     */
193
    public function getOptions(): array
194
    {
195
        return $this->options;
196
    }
197
198
    /**
199
     * @inheritdoc
200
     */
201
    public function clearOptions(): void
202
    {
203
        $this->options = [];
204
    }
205
206
    /**
207
     * @inheritdoc
208
     */
209
    public function addOption($name, $value): void
210
    {
211
        $this->options = array_merge_recursive($this->options, [$name => $value]);
212
    }
213
214
    /**
215
     * @inheritdoc
216
     */
217
    public function setUserAgent($name): void
218
    {
219
        $this->userAgent[$name] = $name;
220
    }
221
222
    /**
223
     * @inheritdoc
224
     */
225
    public function getUserAgent(): array
226
    {
227
        return $this->userAgent;
228
    }
229
}
230