Failed Conditions
Push — next ( 1e4ade...f47ec0 )
by Bas
04:16 queued 11s
created

ArangoClient::schema()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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