Passed
Push — dev ( ce443c...de3a90 )
by 世昌
02:35
created

QueryAccess   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 45
c 0
b 0
f 0
dl 0
loc 199
rs 10
wmc 22

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getMiddleware() 0 3 1
A runStatement() 0 14 4
A bindPDOStatementValues() 0 8 3
A rollBack() 0 3 1
A __construct() 0 4 2
A lastInsertId() 0 3 1
A run() 0 5 2
A createResult() 0 3 1
A commit() 0 3 1
A beginTransaction() 0 3 1
A setMiddleware() 0 4 1
A createPDOStatement() 0 16 3
A raw() 0 2 1
1
<?php
2
namespace suda\database\statement;
3
4
use PDO;
5
use PDOStatement;
6
use suda\database\Binder;
7
use suda\database\DataSource;
8
use suda\database\connection\Connection;
9
use suda\database\middleware\Middleware;
10
use suda\database\exception\SQLException;
11
use suda\database\middleware\NullMiddleware;
12
13
class QueryAccess
14
{
15
    /**
16
     * 数据源
17
     *
18
     * @var DataSource
19
     */
20
    protected $source;
21
22
    /**
23
     * 中间件
24
     *
25
     * @var Middleware
26
     */
27
    protected $middleware;
28
29
    /**
30
     * 创建运行器
31
     *
32
     * @param DataSource $source
33
     * @param Middleware $middleware
34
     */
35
    public function __construct(DataSource $source, Middleware $middleware = null)
36
    {
37
        $this->source = $source;
38
        $this->middleware = $middleware ?: new NullMiddleware;
39
    }
40
41
42
    /**
43
     * 获取最后一次插入的主键ID(用于自增值
44
     *
45
     * @param string $name
46
     * @return string 则获取失败,整数则获取成功
47
     */
48
    public function lastInsertId(string $name = null):string
49
    {
50
        return $this->source->write()->lastInsertId($name);
51
    }
52
53
    /**
54
     * 事务系列,开启事务
55
     *
56
     * @return void
57
     */
58
    public function beginTransaction()
59
    {
60
        $this->source->write()->beginTransaction();
61
    }
62
63
    /**
64
     * 事务系列,提交事务
65
     *
66
     * @return void
67
     */
68
    public function commit()
69
    {
70
        $this->source->write()->commit();
71
    }
72
73
    /**
74
     * 事务系列,撤销事务
75
     *
76
     * @return void
77
     */
78
    public function rollBack()
79
    {
80
        $this->source->write()->rollBack();
81
    }
82
83
    /**
84
     * 运行SQL语句
85
     *
86
     * @param Statement $statement
87
     * @return mixed
88
     * @throws SQLException
89
     */
90
    public function run(Statement $statement)
91
    {
92
        $connection = $statement->isRead() ? $this->source->read() : $this->source->write();
93
        $this->runStatement($connection, $statement);
94
        return $this->createResult($connection, $statement);
95
    }
96
97
98
    /**
99
     * 获取运行结果
100
     *
101
     * @param $connection
102
     * @param Statement $statement
103
     * @return mixed
104
     * @throws SQLException
105
     */
106
    protected function createResult(Connection $connection, Statement $statement)
107
    {
108
        return (new QueryResult($connection, $this->middleware))->createResult($statement);
109
    }
110
111
    /**
112
     * 设置中间件
113
     *
114
     * @param Middleware $middleware
115
     * @return $this
116
     */
117
    public function setMiddleware(Middleware $middleware)
118
    {
119
        $this->middleware = $middleware;
120
        return $this;
121
    }
122
123
    /**
124
     * 创建SQL语句
125
     *
126
     * @param Connection $connection
127
     * @param Statement $statement
128
     * @return PDOStatement
129
     * @throws SQLException
130
     */
131
    protected function createPDOStatement(Connection $connection, Statement $statement): PDOStatement
132
    {
133
        $statement->prepare();
134
        $queryObj = $statement->getQuery();
135
        $query = $connection->prefix($queryObj->getQuery());
136
        if ($statement->isScroll()) {
137
            $stmt = $connection->getPdo()->prepare($query, [
138
                PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL
139
            ]);
140
        } else {
141
            $stmt = $connection->getPdo()->prepare($query);
142
        }
143
        if ($stmt instanceof PDOStatement) {
144
            return $stmt;
145
        }
146
        throw new SQLException(sprintf('prepare error: %s', $statement->getString()), SQLException::ERR_PREPARE);
147
    }
148
149
    /**
150
     * 绑定值
151
     *
152
     * @param PDOStatement $stmt
153
     * @param Statement $statement
154
     * @return void
155
     */
156
    protected function bindPDOStatementValues(PDOStatement $stmt, Statement $statement)
157
    {
158
        foreach ($statement->getQuery()->getBinder() as $binder) {
159
            if ($binder->getKey() !== null) {
160
                $value = $this->middleware->input($binder->getKey(), $binder->getValue());
161
                $stmt->bindValue($binder->getName(), $value, Binder::typeOf($value));
162
            } else {
163
                $stmt->bindValue($binder->getName(), $binder->getValue(), Binder::typeOf($binder->getValue()));
164
            }
165
        }
166
    }
167
168
    /**
169
     * 运行语句
170
     *
171
     * @param Connection $connection
172
     * @param Statement $statement
173
     * @return void
174
     * @throws SQLException
175
     */
176
    protected function runStatement(Connection $connection, Statement $statement)
177
    {
178
        if ($statement->isScroll() && $statement->getStatement() !== null) {
179
            // noop
180
        } else {
181
            $stmt = $this->createPDOStatement($connection, $statement);
182
            $this->bindPDOStatementValues($stmt, $statement);
183
            $statement->setStatement($stmt);
184
            $start = microtime(true);
185
            $status = $stmt->execute();
186
            $statement->setSuccess($status);
187
            $connection->getObserver()->observe($this, $connection, $statement, microtime(true) - $start, $status);
188
            if ($status === false) {
189
                throw new SQLException(implode(':', $stmt->errorInfo()), intval($stmt->errorCode()));
190
            }
191
        }
192
    }
193
194
    /**
195
     * Get 中间件
196
     *
197
     * @return  Middleware
198
     */
199
    public function getMiddleware():Middleware
200
    {
201
        return $this->middleware;
202
    }
203
204
    /**
205
     * 原始SQL
206
     * @param string $query
207
     * @param array $parameter
208
     * @return Query
209
     */
210
    public function raw(string $query, array $parameter = []) {
211
        return new Query($query, $parameter);
212
    }
213
}
214