Passed
Push — master ( 9bc88c...903b03 )
by 世昌
02:14
created

DataAccess::createDefaultMiddleware()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\orm;
3
4
use ReflectionClass;
5
use ReflectionProperty;
6
use suda\orm\DataSource;
7
use suda\orm\TableAccess;
8
use suda\orm\struct\ReadStatement;
9
use suda\orm\middleware\Middleware;
10
use suda\orm\struct\QueryStatement;
11
use suda\orm\struct\WriteStatement;
12
use suda\orm\middleware\NullMiddleware;
13
use suda\orm\struct\TableStructBuilder;
14
use suda\orm\struct\TableStructMiddleware;
15
use suda\orm\struct\TableClassStructBuilder;
16
use suda\orm\struct\TableStructAwareInterface;
17
use suda\orm\middleware\MiddlewareAwareInterface;
18
19
/**
20
 * 数据访问
21
 */
22
class DataAccess
23
{
24
25
    /**
26
     * 数据源
27
     *
28
     * @var TableAccess
29
     */
30
    protected $access;
31
32
    /**
33
     * 数据类型
34
     *
35
     * @var string
36
     */
37
    protected $type;
38
39
    /**
40
     * 创建对数据的操作
41
     *
42
     * @param string $object
43
     * @param \suda\orm\DataSource $source
44
     * @param Middleware|null $middleware
45
     */
46
    public function __construct(string $object, DataSource $source, ?Middleware $middleware = null)
47
    {
48
        $this->type = $object;
49
        $struct = $this->createStruct($object);
50
        $middleware = $middleware ?? $this->createMiddleware($object, $struct);
51
        $this->access = new TableAccess($struct, $source, $middleware);
52
    }
53
54
    /**
55
     * 读取数据
56
     *
57
     * @param array|string $fields
58
     * @return \suda\orm\struct\ReadStatement
59
     */
60
    public function read(...$fields): ReadStatement
61
    {
62
        return $this->access->read(...$fields)->wantType($this->type);
63
    }
64
    
65
    /**
66
     * 写数据
67
     *
68
     * @param array|object $object
69
     * @return \suda\orm\struct\WriteStatement
70
     */
71
    public function write($object): WriteStatement
72
    {
73
        if (\is_object($object)) {
74
            $object = $this->createDataFromObject($object);
75
        }
76
        return $this->access->write($object);
77
    }
78
79
    /**
80
     * 统计计数
81
     *
82
     * @param string|array|object $where
83
     * @param array $whereBinder
84
     * @return integer
85
     */
86
    public function count($where, array $whereBinder = []):int
87
    {
88
        if (\is_object($where)) {
89
            $where = $this->createDataFromObject($where);
90
        }
91
        $fields = $this->access->getStruct()->getFields()->all();
92
        $field = \array_shift($fields);
93
        $total = $this->access->read([$field->getName()])->where($where, $whereBinder);
94
        $data = $this->access->query('SELECT count(*) as `count` from ('.$total.') as total', $total->getBinder())->one();
95
        return intval($data['count']);
96
    }
97
98
    /**
99
     * 查询语句
100
     *
101
     * @param string $query
102
     * @param mixed ...$parameter
103
     * @return QueryStatement
104
     */
105
    public function query(string $query, ...$parameter):QueryStatement
106
    {
107
        return $this->access->query($query, ...$parameter);
108
    }
109
110
    /**
111
     * 获取最后一次插入的主键ID(用于自增值
112
     *
113
     * @param string $name
114
     * @return string 则获取失败,整数则获取成功
115
     */
116
    public function lastInsertId(string $name = null):string
117
    {
118
        return $this->access->lastInsertId($name);
119
    }
120
121
    /**
122
     * 事务系列,开启事务
123
     *
124
     * @return void
125
     */
126
    public function beginTransaction()
127
    {
128
        $this->access->beginTransaction();
129
    }
130
131
    /**
132
     * 事务系列,提交事务
133
     *
134
     * @return void
135
     */
136
    public function commit()
137
    {
138
        $this->access->commit();
139
    }
140
141
    /**
142
     * 事务系列,撤销事务
143
     *
144
     * @return void
145
     */
146
    public function rollBack()
147
    {
148
        $this->access->rollBack();
149
    }
150
151
    /**
152
     * 创建数据
153
     *
154
     * @param object $object
155
     * @return array
156
     */
157
    protected function createDataFromObject($object)
158
    {
159
        if (\method_exists($object, '__get')) {
160
            return $this->createDataViaMagicGet($object);
161
        }
162
        return $this->createDataViaReflection($object);
163
    }
164
165
    /**
166
     * 使用魔术方法获取值
167
     *
168
     * @param object $object
169
     * @return array
170
     */
171
    protected function createDataViaMagicGet($object)
172
    {
173
        $fields = $this->access->getStruct()->getFields();
174
        $data = [];
175
        $isset = \method_exists($object, '__isset');
176
        if ($isset) {
177
            foreach ($fields as $name => $value) {
178
                if ($object->__isset($name)) {
179
                    $dataField = $this->access->getMiddleware()->inputName($name);
180
                    $data[$dataField] = $object->__get($name);
181
                }
182
            }
183
        } else {
184
            foreach ($fields as $name => $value) {
185
                $dataField = $this->access->getMiddleware()->inputName($name);
186
                $data[$dataField] = $object->__get($name);
187
            }
188
        }
189
        return $data;
190
    }
191
192
    /**
193
     * 使用反射方法获取值
194
     *
195
     * @param object $object
196
     * @return array
197
     */
198
    protected function createDataViaReflection($object)
199
    {
200
        $reflection = new ReflectionClass($object);
201
        $data = [];
202
        foreach ($reflection->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE) as $property) {
203
            if (TableStructBuilder::isTableField($property)) {
204
                $property->setAccessible(true);
205
                $value = $property->getValue($object);
206
                if ($value !== null) {
207
                    $dataField = $this->access->getMiddleware()->inputName($property->getName());
208
                    $data[$dataField] = $value;
209
                }
210
            }
211
        }
212
        return $data;
213
    }
