Client::getLastResponse()   A
last analyzed

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
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Manticoresearch;
6
7
use Manticoresearch\Connection\ConnectionPool;
8
use Manticoresearch\Connection\Strategy\SelectorInterface;
9
use Manticoresearch\Connection\Strategy\StaticRoundRobin;
10
11
use Manticoresearch\Endpoints\Pq;
12
use Manticoresearch\Exceptions\ConnectionException;
13
use Manticoresearch\Exceptions\NoMoreNodesException;
14
use Manticoresearch\Exceptions\RuntimeException;
15
use Manticoresearch\Response\SqlToArray;
16
use Psr\Log\LoggerInterface;
17
use Psr\Log\NullLogger;
18
19
/**
20
 * Manticore  client object
21
 * @package Manticoresearch
22
 * @category Manticoresearch
23
 * @author Adrian Nuta <[email protected]>
24
 * @link https://manticoresearch.com
25
 */
26
class Client
27
{
28
    /**
29
     *
30
     */
31
    const VERSION = '1.0.0';
32
33
    /**
34
     * @var array
35
     */
36
    protected $config = [];
37
    /**
38
     * @var string
39
     */
40
    private $connectionStrategy = StaticRoundRobin::class;
41
    /**
42
     * @var ConnectionPool
43
     */
44
    protected $connectionPool;
45
46
    /**
47
     * @var LoggerInterface|NullLogger
48
     */
49
    protected $logger;
50
51
    protected $lastResponse;
52
53
    /*
54
     * $config can be a connection array or
55
     * $config['connections] = array of connections
56
     * $config['connectionStrategy'] = class name of pool strategy
57
     */
58
    public function __construct($config = [], LoggerInterface $logger = null)
59
    {
60
        $this->setConfig($config);
61
        $this->logger = $logger ?? new NullLogger();
62
        $this->initConnections();
63
    }
64
65
    protected function initConnections()
66
    {
67
        $connections = [];
68
        if (isset($this->config['connections'])) {
69
            foreach ($this->config['connections'] as $connection) {
70
                if (is_array($connection)) {
71
                    $connections[] = Connection::create($connection);
72
                } else {
73
                    $connections[] = $connection;
74
                }
75
            }
76
        }
77
78
        if (empty($connections)) {
79
            $connections[] = Connection::create($this->config);
80
        }
81
        if (isset($this->config['connectionStrategy'])) {
82
            if (is_string($this->config['connectionStrategy'])) {
83
                $strategyName = $this->config['connectionStrategy'];
84
                if (strncmp($strategyName, 'Manticoresearch\\', 16) === 0) {
85
                    $strategy = new $strategyName();
86
                } else {
87
                    $strategyFullName = '\\Manticoresearch\\Connection\\Strategy\\' . $strategyName;
88
                    if (class_exists($strategyFullName)) {
89
                        $strategy = new $strategyFullName();
90
                    } elseif (class_exists($strategyName)) {
91
                        $strategy = new $strategyName();
92
                    }
93
                }
94
            } elseif ($this->config['connectionStrategy'] instanceof SelectorInterface) {
95
                $strategy = $this->config['connectionStrategy'];
96
            } else {
97
                throw new RuntimeException('Cannot create a strategy based on provided settings!');
98
            }
99
        } else {
100
            $strategy = new $this->connectionStrategy;
101
        }
102
        if (!isset($this->config['retries'])) {
103
            $this->config['retries'] = count($connections);
104
        }
105
        $this->connectionPool = new Connection\ConnectionPool(
106
            $connections,
107
            $strategy ?? new $this->connectionStrategy,
108
            $this->config['retries']
109
        );
110
    }
111
112
    /**
113
     * @param string|array $hosts
114
     */
115
    public function setHosts($hosts)
116
    {
117
        $this->config['connections'] = $hosts;
118
        $this->initConnections();
119
    }
120
121
    /**
122
     * @param array $config
123
     * @return $this
124
     */
125
    public function setConfig(array $config): self
126
    {
127
        $this->config = array_merge($this->config, $config);
128
        return $this;
129
    }
130
131
    /**
132
     * @param array $config
133
     * @return Client
134
     */
135
    public static function create($config): Client
136
    {
137
        return static::createFromArray($config);
138
    }
139
140
    /**
141
     * @param array $config
142
     * @return Client
143
     */
144
    public static function createFromArray($config): Client
145
    {
146
        return new self($config);
147
    }
148
149
    /**
150
     * @return mixed
151
     */
152
    public function getConnections()
153
    {
154
        return $this->connectionPool->getConnections();
155
    }
156
157
    /**
158
     * @return ConnectionPool
159
     */
160
    public function getConnectionPool(): ConnectionPool
161
    {
162
        return $this->connectionPool;
163
    }
164
165
    /**
166
     * Endpoint: search
167
     * @param array $params
168
     * @param bool $obj
169
     * @return array|Response
170
     */
171
    public function search(array $params = [], $obj = false)
172
    {
173
        $endpoint = new Endpoints\Search($params);
174
        $response = $this->request($endpoint);
175
        if ($obj === true) {
176
            return $response;
177
        } else {
178
            return $response->getResponse();
179
        }
180
    }
181
182
    /**
183
     * Endpoint: insert
184
     * @param array $params
185
     * @return array
186
     */
187
    public function insert(array $params = [])
188
    {
189
        $endpoint = new Endpoints\Insert($params);
190
        $response = $this->request($endpoint);
191
192
        return $response->getResponse();
193
    }
194
195
    /**
196
     * Endpoint: replace
197
     * @param array $params
198
     * @return mixed
199
     */
200
    public function replace(array $params = [])
201
    {
202
        $endpoint = new Endpoints\Replace($params);
203
        $response = $this->request($endpoint);
204
205
        return $response->getResponse();
206
    }
207
208
    /**
209
     * Endpoint: update
210
     * @param array $params
211
     * @return array
212
     */
213
    public function update(array $params = [])
214
    {
215
        $endpoint = new Endpoints\Update($params);
216
        $response = $this->request($endpoint);
217
218
        return $response->getResponse();
219
    }
220
221
222
    /**
223
     * Endpoint: sql
224
     * @param mixed $params
225
     * @return array
226
     *
227
     * $params can be either two parameters (string $query, bool $rawMode = false),
228
     * or a single parameter with the following structure (array [ 'mode' => $mode, 'body' => ['query' => $query] ])
229
     * The second variant is currently supported to provide compatibility with the older versions of the client
230
     */
231
    public function sql(...$params)
232
    {
233
        if (is_string($params[0])) {
234
            $params = [
235
                'body' => [
236
                    'query' => $params[0]
237
                ],
238
                'mode' => !empty($params[1]) && is_bool($params[1]) ? 'raw' : '',
239
            ];
240
        } else {
241
            $params = $params[0];
242
        }
243
        $endpoint = new Endpoints\Sql($params);
244
        if (isset($params['mode'])) {
245
            $endpoint->setMode($params['mode']);
246
            $response = $this->request($endpoint, ['responseClass' => SqlToArray::class]);
247
        } else {
248
            $response = $this->request($endpoint);
249
        }
250
        return $response->getResponse();
251
    }
252
253
    /**
254
     * Endpoint: delete
255
     * @param array $params
256
     * @return array
257
     */
258
    public function delete(array $params = [])
259
    {
260
        $endpoint = new Endpoints\Delete($params);
261
        $response = $this->request($endpoint);
262
263
        return $response->getResponse();
264
    }
265
266
    /**
267
     * Endpoint: pq
268
     */
269
    public function pq(): Pq
270
    {
271
        return new Pq($this);
272
    }
273
274
    /**
275
     * Endpoint: indices
276
     */
277
    public function indices(): Indices
278
    {
279
        return new Indices($this);
280
    }
281
282
    /**
283
     * Endpoint: nodes
284
     */
285
    public function nodes(): Nodes
286
    {
287
        return new Nodes($this);
288
    }
289
290
    public function cluster(): Cluster
291
    {
292
        return new Cluster($this);
293
    }
294
295
    /**
296
     * Return Index object
297
     *
298
     * @param string|null $name Name of index
299
     *
300
     * @return \Manticoresearch\Index
301
     */
302
    public function index(string $name = null): Index
303
    {
304
        return new Index($this, $name);
305
    }
306
307
    /**
308
     * Endpoint: bulk
309
     * @param array $params
310
     * @return array
311
     */
312
    public function bulk(array $params = [])
313
    {
314
        $endpoint = new Endpoints\Bulk($params);
315
        $response = $this->request($endpoint);
316
317
        return $response->getResponse();
318
    }
319
320
    /**
321
     * Endpoint: suggest
322
     * @param array $params
323
     * @return array
324
     */
325
    public function suggest(array $params = [])
326
    {
327
        $endpoint = new Endpoints\Suggest();
328
        $endpoint->setIndex($params['index']);
329
        $endpoint->setBody($params['body']);
330
        $response = $this->request(
331
            $endpoint,
332
            [
333
                'responseClass' => SqlToArray::class,
334
                'responseClassParams' => ['customMapping' => true]
335
            ]
336
        );
337
        return $response->getResponse();
338
    }
339
340
    public function keywords(array $params = [])
341
    {
342
        $endpoint = new Endpoints\Keywords();
343
        $endpoint->setIndex($params['index']);
344
        $endpoint->setBody($params['body']);
345
        $response = $this->request($endpoint, ['responseClass' => SqlToArray::class]);
346
        return $response->getResponse();
347
    }
348
349
    public function explainQuery(array $params = [])
350
    {
351
        $endpoint = new Endpoints\ExplainQuery();
352
        $endpoint->setIndex($params['index']);
353
        $endpoint->setBody($params['body']);
354
        $response = $this->request(
355
            $endpoint,
356
            [
357
                'responseClass' => SqlToArray::class,
358
                'responseClassParams' => ['customMapping' => true]
359
            ]
360
        );
361
        return $response->getResponse();
362
    }
363
364
365
    /*
366
     * @return Response
367
     */
368
369
    public function request(Request $request, array $params = []): Response
370
    {
371
        try {
372
            $connection = $this->connectionPool->getConnection();
373
            $this->lastResponse = $connection->getTransportHandler($this->logger)->execute($request, $params);
0 ignored issues
show
introduced by
The method execute() does not exist on Manticoresearch\Transport. Maybe you want to declare this class abstract? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

373
            $this->lastResponse = $connection->getTransportHandler($this->logger)->/** @scrutinizer ignore-call */ execute($request, $params);
Loading history...
374
        } catch (NoMoreNodesException $e) {
375
            $this->logger->error('Manticore Search Request out of retries:', [
376
                'exception' => $e->getMessage(),
377
                'request' => $request->toArray()
378
            ]);
379
380
            $this->initConnections();
381
            throw $e;
382
        } catch (ConnectionException $e) {
383
            $this->logger->warning(
384
                'Manticore Search Request failed on attempt ' . $this->connectionPool->retries_attempts . ':',
385
                [
386
                    'exception' => $e->getMessage(),
387
                    'request' => $e->getRequest()->toArray()
388
                ]
389
            );
390
391
            if ($connection) {
0 ignored issues
show
introduced by
$connection is of type Manticoresearch\Connection, thus it always evaluated to true.
Loading history...
392
                $connection->mark(false);
393
            }
394
395
            return $this->request($request, $params);
396
        }
397
        return $this->lastResponse;
398
    }
399
400
    /*
401
 *
402
 * @return Response
403
 */
404
405
    public function getLastResponse(): Response
406
    {
407
        return $this->lastResponse;
408
    }
409
}
410