Passed
Push — master ( cfb65e...9c8e10 )
by 世昌
03:13
created

Connection::prefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\orm\connection;
3
4
use PDO;
5
use PDOException;
6
use ReflectionException;
7
use function register_shutdown_function;
8
use suda\orm\statement\Statement;
9
use suda\orm\statement\QueryAccess;
10
use suda\orm\exception\SQLException;
11
use suda\orm\connection\observer\Observer;
12
use suda\orm\connection\observer\NullObserver;
13
14
/**
15
 * 数据表链接对象
16
 *
17
 */
18
abstract class Connection
19
{
20
    /**
21
     * @var string
22
     */
23
    protected $type = 'mysql';
24
25
    /**
26
     * Config
27
     *
28
     * @var array
29
     */
30
    protected $config;
31
32
    /**
33
     * @var int
34
     */
35
    protected $queryCount = 0;
36
37
    /**
38
     * @var PDO
39
     */
40
    protected $pdo;
41
42
    /**
43
     * @var int
44
     */
45
    protected $transaction = 0;
46
47
    /**
48
     * @var
49
     */
50
    protected $id;
51
52
    /**
53
     * @var int
54
     */
55
    protected static $connectionCount = 0;
56
57
    /**
58
     * 链接别名
59
     *
60
     * @var string
61
     */
62
    protected $name;
63
64
    /**
65
     * 性能观测
66
     *
67
     * @var Observer
68
     */
69
    protected $observer;
70
71
    /**
72
     * 创建连接
73
     *
74
     * @param array $config
75
     * @param string|null $name
76
     */
77
    public function __construct(array $config, string $name = null)
78
    {
79
        $this->config = $config;
80
        $this->name = $name ?? 'anonymous';
81
        $this->observer = new NullObserver;
82
        register_shutdown_function(function () {
83
            $this->onBeforeSystemShutdown();
84
        });
85
    }
86
87
    /**
88
     * @return mixed
89
     */
90
    abstract public function getDsn();
91
92
    /**
93
     * @return PDO
94
     */
95
    abstract public function createPDO(): PDO;
96
97
    /**
98
     * 连接服务器
99
     *
100
     * @return bool
101
     * @throws SQLException
102
     */
103
    public function connect()
104
    {
105
        // 链接数据库
106
        if (null === $this->pdo && $this->getConfig('enable', true)) {
107
            try {
108
                $this->pdo = $this->createPDO();
109
                $this->id = static::$connectionCount;
110
                static::$connectionCount ++;
111
            } catch (PDOException $e) {
112
                throw new SQLException(sprintf(
113
                    "%s connect database error:%s",
114
                    $this->getName(),
115
                    $e->getMessage()
116
                ), $e->getCode(), $e);
117
            }
118
        }
119
        return $this->isConnected();
120
    }
121
122
    /**
123
     * 获取PDO
124
     * @ignore-dump
125
     * @return PDO
126
     * @throws SQLException
127
     */
128
    public function getPdo()
129
    {
130
        if (!$this->connect()) {
131
            throw new SQLException(sprintf(
132
                "%s data source is not connected",
133
                $this->getName()
134
            ), SQLException::ERR_NO_CONNECTION);
135
        }
136
        return $this->pdo;
137
    }
138
139
    /**
140
     * 获取配置
141
     *
142
     * @param string $name
143
     * @param mixed $default
144
     * @return mixed
145
     */
146
    public function getConfig(string $name, $default = null)
147
    {
148
        return $this->config[$name] ?? $default;
149
    }
150
151
    /**
152
     * 获取最后一次插入的主键ID(用于自增值
153
     *
154
     * @param string|null $name
155
     * @return string
156
     */
157
    public function lastInsertId(?string $name = null):string
158
    {
159
        if (null === $name) {
160
            return $this->pdo->lastInsertId();
161
        } else {
162
            return $this->pdo->lastInsertId($name);
163
        }
164
    }
165
166
    /**
167
     * 事务系列,开启事务
168
     *
169
     * @return void
170
     */
171
    public function begin()
172
    {
173
        $this->beginTransaction();
174
    }
175
176
    /**
177
     * 事务系列,开启事务
178
     *
179
     * @return void
180
     */
181
    public function beginTransaction()
182
    {
183
        $this->transaction ++;
184
        if ($this->transaction == 1) {
185
            $this->pdo->beginTransaction();
186
        }
187
    }
188
189
    /**
190
     * 判断是否连接
191
     *
192
     * @return boolean
193
     */
194
    public function isConnected():bool
195
    {
196
        return $this->pdo !== null;
197
    }
198
199
    /**
200
     * 事务系列,提交事务
201
     *
202
     * @return void
203
     */
204
    public function commit()
205
    {
206
        if ($this->transaction == 1) {
207
            $this->pdo->commit();
208
        }
209
        $this->transaction--;
210
    }
211
212
    /**
213
     * 事务系列,撤销事务
214
     *
215
     * @return void
216
     */
217
    public function rollBack()
218
    {
219
        if ($this->transaction == 1) {
220
            $this->transaction = 0;
221
            $this->pdo->rollBack();
222
        } else {
223
            $this->transaction--;
224
        }
225
    }
226
227
    /**
228
     * 事务关闭检测
229
     *
230
     * @return void
231
     * @throws SQLException
232
     */
233
    protected function onBeforeSystemShutdown()
234
    {
235
        if ($this->pdo && ($this->transaction > 0 || $this->pdo->inTransaction())) {
236
            throw new SQLException(sprintf(
237
                "SQL transaction is open (%d) in connection %s",
238
                $this->transaction,
239
                $this->__toString()
240
            ), SQLException::ERR_TRANSACTION);
241
        }
242
    }
243
244
    /**
245
     * 查询SQL
246
     *
247
     * @param Statement $statement
248
     * @return mixed
249
     * @throws SQLException
250
     * @throws ReflectionException
251
     */
252
    public function query(Statement $statement)
253
    {
254
        return (new QueryAccess($this))->run($statement);
0 ignored issues
show
Bug introduced by
$this of type suda\orm\connection\Connection is incompatible with the type suda\orm\DataSource expected by parameter $source of suda\orm\statement\QueryAccess::__construct(). ( Ignorable by Annotation )

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

254
        return (new QueryAccess(/** @scrutinizer ignore-type */ $this))->run($statement);
Loading history...
255
    }
256
257
    /**
258
     * 转义字符
259
     *
260
     * @param $string
261
     * @return string
262
     * @throws SQLException
263
     */
264
    public function quote($string)
265
    {
266
        return $this->getPdo()->quote($string);
267
    }
268
269
    /**
270
     * 转义字符
271
     *
272
     * @param array $array
273
     * @return string
274
     * @throws SQLException
275
     */
276
    public function arrayQuote(array $array)
277
    {
278
        $temp = array();
279
        foreach ($array as $value) {
280
            $temp[] = is_int($value) ? $value : $this->quote($value);
281
        }
282
        return implode(',', $temp);
283
    }
284
285
    /**
286
     * 统计查询数量
287
     *
288
     * @return void
289
     */
290
    public function countQuery()
291
    {
292
        $this->queryCount++;
293
    }
294
295
    /**
296
     * @return string
297
     */
298
    public function __toString()
299
    {
300
        return $this->getName();
301
    }
302
303
    /**
304
     * @param string $name
305
     * @return mixed
306
     */
307
    abstract public function switchDatabase(string $name);
308
309
    /**
310
     * @param string $name
311
     * @return mixed
312
     */
313
    abstract public function rawTableName(string $name);
314
315
    /**
316
     * Get 链接别名
317
     *
318
     * @return  string
319
     */
320
    public function getName()
321
    {
322
        return 'DataConnection['.$this->name.'][at '.$this->getDsn().']';
323
    }
324
325
    /**
326
     * Get 性能观测
327
     *
328
     * @return  Observer
329
     */
330
    public function getObserver():Observer
331
    {
332
        return $this->observer;
333
    }
334
335
    /**
336
     * Set 性能观测
337
     *
338
     * @param  Observer  $observer  性能观测
339
     *
340
     * @return  self
341
     */
342
    public function setObserver(Observer $observer)
343
    {
344
        $this->observer = $observer;
345
346
        return $this;
347
    }
348
349
350
    /**
351
     * @return string
352
     */
353
    public function getType(): string
354
    {
355
        return $this->type;
356
    }
357
358
    /**
359
     * @param string $type
360
     */
361
    public function setType(string $type): void
362
    {
363
        $this->type = $type;
364
    }
365
366
367
    /**
368
     * 自动填充前缀
369
     *
370
     * @param string $query
371
     * @return string
372
     */
373
    public function prefix( string $query):string
374
    {
375
        // _:table 前缀控制
376
        $prefix = $this->getConfig('prefix', '');
377
        return preg_replace('/_:(\w+)/', $prefix.'$1', $query);
378
    }
379
}
380