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

QueryResult::createResult()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 5
nop 1
dl 0
loc 14
rs 9.6111
c 0
b 0
f 0
1
<?php
2
namespace suda\database\statement;
3
4
use function method_exists;
5
use PDO;
6
use ReflectionClass;
7
use ReflectionException;
8
use suda\database\exception\SQLException;
9
use suda\database\connection\Connection;
10
use suda\database\middleware\Middleware;
11
12
class QueryResult
13
{
14
    /**
15
     * 数据源
16
     *
17
     * @var Connection
18
     */
19
    protected $connection;
20
21
    /**
22
     * 中间件
23
     *
24
     * @var Middleware
25
     */
26
    protected $middleware;
27
28
    /**
29
     * 创建运行器
30
     *
31
     * @param Connection $connection
32
     * @param Middleware $middleware
33
     */
34
    public function __construct(Connection $connection, Middleware $middleware)
35
    {
36
        $this->connection = $connection;
37
        $this->middleware = $middleware;
38
    }
39
40
    /**
41
     * 获取运行结果
42
     *
43
     * @param Statement $statement
44
     * @return mixed
45
     * @throws SQLException
46
     * @throws ReflectionException
47
     */
48
    public function createResult(Statement $statement)
49
    {
50
        if ($statement->isWrite()) {
51
            if ($statement->getReturnType() === Statement::RET_ROWS) {
52
                return $statement->getStatement()->rowCount();
53
            }
54
            if ($statement->getReturnType() === Statement::RET_LAST_INSERT_ID) {
55
                return $this->connection->getPdo()->lastInsertId();
56
            }
57
            return $statement->isSuccess();
58
        } elseif ($statement->isFetch()) {
59
            return $this->fetchResult($statement);
60
        }
61
        return null;
62
    }
63
64
    /**
65
     * 取结果
66
     *
67
     * @param QueryStatement|ReadStatement|Statement $statement
68
     * @param string|null $class
69
     * @param array $ctor_args
70
     * @return mixed
71
     * @throws ReflectionException
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->fetchOneProccess($statement, $data);
82
            }
83
            return $data;
84
        } elseif ($statement->isFetchAll()) {
85
            $data = $statement->getStatement()->fetchAll(PDO::FETCH_ASSOC);
86
            return $this->fetchAllProccess($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
     * @throws ReflectionException
100
     */
101
    protected function fetchOneProccess($statement, array $data)
102
    {
103
        if ($statement->getFetchClass() !== null) {
104
            $reflectClass = new ReflectionClass($statement->getFetchClass());
105
            $object = $reflectClass->newInstanceArgs($statement->getFetchClassArgs());
106
            if (method_exists($object, '__set')) {
107
                $this->setValueWithMagicSet($object, $data);
108
            } else {
109
                $this->setValueWithReflection($reflectClass, $object, $data);
110
            }
111
            return $object;
112
        }
113
        return $this->fetchOneProccessArray($data);
114
    }
115
116
    /**
117
     * 通过反射方法设置值
118
     *
119
     * @param ReflectionClass $reflectClass
120
     * @param mixed $object
121
     * @param array $data
122
     * @return void
123
     * @throws ReflectionException
124
     */
125
    protected function setValueWithReflection(ReflectionClass $reflectClass, $object, array $data)
126
    {
127
        foreach ($data as $name => $value) {
128
            $value = $this->middleware->output($name, $value);
129
            $propertyName = $this->middleware->outputName($name);
130
            if ($reflectClass->hasProperty($propertyName)) {
131
                $property = $reflectClass->getProperty($propertyName);
132
                $property->setAccessible(true);
133
                $property->setValue($object, $value);
134
            } else {
135
                // 属性不存在则尝试直接赋值
136
                $object->$propertyName = $value;
137
            }
138
        }
139
    }
140
141
    /**
142
     * 通过魔术方法设置值
143
     *
144
     * @param mixed $object
145
     * @param array $data
146
     * @return void
147
     */
148
    protected function setValueWithMagicSet($object, array $data)
149
    {
150
        foreach ($data as $name => $value) {
151
            $value = $this->middleware->output($name, $value);
152
            $propertyName = $this->middleware->outputName($name); 
153
            $object->__set($propertyName, $value);
154
        }
155
    }
156
157
    /**
158
     * 处理多行数据
159
     *
160
     * @param ReadStatement|QueryStatement $statement
161
     * @param array $data
162
     * @return array
163
     * @throws ReflectionException
164
     */
165
    protected function fetchAllProccess($statement, array $data): array
166
    {
167
        foreach ($data as $index => $row) {
168
            $row = $this->fetchOneProccess($statement, $row);
169
            $row = $this->middleware->outputRow($row);
170
            $data[$index] = $row;
171
        }
172
        $withKey = $statement->getWithKey();
173
        if ($withKey !== null) {
174
            $target = [];
175
            foreach ($data as $key => $value) {
176
                $target[$value[$withKey]] = $value;
177
            }
178
            return $target;
179
        }
180
        return $data;
181
    }
182
    
183
    /**
184
     * 处理一行数据
185
     *
186
     * @param array $data
187
     * @return array
188
     */
189
    protected function fetchOneProccessArray($data)
190
    {
191
        if ($this->middleware !== null) {
192
            foreach ($data as $name => $value) {
193
                $data[$name] = $this->middleware->output($name, $value);
194
            }
195
        }
196
        return $data;
197
    }
198
}
199