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

QueryAccess::commit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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