Passed
Push — dev ( 785e91...c8721b )
by 世昌
02:13
created

Connection::__sleep()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
namespace suda\database\connection;
3
4
use PDO;
5
use PDOException;
6
use suda\database\DataSource;
7
use suda\database\statement\Statement;
8
use suda\database\statement\QueryAccess;
9
use suda\database\exception\SQLException;
10
use suda\database\connection\observer\Observer;
11
use suda\database\connection\observer\NullObserver;
12
13
/**
14
 * 数据表链接对象
15
 *
16
 */
17
abstract class Connection
18
{
19
    /**
20
     * @var string
21
     */
22
    protected $type = 'mysql';
23
24
    /**
25
     * Config
26
     *
27
     * @var array
28
     */
29
    protected $config;
30
31
    /**
32
     * @var int
33
     */
34
    protected $queryCount = 0;
35
36
    /**
37
     * @var PDO
38
     */
39
    protected $pdo;
40
41
    /**
42
     * @var int
43
     */
44
    protected $transaction = 0;
45
46
    /**
47
     * @var
48
     */
49
    protected $id;
50
51
    /**
52
     * @var int
53
     */
54
    protected static $connectionCount = 0;
55
56
    /**
57
     * 链接别名
58
     *
59
     * @var string
60
     */
61
    protected $name;
62
63
    /**
64
     * 性能观测
65
     *
66
     * @var Observer
67
     */
68
    protected $observer;
69
70
    /**
71
     * 创建连接
72
     *
73
     * @param array $config
74
     * @param string $name
75
     */
76
    public function __construct(array $config, string $name = null)
77
    {
78
        $this->config = $config;
79
        $this->name = $name ?? 'anonymous';
80
        $this->observer = new NullObserver;
81
        register_shutdown_function(function () {
82
            $this->onBeforeSystemShutdown();
83
        });
84
    }
85
86
    /**
87
     * @return mixed
88
     */
89
    abstract public function getDsn();
90
91
    /**
92
     * @return PDO
93
     */
94
    abstract public function createPDO(): PDO;
95
96
    /**
97
     * 连接服务器
98
     *
99
     * @return bool
100
     * @throws SQLException
101
     */
102
    public function connect()
103
    {
104
        // 链接数据库
105
        if (null === $this->pdo && $this->getConfig('enable', true)) {
106
            try {
107
                $time = microtime(true);
108
                $this->pdo = $this->createPDO();
109
                $this->observer->connectDatabase(microtime(true) - $time);
110
                $this->id = static::$connectionCount;
111
                static::$connectionCount ++;
112
            } catch (PDOException $e) {
113
                throw new SQLException(sprintf(
114
                    "%s connect database error:%s",
115
                    $this->getName(),
116
                    $e->getMessage()
117
                ), $e->getCode(), $e);
118
            }
119
        }
120
        return $this->isConnected();
121
    }
122
123
    /**
124
     * @return array
125
     */
126
    public function __sleep()
127
    {
128
        return ['type', 'config', 'observer'];
129
    }
130
131
    /**
132
     * 获取PDO
133
     * @ignore-dump
134
     * @return PDO
135
     * @throws SQLException
136
     */
137
    public function getPdo()
138
    {
139
        if (!$this->connect()) {
140
            throw new SQLException(sprintf(
141
                "%s data source is not connected",
142
                $this->getName()
143
            ), SQLException::ERR_NO_CONNECTION);
144
        }
145
        return $this->pdo;
146
    }
147
148
    /**
149
     * 获取配置
150
     *
151
     * @param string $name
152
     * @param mixed $default
153
     * @return mixed
154
     */
155
    public function getConfig(string $name, $default = null)
156
    {
157
        return $this->config[$name] ?? $default;
158
    }
159
160
    /**
161
     * 获取最后一次插入的主键ID(用于自增值
162
     *
163
     * @param string|null $name
164
     * @return string
165
     */
166
    public function lastInsertId(?string $name = null):string
167
    {
168
        if (null === $name) {
169
            return $this->pdo->lastInsertId();
170
        } else {
171
            return $this->pdo->lastInsertId($name);
172
        }
173
    }
174
175
    /**
176
     * 事务系列,开启事务
177
     *
178
     * @return void
179
     */
180
    public function begin()
181
    {
182
        $this->beginTransaction();
183
    }
184
185
    /**
186
     * 事务系列,开启事务
187
     *
188
     * @return void
189
     */
190
    public function beginTransaction()
191
    {
192
        $this->transaction ++;
193
        if ($this->transaction == 1) {
194
            $this->pdo->beginTransaction();
195
        }
196
    }
197
198
    /**
199
     * 判断是否连接
200
     *
201
     * @return boolean
202
     */
203
    public function isConnected():bool
204
    {
205
        return $this->pdo !== null;
206
    }
207
208
    /**
209
     * 事务系列,提交事务
210
     *
211
     * @return void
212
     */
213
    public function commit()
214
    {
215
        if ($this->transaction == 1) {
216
            $this->pdo->commit();
217
        }
218
        $this->transaction--;
219
    }
220
221
    /**
222
     * 事务系列,撤销事务
223
     *
224
     * @return void
225
     */
226
    public function rollBack()
227
    {
228
        if ($this->transaction == 1) {
229
            $this->transaction = 0;
230
            $this->pdo->rollBack();
231
        } else {
232
            $this->transaction--;
233
        }
234
    }
235
236
    /**
237
     * 事务关闭检测
238
     *
239
     * @return void
240
     * @throws SQLException
241
     */
242
    protected function onBeforeSystemShutdown()
243
    {
244
        if ($this->pdo && ($this->transaction > 0 || $this->pdo->inTransaction())) {
245
            throw new SQLException(sprintf(
246
                "SQL transaction is open (%d) in connection %s",
247
                $this->transaction,
248
                $this->__toString()
249
            ), SQLException::ERR_TRANSACTION);
250
        }
251
    }
252
253
    /**
254
     * 查询SQL
255
     *
256
     * @param Statement $statement
257
     * @return mixed
258
     * @throws SQLException
259
     */
260
    public function query(Statement $statement)
261
    {
262
        $source = new DataSource();
263
        $source->add($this);
264
        return (new QueryAccess($source))->run($statement);
265
    }
266
267
    /**
268
     * 转义字符
269
     *
270
     * @param $string
271
     * @return string
272
     * @throws SQLException
273
     */
274
    public function quote($string)
275
    {
276
        return $this->getPdo()->quote($string);
277
    }
278
279
    /**
280
     * 转义字符
281
     *
282
     * @param array $array
283
     * @return string
284
     * @throws SQLException
285
     */
286
    public function arrayQuote(array $array)
287
    {
288
        $temp = array();
289
        foreach ($array as $value) {
290
            $temp[] = is_int($value) ? $value : $this->quote($value);
291
        }
292
        return implode(',', $temp);
293
    }
294
295
    /**
296
     * 统计查询数量
297
     *
298
     * @return void
299
     */
300
    public function countQuery()
301
    {
302
        $this->queryCount++;
303
    }
304
305
    /**
306
     * @return string
307
     */
308
    public function __toString()
309
    {
310
        return $this->getName();
311
    }
312
313
    /**
314
     * @param string $name
315
     * @return mixed
316
     */
317
    abstract public function switchDatabase(string $name);
318
319
    /**
320
     * @param string $name
321
     * @return mixed
322
     */
323
    abstract public function rawTableName(string $name);
324
325
    /**
326
     * Get 链接别名
327
     *
328
     * @return  string
329
     */
330
    public function getName()
331
    {
332
        return 'DataConnection['.$this->name.'][at '.$this->getDsn().']';
333
    }
334
335
    /**
336
     * Get 性能观测
337
     *
338
     * @return  Observer
339
     */
340
    public function getObserver():Observer
341
    {
342
        return $this->observer;
343
    }
344
345
    /**
346
     * Set 性能观测
347
     *
348
     * @param  Observer  $observer  性能观测
349
     *
350
     * @return  self
351
     */
352
    public function setObserver(Observer $observer)
353
    {
354
        $this->observer = $observer;
355
356
        return $this;
357
    }
358
359
360
    /**
361
     * @return string
362
     */
363
    public function getType(): string
364
    {
365
        return $this->type;
366
    }
367
368
    /**
369
     * @param string $type
370
     */
371
    public function setType(string $type): void
372
    {
373
        $this->type = $type;
374
    }
375
376
377
    /**
378
     * 自动填充前缀
379
     *
380
     * @param string $query
381
     * @return string
382
     */
383
    public function prefix(string $query):string
384
    {
385
        // _:table 前缀控制
386
        $prefix = $this->getConfig('prefix', '');
387
        return preg_replace('/_:(\w+)/', $prefix.'$1', $query);
388
    }
389
}
390