ApiClient::getHttpClient()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 0
1
<?php
2
3
namespace ArgentCrusade\Selectel\CloudStorage\Api;
4
5
use RuntimeException;
6
use GuzzleHttp\Client;
7
use GuzzleHttp\ClientInterface;
8
use GuzzleHttp\Exception\RequestException;
9
use ArgentCrusade\Selectel\CloudStorage\Contracts\Api\ApiClientContract;
10
use ArgentCrusade\Selectel\CloudStorage\Exceptions\AuthenticationFailedException;
11
12
class ApiClient implements ApiClientContract
13
{
14
    const AUTH_URL = 'https://auth.selcdn.ru';
15
16
    /**
17
     * API Username.
18
     *
19
     * @var string
20
     */
21
    protected $username;
22
23
    /**
24
     * API Password.
25
     *
26
     * @var string
27
     */
28
    protected $password;
29
30
    /**
31
     * Authorization token.
32
     *
33
     * @var string
34
     */
35
    protected $token;
36
37
    /**
38
     * Storage URL.
39
     *
40
     * @var string
41
     */
42
    protected $storageUrl;
43
44
    /**
45
     * HTTP Client.
46
     *
47
     * @var \GuzzleHttp\ClientInterface
48
     */
49
    protected $httpClient;
50
51
    /**
52
     * Creates new API Client instance.
53
     *
54
     * @param string $username
55
     * @param string $password
56
     */
57
    public function __construct($username, $password)
58
    {
59
        $this->username = $username;
60
        $this->password = $password;
61
    }
62
63
    /**
64
     * Replaces HTTP Client instance.
65
     *
66
     * @param \GuzzleHttp\ClientInterface $httpClient
67
     *
68
     * @return \ArgentCrusade\Selectel\CloudStorage\Contracts\Api\ApiClientContract
69
     */
70
    public function setHttpClient(ClientInterface $httpClient)
71
    {
72
        $this->httpClient = $httpClient;
73
74
        return $this;
75
    }
76
77
    /**
78
     * HTTP Client.
79
     *
80
     * @return \GuzzleHttp\ClientInterface|null
81
     */
82
    public function getHttpClient()
83
    {
84
        if (!is_null($this->httpClient)) {
85
            return $this->httpClient;
86
        }
87
88
        return $this->httpClient = new Client([
89
            'base_uri' => $this->storageUrl(),
90
            'headers' => [
91
                'X-Auth-Token' => $this->token(),
92
            ],
93
        ]);
94
    }
95
96
    /**
97
     * Authenticated user's token.
98
     *
99
     * @return string
100
     */
101
    public function token()
102
    {
103
        return $this->token;
104
    }
105
106
    /**
107
     * Storage URL.
108
     *
109
     * @return string
110
     */
111
    public function storageUrl()
112
    {
113
        return $this->storageUrl;
114
    }
115
116
    /**
117
     * Determines if user is authenticated.
118
     *
119
     * @return bool
120
     */
121
    public function authenticated()
122
    {
123
        return !is_null($this->token());
124
    }
125
126
    /**
127
     * Performs authentication request.
128
     *
129
     * @throws \ArgentCrusade\Selectel\CloudStorage\Exceptions\AuthenticationFailedException
130
     * @throws \RuntimeException
131
     */
132
    public function authenticate()
133
    {
134
        if (!is_null($this->token)) {
135
            return;
136
        }
137
138
        $response = $this->authenticationResponse();
139
140
        if (!$response->hasHeader('X-Auth-Token')) {
141
            throw new AuthenticationFailedException('Given credentials are wrong.', 403);
142
        }
143
144
        if (!$response->hasHeader('X-Storage-Url')) {
145
            throw new RuntimeException('Storage URL is missing.', 500);
146
        }
147
148
        $this->token = $response->getHeaderLine('X-Auth-Token');
149
        $this->storageUrl = $response->getHeaderLine('X-Storage-Url');
150
    }
151
152
    /**
153
     * Performs authentication request and returns its response.
154
     *
155
     * @throws \ArgentCrusade\Selectel\CloudStorage\Exceptions\AuthenticationFailedException
156
     *
157
     * @return \Psr\Http\Message\ResponseInterface
158
     */
159
    public function authenticationResponse()
160
    {
161
        $client = new Client();
162
163
        try {
164
            $response = $client->request('GET', static::AUTH_URL, [
165
                'headers' => [
166
                    'X-Auth-User' => $this->username,
167
                    'X-Auth-Key' => $this->password,
168
                ],
169
            ]);
170
        } catch (RequestException $e) {
171
            throw new AuthenticationFailedException('Given credentials are wrong.', 403);
172
        }
173
174
        return $response;
175
    }
176
177
    /**
178
     * Performs new API request. $params array will be passed to HTTP Client as is.
179
     *
180
     * @param string $method
181
     * @param string $url
182
     * @param array  $params = []
183
     *
184
     * @return \Psr\Http\Message\ResponseInterface
185
     */
186
    public function request($method, $url, array $params = [])
187
    {
188
        if (!$this->authenticated()) {
189
            $this->authenticate();
190
        }
191
192
        if (!isset($params['query'])) {
193
            $params['query'] = [];
194
        }
195
196
        $params['query']['format'] = 'json';
197
198
        try {
199
            $response = $this->getHttpClient()->request($method, $url, $params);
200
        } catch (RequestException $e) {
201
            return $e->getResponse();
202
        }
203
204
        return $response;
205
    }
206
}
207