Completed
Pull Request — master (#37)
by Eugene
03:12
created

Client::ping()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 4
cp 0.75
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1.0156
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\Connection;
17
use Tarantool\Client\Exception\Exception;
18
use Tarantool\Client\Packer\Packer;
19
use Tarantool\Client\Request\AuthenticateRequest;
20
use Tarantool\Client\Request\CallRequest;
21
use Tarantool\Client\Request\EvaluateRequest;
22
use Tarantool\Client\Request\ExecuteRequest;
23
use Tarantool\Client\Request\PingRequest;
24
use Tarantool\Client\Request\Request;
25
use Tarantool\Client\Schema\Index;
26
use Tarantool\Client\Schema\Space;
27
28
final class Client
29
{
30
    private $connection;
31
    private $packer;
32
    private $salt;
33
    private $username;
34
    private $password;
35
    private $spaces = [];
36
37 129
    public function __construct(Connection $connection, Packer $packer)
38
    {
39 129
        $this->connection = $connection;
40 129
        $this->packer = $packer;
41 129
    }
42
43 2
    public function getConnection() : Connection
44
    {
45 2
        return $this->connection;
46
    }
47
48 2
    public function getPacker() : Packer
49
    {
50 2
        return $this->packer;
51
    }
52
53 123
    public function connect() : void
54
    {
55 123
        $this->salt = $this->connection->open();
56
57 102
        if ($this->username) {
58 2
            $this->authenticate($this->username, $this->password);
59
        }
60 102
    }
61
62 2
    public function disconnect() : void
63
    {
64 2
        $this->connection->close();
65 2
        $this->salt = null;
66 2
    }
67
68 6
    public function isDisconnected() : bool
69
    {
70 6
        return $this->connection->isClosed() || !$this->salt;
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->salt of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
71
    }
72
73 6
    public function authenticate(string $username, string $password = '') : void
74
    {
75 6
        if ($this->isDisconnected()) {
76 4
            $this->salt = $this->connection->open();
77
        }
78
79 6
        $request = new AuthenticateRequest($this->salt, $username, $password);
80 6
        $this->sendRequest($request);
81
82 3
        $this->username = $username;
83 3
        $this->password = $password;
84
85 3
        $this->flushSpaces();
86 3
    }
87
88 6
    public function ping() : void
89
    {
90 6
        $request = new PingRequest();
91
92 6
        $this->sendRequest($request);
93
    }
94
95 60
    public function getSpace(string $spaceName) : Space
96
    {
97 60
        if (isset($this->spaces[$spaceName])) {
98 3
            return $this->spaces[$spaceName];
99
        }
100
101 60
        $spaceId = $this->getSpaceIdByName($spaceName);
102
103 58
        return $this->spaces[$spaceName] = $this->spaces[$spaceId] = new Space($this, $spaceId);
104
    }
105
106 63
    public function getSpaceById(int $spaceId) : Space
107
    {
108 63
        if (isset($this->spaces[$spaceId])) {
109 2
            return $this->spaces[$spaceId];
110
        }
111
112 63
        return $this->spaces[$spaceId] = new Space($this, $spaceId);
113
    }
114
115 5
    public function call(string $funcName, ...$args) : array
116
    {
117 5
        $request = new CallRequest($funcName, $args);
118
119 5
        return $this->sendRequest($request)->getBodyField(IProto::DATA);
120
    }
121
122 4
    public function executeQuery(string $sql, array $params = []) : SqlQueryResult
123
    {
124 4
        $request = new ExecuteRequest($sql, $params);
125 4
        $response = $this->sendRequest($request);
126
127 4
        return new SqlQueryResult(
128 4
            $response->getBodyField(IProto::DATA),
129 4
            $response->getBodyField(IProto::METADATA)
130
        );
131
    }
132
133 4
    public function executeUpdate(string $sql, array $params = []) : int
134
    {
135 4
        $request = new ExecuteRequest($sql, $params);
136
137 4
        return $this->sendRequest($request)->getBodyField(IProto::SQL_INFO)[0];
138
    }
139
140 27
    public function evaluate(string $expr, array $args = []) : array
141
    {
142 27
        $request = new EvaluateRequest($expr, $args);
143
144 27
        return $this->sendRequest($request)->getBodyField(IProto::DATA);
145
    }
146
147 5
    public function flushSpaces() : void
148
    {
149 5
        $this->spaces = [];
150 5
    }
151
152 106
    public function sendRequest(Request $request) : Response
153
    {
154 106
        if ($this->connection->isClosed()) {
155 104
            $this->connect();
156
        }
157
158 104
        $data = $this->packer->pack($request);
159 104
        $data = $this->connection->send($data);
160
161 100
        $response = $this->packer->unpack($data);
162 100
        if (!$response->isError()) {
163 96
            return $response;
164
        }
165
166 20
        throw new Exception(
167 20
            $response->getBodyField(IProto::ERROR),
168 20
            $response->getHeaderField(IProto::CODE) & (Response::TYPE_ERROR - 1)
169
        );
170
    }
171
172 60
    private function getSpaceIdByName(string $spaceName) : int
173
    {
174 60
        $schema = $this->getSpaceById(Space::VSPACE);
175 60
        $data = $schema->select([$spaceName], Index::SPACE_NAME);
176
177 60
        if (empty($data)) {
178 3
            throw new Exception("Space '$spaceName' does not exist");
179
        }
180
181 58
        return $data[0][0];
182
    }
183
}
184