MySQL::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 8
dl 0
loc 24
rs 9.9332
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * MySQL connector
4
 * User: moyo
5
 * Date: 20/10/2017
6
 * Time: 5:51 PM
7
 */
8
9
namespace Carno\Database\Connectors;
10
11
use function Carno\Coroutine\await;
12
use function Carno\Coroutine\ctx;
13
use Carno\Database\Chips\ErrorsClassify;
14
use Carno\Database\Chips\ParamsBind;
15
use Carno\Database\Contracts\Executable;
16
use Carno\Database\Contracts\Transaction;
17
use Carno\Database\Exception\ConnectingException;
18
use Carno\Database\Exception\TimeoutException;
19
use Carno\Database\Exception\TransactionException;
20
use Carno\Database\Exception\UplinkException;
21
use Carno\Database\Options\Timeouts;
22
use Carno\Database\Results\Created;
23
use Carno\Database\Results\Selected;
24
use Carno\Database\Results\Updated;
25
use Carno\Pool\Managed;
26
use Carno\Pool\Poolable;
27
use Carno\Promise\Promise;
28
use Carno\Promise\Promised;
29
use Carno\Tracing\Contracts\Vars\EXT;
30
use Carno\Tracing\Contracts\Vars\TAG;
31
use Carno\Tracing\Standard\Endpoint;
32
use Carno\Tracing\Utils\SpansCreator;
33
use Swoole\MySQL as SWMySQL;
0 ignored issues
show
Bug introduced by
The type Swoole\MySQL was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
35
class MySQL implements Poolable, Executable, Transaction
36
{
37
    use Managed, ParamsBind, ErrorsClassify, SpansCreator;
38
39
    /**
40
     * @var Timeouts
41
     */
42
    private $timeout = null;
43
44
    /**
45
     * @var string
46
     */
47
    private $named = null;
48
49
    /**
50
     * @var string
51
     */
52
    private $host = null;
53
54
    /**
55
     * @var int
56
     */
57
    private $port = null;
58
59
    /**
60
     * @var string
61
     */
62
    private $username = null;
63
64
    /**
65
     * @var string
66
     */
67
    private $password = null;
68
69
    /**
70
     * @var string
71
     */
72
    private $database = null;
73
74
    /**
75
     * @var string
76
     */
77
    private $charset = null;
78
79
    /**
80
     * @var SWMySQL
81
     */
82
    private $link = null;
83
84
    /**
85
     * MySQL constructor.
86
     * @param string $host
87
     * @param int $port
88
     * @param string $username
89
     * @param string $password
90
     * @param string $database
91
     * @param string $charset
92
     * @param Timeouts $timeout
93
     * @param string $named
94
     */
95
    public function __construct(
96
        string $host,
97
        int $port,
98
        string $username,
99
        string $password,
100
        string $database,
101
        string $charset = 'utf8mb4',
102
        Timeouts $timeout = null,
103
        string $named = 'mysql'
104
    ) {
105
        $this->host = $host;
106
        $this->port = $port;
107
108
        $this->username = $username;
109
        $this->password = $password;
110
111
        $this->database = $database;
112
        $this->charset = $charset;
113
114
        $this->named = $named;
115
        $this->timeout = $timeout ?? new Timeouts;
116
117
        ($this->link = new SWMySQL)->on('close', function () {
118
            $this->closed()->resolve();
119
        });
120
    }
121
122
    /**
123
     * @return array
124
     */
125
    private function options() : array
126
    {
127
        return [
128
            'host' => $this->host,
129
            'port' => $this->port,
130
            'user' => $this->username,
131
            'password' => $this->password,
132
            'database' => $this->database,
133
            'charset' => $this->charset,
134
            'timeout' => round($this->timeout->connect() / 1000, 3),
135
        ];
136
    }
137
138
    /**
139
     * @return Promised
140
     */
141
    public function connect() : Promised
142
    {
143
        return new Promise(function (Promised $promise) {
144
            $this->link->connect($this->options(), static function (SWMySQL $db, bool $success) use ($promise) {
145
                $success
146
                    ? $promise->resolve()
147
                    : $promise->throw(new ConnectingException($db->connect_error, $db->connect_errno))
148
                ;
149
            });
150
        });
151
    }
152
153
    /**
154
     * @return Promised
155
     */
156
    public function heartbeat() : Promised
157
    {
158
        return new Promise(function (Promised $promised) {
159
            $this->link->query('SELECT 1', function (SWMySQL $db, $result) use ($promised) {
160
                (is_array($result) && count($result) === 1)
161
                    ? $promised->resolve()
162
                    : $promised->reject()
163
                ;
164
            });
165
        });
166
    }
167
168
    /**
169
     * @return Promised
170
     */
171
    public function close() : Promised
172
    {
173
        $this->link->close();
174
        return $this->closed();
175
    }
176
177
    /**
178
     * @param string $sql
179
     * @param array $bind
180
     * @return Promised
181
     */
182
    public function execute(string $sql, array $bind = [])
183
    {
184
        $this->traced() && $this->newSpan($ctx = clone yield ctx(), 'sql.execute', [
0 ignored issues
show
Bug Best Practice introduced by
The expression yield ctx() returns the type Generator which is incompatible with the documented return type Carno\Promise\Promised.
Loading history...
185
            TAG::SPAN_KIND => TAG::SPAN_KIND_RPC_CLIENT,
186
            TAG::DATABASE_TYPE => 'mysql',
187
            TAG::DATABASE_INSTANCE => sprintf('%s:%d', $this->host, $this->port),
188
            TAG::DATABASE_USER => $this->username,
189
            TAG::DATABASE_STATEMENT => $sql,
190
            EXT::REMOTE_ENDPOINT => new Endpoint($this->named),
191
        ]);
192
193
        if ($bind) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $bind of type array 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...
194
            $sql = $this->binding($sql, $bind);
195
        }
196
197
        $executor = function ($fn) use ($sql) {
198
            if (false === $this->link->query($sql, $fn)) {
199
                throw new UplinkException('Unknown failure');
200
            }
201
        };
202
203
        $receiver = function (SWMySQL $db, $result) use ($sql) {
204
            if (is_bool($result)) {
205
                if ($result) {
206
                    if ($db->insert_id) {
207
                        return new Created($db->insert_id);
208
                    } else {
209
                        return new Updated($db->affected_rows);
210
                    }
211
                } else {
212
                    throw $this->executingFail($sql, $db->error, $db->errno);
213
                }
214
            } else {
215
                return new Selected($result);
216
            }
217
        };
218
219
        return $this->finishSpan(
220
            await(
221
                $executor,
222
                $receiver,
223
                $this->timeout->execute(),
224
                TimeoutException::class,
225
                sprintf('SQL [->] %s', $sql)
226
            ),
227
            $ctx ?? null
228
        );
229
    }
