QueryResult   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 76
c 0
b 0
f 0
dl 0
loc 226
rs 9.68
wmc 34

11 Methods

Rating   Name   Duplication   Size   Complexity  
A fetchResult() 0 16 6
A createResult() 0 14 5
A fetchOneProcessor() 0 17 4
A setValueWithReflection() 0 16 4
A fetchOneProcessorArray() 0 8 3
A setValueWithMagicSet() 0 6 2
A __construct() 0 4 1
A prepareWithKeyField() 0 7 2
A fetchAllProcessor() 0 8 2
A prepareWithKeyCallback() 0 7 2
A prepareWithKey() 0 11 3
1
<?php
2
3
namespace suda\database\statement;
4
5
use function method_exists;
6
use PDO;
7
use ReflectionClass;
8
use ReflectionException;
9
use suda\database\exception\FetchResultException;
10
use suda\database\exception\SQLException;
11
use suda\database\connection\Connection;
12
use suda\database\middleware\Middleware;
13
14
class QueryResult
15
{
16
    /**
17
     * 数据源
18
     *
19
     * @var Connection
20
     */
21
    protected $connection;
22
23
    /**
24
     * 中间件
25
     *
26
     * @var Middleware
27
     */
28
    protected $middleware;
29
30
    /**
31
     * 创建运行器
32
     *
33
     * @param Connection $connection
34
     * @param Middleware $middleware
35
     */
36
    public function __construct(Connection $connection, Middleware $middleware)
37
    {
38
        $this->connection = $connection;
39
        $this->middleware = $middleware;
40
    }
41
42
    /**
43
     * 获取运行结果
44
     *
45
     * @param Statement $statement
46
     * @return mixed
47
     * @throws SQLException
48
     */
49
    public function createResult(Statement $statement)
50
    {
51
        if ($statement->isWrite()) {
52
            if ($statement->getReturnType() === Statement::RET_ROWS) {
53
                return $statement->getStatement()->rowCount();
54
            }
55
            if ($statement->getReturnType() === Statement::RET_LAST_INSERT_ID) {
56
                return $this->connection->getPdo()->lastInsertId();
57
            }
58
            return $statement->isSuccess();
59
        } elseif ($statement->isFetch()) {
60
            return $this->fetchResult($statement);
61
        }
62
        return null;
63
    }
64
65
    /**
66
     * 取结果
67
     *
68
     * @param QueryStatement|ReadStatement|Statement $statement
69
     * @param string|null $class
70
     * @param array $ctor_args
71
     * @return mixed
72
     */
73
    protected function fetchResult(Statement $statement, ?string $class = null, array $ctor_args = [])
74
    {
75
        if ($class !== null) {
76
            $statement->setFetchType($class, $ctor_args);
77
        }
78
        if ($statement->isFetchOne()) {
79
            $data = $statement->getStatement()->fetch(PDO::FETCH_ASSOC) ?: null;
80
            if ($data !== null) {
81
                return $this->fetchOneProcessor($statement, $data);
82
            }
83
            return $data;
84
        } elseif ($statement->isFetchAll()) {
85
            $data = $statement->getStatement()->fetchAll(PDO::FETCH_ASSOC);
86
            return $this->fetchAllProcessor($statement, $data);
87
        }
88
        return null;
89
    }
90
91
    /**
92
     * 处理一行数据
93
     *
94
     * 由于PDO的构造函数在设置值之后才会被调用,所以需要一个创建对象的方法
95
     *
96
     * @param ReadStatement|QueryStatement $statement
97
     * @param array $data
98
     * @return mixed
99
     */
100
    protected function fetchOneProcessor($statement, array $data)
101
    {
102
        if ($statement->getFetchClass() !== null) {
103
            try {
104
                $reflectClass = new ReflectionClass($statement->getFetchClass());
105
            } catch (ReflectionException $e) {
106
                throw new FetchResultException('error create class: '. $e->getMessage(), $e->getCode(), $e);
107
            }
108
            $object = $reflectClass->newInstanceArgs($statement->getFetchClassArgs());
109
            if (method_exists($object, '__set')) {
110
                $this->setValueWithMagicSet($object, $data);
111
            } else {
112
                $this->setValueWithReflection($reflectClass, $object, $data);
113
            }
114
            return $object;
115
        }
116
        return $this->fetchOneProcessorArray($data);
117
    }
118
119
    /**
120
     * 通过反射方法设置值
121
     *
122
     * @param ReflectionClass $reflectClass
123
     * @param mixed $object
124
     * @param array $data
125
     * @return void
126
     */
127
    protected function setValueWithReflection(ReflectionClass $reflectClass, $object, array $data)
128
    {
129
        foreach ($data as $name => $value) {
130
            $value = $this->middleware->output($name, $value);
131
            $propertyName = $this->middleware->outputName($name);
132
            if ($reflectClass->hasProperty($propertyName)) {
133
                try {
134
                    $property = $reflectClass->getProperty($propertyName);
135
                } catch (ReflectionException $e) {
136
                    throw new FetchResultException('error create property: '. $e->getMessage(), $e->getCode(), $e);
137
                }
138
                $property->setAccessible(true);
139
                $property->setValue($object, $value);
140
            } else {
141
                // 属性不存在则尝试直接赋值
142
                $object->$propertyName = $value;
143
            }
144
        }
145
    }
146
147
    /**
148
     * 通过魔术方法设置值
149
     *
150
     * @param mixed $object
151
     * @param array $data
152
     * @return void
153
     */
154
    protected function setValueWithMagicSet($object, array $data)
155
    {
156
        foreach ($data as $name => $value) {
157
            $value = $this->middleware->output($name, $value);
158
            $propertyName = $this->middleware->outputName($name);
159
            $object->__set($propertyName, $value);
160
        }
161
    }
162
163
    /**
164
     * 处理多行数据
165
     *
166
     * @param ReadStatement|QueryStatement $statement
167
     * @param array $data
168
     * @return array
169
     */
170
    protected function fetchAllProcessor($statement, array $data): array
171
    {
172
        foreach ($data as $index => $row) {
173
            $row = $this->fetchOneProcessor($statement, $row);
174
            $row = $this->middleware->outputRow($row);
175
            $data[$index] = $row;
176
        }
177
        return $this->prepareWithKey($statement, $data);
178
    }
179
180
    /**
181
     * @param ReadStatement|QueryStatement $statement
182
     * @param array $data
183
     * @return array
184
     */
185
    protected function prepareWithKey($statement, array $data)
186
    {
187
        $withKey = $statement->getWithKey();
188
        if ($withKey !== null) {
189
            return $this->prepareWithKeyField($withKey, $data);
190
        }
191
        $withKeyCallback = $statement->getWithKeyCallback();
192
        if ($withKeyCallback !== null) {
193
            return $this->prepareWithKeyCallback($withKeyCallback, $data);
194
        }
195
        return $data;
196
    }
197
198
    /**
199
     * @param string $withKey
200
     * @param array $data
201
     * @return array
202
     */
203
    protected function prepareWithKeyField(string $withKey, array $data)
204
    {
205
        $target = [];
206
        foreach ($data as $key => $value) {
207
            $target[$value[$withKey]] = $value;
208
        }
209
        return $target;
210
    }
211
212
    /**
213
     * @param callable $withKey
214
     * @param array $data
215
     * @return array
216
     */
217
    protected function prepareWithKeyCallback($withKey, array $data)
218
    {
219
        $target = [];
220
        foreach ($data as $key => $value) {
221
            $target[$withKey($value)] = $value;
222
        }
223
        return $target;
224
    }
225
226
    /**
227
     * 处理一行数据
228
     *
229
     * @param array $data
230
     * @return array
231
     */
232
    protected function fetchOneProcessorArray($data)
233
    {
234
        if ($this->middleware !== null) {
235
            foreach ($data as $name => $value) {
236
                $data[$name] = $this->middleware->output($name, $value);
237
            }
238
        }
239
        return $data;
240
    }
241
}
242