Passed
Push — master ( 9a922b...586424 )
by
unknown
02:20
created

Client::update()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

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