214
215
    /**
216
     * 创建表结构
217
     *
218
     * @param string $object
219
     * @return TableStruct
220
     */
221
    protected function createStruct(string $object)
222
    {
223
        if (is_subclass_of($object, TableStructAwareInterface::class)) {
224
            return $object::getTableStruct();
225
        }
226
        return (new TableClassStructBuilder($object))->createStruct();
227
    }
228
229
    /**
230
     * 创建中间件
231
     *
232
     * @param string $object
233
     * @param TableStruct $struct
234
     * @return Middleware
235
     */
236
    protected function createMiddleware(string $object, TableStruct $struct)
237
    {
238
        if (is_subclass_of($object, MiddlewareAwareInterface::class)) {
239
            return $object::getMiddleware($struct);
240
        }
241
        return $this->createDefaultMiddleware($object, $struct);
242
    }
243
244
    /**
245
     * 创建默认中间件
246
     *
247
     * @param string $object
248
     * @param TableStruct $struct
249
     * @return Middleware
250
     */
251
    protected function createDefaultMiddleware(string $object, TableStruct $struct)
252
    {
253
        $reflectObject = new ReflectionClass($object);
254
        $classDoc = $reflectObject->getDocComment()?:'';
255
        if (\preg_match('/@field-serialize\s+(\w+)/i', $classDoc, $matchs)) {
0 ignored issues
show
Bug introduced by
It seems like $classDoc can also be of type true; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

255
        if (\preg_match('/@field-serialize\s+(\w+)/i', /** @scrutinizer ignore-type */ $classDoc, $matchs)) {
Loading history...
256
            return new TableStructMiddleware($object, $struct);
257
        }
258
        return new NullMiddleware;
259
    }
260
261
    /**
262
     * 获取表结构
263
     *
264
     * @return \suda\orm\TableStruct
265
     */
266
    public function getStruct():TableStruct
267
    {
268
        return $this->access->getStruct();
269
    }
270
271
    /**
272
     * 获取表名
273
     *
274
     * @return string
275
     */
276
    public function getName():string
277
    {
278
        return $this->access->getName();
279
    }
280
}
281