Passed
Push — master ( 566a3a...fbef46 )
by 世昌
02:19
created

DataAccess::lastInsertId()   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 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\database;
3
4
use function array_shift;
5
use function is_object;
6
use function method_exists;
7
use function preg_match;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionProperty;
11
use suda\database\statement\Statement;
12
use suda\database\struct\ReadStatement;
13
use suda\database\middleware\Middleware;
14
use suda\database\struct\QueryStatement;
15
use suda\database\struct\TableStruct;
16
use suda\database\struct\WriteStatement;
17
use suda\database\middleware\NullMiddleware;
18
use suda\database\struct\TableStructBuilder;
19
use suda\database\struct\TableStructMiddleware;
20
use suda\database\struct\TableClassStructBuilder;
21
use suda\database\struct\TableStructAwareInterface;
22
use suda\database\middleware\MiddlewareAwareInterface;
23
24
/**
25
 * 数据访问
26
 */
27
class DataAccess
28
{
29
30
    /**
31
     * 数据源
32
     *
33
     * @var TableAccess
34
     */
35
    protected $access;
36
37
    /**
38
     * 数据类型
39
     *
40
     * @var string
41
     */
42
    protected $type;
43
44
    /**
45
     * 创建对数据的操作
46
     *
47
     * @param string $object
48
     * @param DataSource $source
49
     * @param Middleware|null $middleware
50
     * @throws ReflectionException
51
     */
52
    public function __construct(string $object, DataSource $source, ?Middleware $middleware = null)
53
    {
54
        $this->type = $object;
55
        $struct = $this->createStruct($object);
56
        $middleware = $middleware ?? $this->createMiddleware($object, $struct);
57
        $this->access = new TableAccess($struct, $source, $middleware);
58
    }
59
60
    /**
61
     * 读取数据
62
     *
63
     * @param array|string $fields
64
     * @return ReadStatement
65
     */
66
    public function read(...$fields): ReadStatement
67
    {
68
        return $this->access->read(...$fields)->wantType($this->type);
69
    }
70
71
    /**
72
     * 写数据
73
     *
74
     * @param array|object|string $object
75
     * @return WriteStatement
76
     * @throws ReflectionException
77
     * @throws exception\SQLException
78
     */
79
    public function write($object): WriteStatement
80
    {
81
        if (is_object($object)) {
82
            $object = $this->createDataFromObject($object);
83
        }
84
        return $this->access->write($object);
85
    }
86
87
    /**
88
     * 删
89
     *
90
     * @param string|array $where
91
     * @param array $whereParameter
92
     * @return WriteStatement
93
     * @throws exception\SQLException
94
     */
95
    public function delete($where = null, ...$whereParameter):WriteStatement
96
    {
97
        if ($where !== null) {
98
            return $this->access->delete($where, ...$whereParameter);
99
        }
100
        return $this->access->delete();
101
    }
102
103
    /**
104
     * 统计计数
105
     *
106
     * @param string|array|object $where
107
     * @param array $whereBinder
108
     * @return integer
109
     * @throws ReflectionException
110
     * @throws exception\SQLException
111
     */
112
    public function count($where, array $whereBinder = []):int
113
    {
114
        if (is_object($where)) {
115
            $where = $this->createDataFromObject($where);
116
        }
117
        $fields = $this->access->getStruct()->all();
118
        $field = array_shift($fields);
119
        $total = $this->access->read([$field->getName()])->where($where, $whereBinder);
120
        $data = $this->access->query(
121
            sprintf("SELECT count(*) as `count` from (%s) as total", $total),
122
            $total->getBinder()
123
        )->one();
124
        return intval($data['count']);
125
    }
126
127
    /**
128
     * 查询语句
129
     *
130
     * @param string $query
131
     * @param mixed ...$parameter
132
     * @return QueryStatement
133
     */
134
    public function query(string $query, ...$parameter):QueryStatement
135
    {
136
        return $this->access->query($query, ...$parameter);
137
    }
138
139
140
    /**
141
     * 运行SQL语句
142
     *
143
     * @param Statement $statement
144
     * @return mixed
145
     * @throws exception\SQLException
146
     * @throws ReflectionException
147
     */
148
    public function run(Statement $statement)
149
    {
150
        return $this->access->run($statement);
151
    }
152
    
153
    /**
154
     * 获取最后一次插入的主键ID(用于自增值
155
     *
156
     * @param string $name
157
     * @return string 则获取失败,整数则获取成功
158
     */
159
    public function lastInsertId(string $name = null):string
160
    {
161
        return $this->access->lastInsertId($name);
162
    }
163
164
    /**
165
     * 事务系列,开启事务
166
     *
167
     * @return void
168
     */
169
    public function beginTransaction()
170
    {
171
        $this->access->beginTransaction();
172
    }
173
174
    /**
175
     * 事务系列,提交事务
176
     *
177
     * @return void
178
     */
179
    public function commit()
180
    {
181
        $this->access->commit();
182
    }
183
184
    /**
185
     * 事务系列,撤销事务
186
     *
187
     * @return void
188
     */
189
    public function rollBack()
190
    {
191
        $this->access->rollBack();
192
    }
193
194
    /**
195
     * 创建数据
196
     *
197
     * @param object $object
198
     * @return array
199
     * @throws ReflectionException
200
     */
201
    protected function createDataFromObject($object)
202
    {
203
        if (method_exists($object, '__get')) {
204
            return $this->createDataViaMagicGet($object);
205
        }
206
        return $this->createDataViaReflection($object);
207
    }
208
209
    /**
210
     * 使用魔术方法获取值
211
     *
212
     * @param object $object
213
     * @return array
214
     */
215
    protected function createDataViaMagicGet($object)
216
    {
217
        $fields = $this->access->getStruct();
218
        $data = [];
219
        $isset = method_exists($object, '__isset');
220
        if ($isset) {
221
            foreach ($fields as $name => $value) {
222
                if ($object->__isset($name)) {
223
                    $dataField = $this->access->getMiddleware()->inputName($name);
224
                    $data[$dataField] = $object->__get($name);
225
                }
226
            }
227
        } else {
228
            foreach ($fields as $name => $value) {
229
                $dataField = $this->access->getMiddleware()->inputName($name);
230
                $data[$dataField] = $object->__get($name);
231
            }
232
        }
233
        return $data;
234
    }
235
236
    /**
237
     * 使用反射方法获取值
238
     *
239
     * @param object $object
240
     * @return array
241
     * @throws ReflectionException
242
     */
243
    protected function createDataViaReflection($object)
244
    {
245
        $reflection = new ReflectionClass($object);
246
        $data = [];
247
        foreach ($reflection->getProperties(
248
            ReflectionProperty::IS_PUBLIC
249
            | ReflectionProperty::IS_PROTECTED
250
            | ReflectionProperty::IS_PRIVATE
251
        ) as $property) {
252
            if (TableStructBuilder::isTableField($property)) {
253
                $property->setAccessible(true);
254
                $value = $property->getValue($object);
255
                if ($value !== null) {
256
                    $dataField = $this->access->getMiddleware()->inputName($property->getName());
257
                    $data[$dataField] = $value;
258
                }
259
            }
260
        }
261
        return $data;
262
    }
263
264
    /**
265
     * 创建表结构
266
     *
267
     * @param string $object
268
     * @return TableStruct
269
     * @throws ReflectionException
270
     */
271
    public static function createStruct(string $object)
272
    {
273
        if (is_subclass_of($object, TableStructAwareInterface::class)) {
274
            return forward_static_call([$object, 'getTableStruct']);
275
        }
276
        return (new TableClassStructBuilder($object))->createStruct();
277
    }
278
279
280
    /**
281
     * @param string $object
282
     * @return string
283
     */
284
    public static function createTableName(string $object)
285
    {
286
        $pos = strrpos($object, '\\');
287
        if ($pos !== false && $pos >= 0) {
288
            $object = substr($object, $pos + 1);
289
        }
290
        return TableStructBuilder::createName($object);
291
    }
292
293
    /**
294
     * 创建中间件
295
     *
296
     * @param string $object
297
     * @param TableStruct $struct
298
     * @return Middleware
299
     * @throws ReflectionException
300
     */
301
    public static function createMiddleware(string $object, TableStruct $struct)
302
    {
303
        if (is_subclass_of($object, MiddlewareAwareInterface::class)) {
304
            return forward_static_call([$object, 'getMiddleware']);
305
        }
306
        return static::createDefaultMiddleware($object, $struct);
307
    }
308
309
    /**
310
     * 创建默认中间件
311
     *
312
     * @param string $object
313
     * @param TableStruct $struct
314
     * @return Middleware
315
     * @throws ReflectionException
316
     */
317
    protected static function createDefaultMiddleware(string $object, TableStruct $struct)
318
    {
319
        $reflectObject = new ReflectionClass($object);
320
        $classDoc = is_string($reflectObject->getDocComment())?$reflectObject->getDocComment():'';
321
        if (preg_match('/@field-(serialize|json)\s+(\w+)/i', $classDoc, $matchs)) {
322
            return new TableStructMiddleware($object, $struct);
323
        }
324
        return new NullMiddleware;
325
    }
326
327
    /**
328
     * @return TableAccess
329
     */
330
    public function getAccess(): TableAccess
331
    {
332
        return $this->access;
333
    }
334
335
    /**
336
     * 获取表结构
337
     *
338
     * @return TableStruct
339
     */
340
    public function getStruct():TableStruct
341
    {
342
        return $this->access->getStruct();
343
    }
344
345
    /**
346
     * 获取表名
347
     *
348
     * @return string
349
     */
350
    public function getName():string
351
    {
352
        return $this->access->getName();
353
    }
354
}
355