Passed
Push — master ( 9155e7...72c61b )
by 世昌
02:37
created

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