Completed
Pull Request — master (#37)
by Eugene
06:36
created

Client::fromOptions()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 0
cts 18
cp 0
rs 8.7537
c 0
b 0
f 0
cc 6
nc 32
nop 1
crap 42
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Tarantool Client package.
7
 *
8
 * (c) Eugene Leonovich <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Tarantool\Client;
15
16
use Tarantool\Client\Connection\StreamConnection;
17
use Tarantool\Client\Exception\RequestFailed;
18
use Tarantool\Client\Handler\DefaultHandler;
19
use Tarantool\Client\Handler\Handler;
20
use Tarantool\Client\Handler\MiddlewareHandler;
21
use Tarantool\Client\Middleware\AuthMiddleware;
22
use Tarantool\Client\Middleware\Middleware;
23
use Tarantool\Client\Middleware\RetryMiddleware;
24
use Tarantool\Client\Packer\PurePacker;
25
use Tarantool\Client\Request\Call;
26
use Tarantool\Client\Request\Evaluate;
27
use Tarantool\Client\Request\Execute;
28
use Tarantool\Client\Request\Ping;
29
use Tarantool\Client\Schema\Index;
30
use Tarantool\Client\Schema\Space;
31
32
final class Client
33
{
34
    private $handler;
35
    private $spaces = [];
36
37 258
    public function __construct(Handler $handler)
38
    {
39 258
        $this->handler = $handler;
40 258
    }
41
42
    public static function fromDefaults() : self
43
    {
44
        return new self(new DefaultHandler(
45
            new StreamConnection(),
46
            new PurePacker()
47
        ));
48
    }
49
50
    public static function fromOptions(array $options) : self
51
    {
52
        $connectionOptions = [];
53
54
        if (isset($options['connect_timeout'])) {
55
            $connectionOptions['connect_timeout'] = $options['connect_timeout'];
56
        }
57
        if (isset($options['socket_timeout'])) {
58
            $connectionOptions['socket_timeout'] = $options['socket_timeout'];
59
        }
60
        if (isset($options['tcp_nodelay'])) {
61
            $connectionOptions['tcp_nodelay'] = $options['tcp_nodelay'];
62
        }
63
64
        $handler = new DefaultHandler(
65
            new StreamConnection($options['uri'] ?? StreamConnection::DEFAULT_URI, $connectionOptions),
66
            new PurePacker()
67
        );
68
69
        if (isset($options['username'])) {
70
            $handler = new MiddlewareHandler(
71
                new AuthMiddleware($options['username'], $options['password'] ?? ''),
72
                $handler
73
            );
74
        }
75
        if (isset($options['max_retries'])) {
76
            $handler = new MiddlewareHandler(
77
                RetryMiddleware::linear($options['max_retries']),
78
                $handler
79
            );
80
        }
81
82
        return new self($handler);
83
    }
84
85
    public static function fromDsn(string $dsn) : self
86
    {
87
        $dsn = Dsn::parse($dsn);
88
89
        return self::fromOptions([
90
            'uri' => $dsn->getConnectionUri(),
91
            'connect_timeout' => $dsn->getInt('connect_timeout'),
92
            'socket_timeout' => $dsn->getInt('socket_timeout'),
93
            'tcp_nodelay' => $dsn->getBool('tcp_nodelay'),
94
            'username' => $dsn->getUsername(),
95
            'password' => $dsn->getPassword(),
96
            'max_retries' => $dsn->getInt('max_retries'),
97
        ]);
98
    }
99
100
    public function withMiddleware(Middleware $middleware, Middleware ...$middlewares) : self
101
    {
102
        $new = clone $this;
103
        $new->handler = new MiddlewareHandler($middleware, $this->handler);
104
105
        if ($middlewares) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $middlewares of type Tarantool\Client\Middleware\Middleware[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
106
            $new->handler = MiddlewareHandler::create($new->handler, $middlewares);
107
        }
108
109
        return $new;
110
    }
111
112 12
    public function getHandler() : Handler
113
    {
114 12
        return $this->handler;
115
    }
116
117 54
    public function ping() : void
118
    {
119 54
        $this->handler->handle(new Ping());
120 4
    }
121
122 116
    public function getSpace(string $spaceName) : Space
123
    {
124 116
        if (isset($this->spaces[$spaceName])) {
125 2
            return $this->spaces[$spaceName];
126
        }
127
128 116
        $spaceId = $this->getSpaceIdByName($spaceName);
129
130 112
        return $this->spaces[$spaceName] = $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
131
    }
132
133 122
    public function getSpaceById(int $spaceId) : Space
134
    {
135 122
        if (isset($this->spaces[$spaceId])) {
136
            return $this->spaces[$spaceId];
137
        }
138
139 122
        return $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
140
    }
141
142 10
    public function call(string $funcName, ...$args) : array
143
    {
144 10
        $request = new Call($funcName, $args);
145
146 10
        return $this->handler->handle($request)->getBodyField(IProto::DATA);
147
    }
148
149 8
    public function executeQuery(string $sql, array $params = []) : SqlQueryResult
150
    {
151 8
        $request = new Execute($sql, $params);
152 8
        $response = $this->handler->handle($request);
153
154 8
        return new SqlQueryResult(
155 8
            $response->getBodyField(IProto::DATA),
156 8
            $response->getBodyField(IProto::METADATA)
157
        );
158
    }
159
160 8
    public function executeUpdate(string $sql, array $params = []) : int
161
    {
162 8
        $request = new Execute($sql, $params);
163
164 8
        return $this->handler->handle($request)->getBodyField(IProto::SQL_INFO)[0];
165
    }
166
167 58
    public function evaluate(string $expr, ...$args) : array
168
    {
169 58
        $request = new Evaluate($expr, $args);
170
171 58
        return $this->handler->handle($request)->getBodyField(IProto::DATA);
172
    }
173
174 4
    public function flushSpaces() : void
175
    {
176 4
        $this->spaces = [];
177 4
    }
178
179 116
    private function getSpaceIdByName(string $spaceName) : int
180
    {
181 116
        $schema = $this->getSpaceById(Space::VSPACE_ID);
182 116
        $data = $schema->select([$spaceName], Index::SPACE_NAME);
183
184 116
        if (empty($data)) {
185 4
            throw RequestFailed::unknownSpace($spaceName);
186
        }
187
188 112
        return $data[0][0];
189
    }
190
}
191