Passed
Pull Request — next (#13)
by
unknown
12:47 queued 10:38
created

ArangoClient::getDatabase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ArangoClient;
6
7
use ArangoClient\Exceptions\ArangoException;
8
use ArangoClient\Http\HttpClientConfig;
9
use ArangoClient\Http\HttpRequestOptions;
10
use ArangoClient\Statement\Statement;
11
use ArangoClient\Transactions\SupportsTransactions;
12
use GuzzleHttp\Client as GuzzleClient;
13
use GuzzleHttp\Exception\GuzzleException;
14
use GuzzleHttp\Exception\RequestException;
15
use Psr\Http\Message\ResponseInterface;
16
use Spatie\DataTransferObject\Exceptions\UnknownProperties;
17
use stdClass;
18
use Throwable;
19
use Traversable;
20
21
/**
22
 * The arangoClient handles connections to ArangoDB's HTTP REST API.
23
 *
24
 * @see https://www.arangodb.com/docs/stable/http/
25
 */
26
class ArangoClient
27
{
28
    use HandlesJson;
29
    use HasManagers;
30
    use SupportsTransactions;
31
32
    protected GuzzleClient $httpClient;
33
34
    protected HttpClientConfig $config;
35
36
    /**
37
     * ArangoClient constructor.
38
     *
39
     * @param  array<string|numeric|null>  $config
40
     * @param  GuzzleClient|null  $httpClient
41
     *
42
     * @throws UnknownProperties
43
     */
44 107
    public function __construct(array $config = [], GuzzleClient $httpClient = null)
45
    {
46 107
        $config['endpoint'] = $this->generateEndpoint($config);
47 107
        $this->config = new HttpClientConfig($config);
48
49 107
        $this->httpClient = $httpClient ?? new GuzzleClient($this->config->mapGuzzleHttpClientConfig());
50
    }
51
52
    /**
53
     * @param  array<mixed>  $config
54
     * @return string
55
     */
56 107
    public function generateEndpoint(array $config): string
57
    {
58 107
        if (isset($config['endpoint'])) {
59
            return (string) $config['endpoint'];
60
        }
61 107
        $endpoint = 'http://localhost:8529';
62 107
        if (isset($config['host'])) {
63 2
            $endpoint = (string) $config['host'];
64
        }
65 107
        if (isset($config['port'])) {
66 2
            $endpoint .= ':'.(string) $config['port'];
67
        }
68
69 107
        return $endpoint;
70
    }
71
72
    /**
73
     * @psalm-suppress MixedReturnStatement
74
     *
75
     * @param  string  $method
76
     * @param  string  $uri
77
     * @param  array<mixed>|HttpRequestOptions  $options
78
     * @param  string|null  $database
79
     * @return stdClass
80
     *
81
     * @throws ArangoException
82
     */
83 107
    public function request(string $method, string $uri, $options = [], ?string $database = null): stdClass
84
    {
85 107
        $uri = $this->prependDatabaseToUri($uri, $database);
86
87 107
        if (is_array($options)) {
88 107
            $options = $this->prepareRequestOptions($options);
89
        }
90
91 107
        $response = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
92
        try {
93 107
            $response = $this->httpClient->request($method, $uri, $options->all());
94 2
        } catch (Throwable $e) {
95 2
            $this->handleGuzzleException($e);
96
        }
97
98 107
        return $this->cleanupResponse($response);
99
    }
100
101
    /**
102
     * @param  array<mixed>  $options
103
     * @return HttpRequestOptions
104
     *
105
     * @throws ArangoException
106
     */
107 107
    protected function prepareRequestOptions(array $options): HttpRequestOptions
108
    {
109 107
        if (isset($options['body'])) {
110 69
            $options['body'] = $this->jsonEncode($options['body']);
111
        }
112
113 107
        return new HttpRequestOptions($options);
114
    }
115
116
    /**
117
     * Return the response with debug information (for internal testing purposes).
118
     *
119
     * @param  string  $method
120
     * @param  string  $uri
121
     * @param  array<mixed>  $options
122
     * @param  string|null  $database
123
     * @return ResponseInterface
124
     *
125
     * @throws GuzzleException
126
     */
127 2
    public function debugRequest(
128
        string $method,
129
        string $uri,
130
        array $options = [],
131
        ?string $database = null
132
    ): ResponseInterface {
133 2
        $uri = $this->prependDatabaseToUri($uri, $database);
134 2
        $options['debug'] = true;
135
136 2
        return $this->httpClient->request($method, $uri, $options);
137
    }
138
139 107
    protected function prependDatabaseToUri(string $uri, ?string $database = null): string
140
    {
141 107
        if (! isset($database)) {
142 107
            $database = $this->config->database;
143
        }
144
145 107
        return '/_db/'.urlencode($database).$uri;
146
    }
147
148
    /**
149
     * @param  Throwable  $e
150
     *
151
     * @throws ArangoException
152
     */
153 2
    protected function handleGuzzleException(Throwable $e): void
154
    {
155 2
        $message = $e->getMessage();
156 2
        $code = $e->getCode();
157
158 2
        if ($e instanceof RequestException && $e->hasResponse()) {
159 2
            $decodedResponse = $this->decodeResponse($e->getResponse());
160 2
            $message = (string) $decodedResponse->errorMessage;
161 2
            $code = (int) $decodedResponse->code;
162
        }
163
164
        throw(
165 2
            new ArangoException(
166
                $code.' - '.$message,
167
                $code
168
            )
169
        );
170
    }
171
172
    /**
173
     * @psalm-suppress MixedAssignment, MixedArrayOffset
174
     * @SuppressWarnings(PHPMD.StaticAccess)
175
     *
176
     * @param  ResponseInterface|null  $response
177
     * @return stdClass
178
     */
179 107
    protected function cleanupResponse(?ResponseInterface $response): stdClass
180
    {
181 107
        $response = $this->decodeResponse($response);
182 107
        unset($response->error);
183 107
        unset($response->code);
184
185 107
        return $response;
186
    }
187
188
    /**
189
     * @param  string  $query
190
     * @param  array<scalar>  $bindVars
191
     * @param  array<mixed>  $options
192
     * @return Statement
193
     */
194 17
    public function prepare(
195
        string $query,
196
        array $bindVars = [],
197
        array $options = []
198
    ): Traversable {
199 17
        return new Statement($this, $query, $bindVars, $options);
200
    }
201
202
    /**
203
     * @return array<array-key, mixed>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, mixed> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, mixed>.
Loading history...
204
     */
205 4
    public function getConfig(): array
206
    {
207 4
        return $this->config->toArray();
208
    }
209
210
    /**
211
     * @param  string  $name
212
     * @return void
213
     */
214 107
    public function setDatabase(string $name): void
215
    {
216 107
        $this->config->database = $name;
217
    }
218
219
    /**
220
     * @return string
221
     */
222 1
    public function getDatabase(): string
223
    {
224 1
        return $this->config->database;
225
    }
226
227 1
    public function setHttpClient(GuzzleClient $httpClient): void
228
    {
229 1
        $this->httpClient = $httpClient;
230
    }
231
232 1
    public function getHttpClient(): GuzzleClient
233
    {
234 1
        return $this->httpClient;
235
    }
236
237 107
    public function getUser(): string
238
    {
239 107
        return (string) $this->config->username;
240
    }
241
}
242