230
231
    /**
232
     * @param string $data
233
     * @return string
234
     */
235
    public function escape(string $data) : string
236
    {
237
        return is_numeric($data) ? $data : ($data ? $this->link->escape($data) : '');
238
    }
239
240
    /**
241
     * @return Promised
242
     */
243
    public function begin()
244
    {
245
        return $this->transCMD('begin');
246
    }
247
248
    /**
249
     * @return Promised
250
     */
251
    public function commit()
252
    {
253
        return $this->transCMD('commit');
254
    }
255
256
    /**
257
     * @return Promised
258
     */
259
    public function rollback()
260
    {
261
        return $this->transCMD('rollback');
262
    }
263
264
    /**
265
     * @param string $func
266
     * @return Promised
267
     */
268
    private function transCMD(string $func)
269
    {
270
        $this->traced() && $this->newSpan($ctx = clone yield ctx(), "trx.{$func}", [
0 ignored issues
show
Bug Best Practice introduced by
The expression yield ctx() returns the type Generator which is incompatible with the documented return type Carno\Promise\Promised.
Loading history...
271
            SPAN_KIND => SPAN_KIND_RPC_CLIENT,
272
            DATABASE_TYPE => 'mysql',
273
            DATABASE_INSTANCE => sprintf('%s:%d', $this->host, $this->port),
274
            DATABASE_USER => $this->username,
275
            DATABASE_STATEMENT => $func,
276
            EXT::REMOTE_ENDPOINT => new Endpoint($this->named),
277
        ]);
278
279
        $executor = function ($fn) use ($func) {
280
            if (false === $this->link->$func($fn)) {
281
                throw new UplinkException('Unknown failure');
282
            }
283
        };
284
285
        $receiver = static function (SWMySQL $db, bool $result) {
286
            if ($result) {
287
                return;
288
            } else {
289
                throw new TransactionException($db->error, $db->errno);
290
            }
291
        };
292
293
        return $this->finishSpan(
294
            await(
295
                $executor,
296
                $receiver,
297
                $this->timeout->execute(),
298
                TimeoutException::class,
299
                sprintf('TRANS [->] %s', $func)
300
            ),
301
            $ctx ?? null
302
        );
303
    }
304
}
305