Passed
Push — master ( 8a2cc4...a6995c )
by 世昌
02:15
created

PrepareTrait::prepareWhere()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\database\statement;
3
4
use ArrayObject;
5
use suda\database\Binder;
6
use suda\database\exception\SQLException;
7
8
/**
9
 * Trait PrepareTrait
10
 * @package suda\database\statement
11
 */
12
trait PrepareTrait
13
{
14
15
    /**
16
     * 准备选择列
17
     *
18
     * @param string|array $reads
19
     * @param string $table
20
     * @return string
21
     */
22
    protected function prepareReadFields($reads, string $table = ''):string
23
    {
24
        if (is_string($reads)) {
25
            $fields = $reads;
26
        } else {
27
            $field = [];
28
            $prefix = strlen($table) ?"`{$table}`." :'';
29
            foreach ($reads as $want) {
30
                $field[] = $prefix."`$want`";
31
            }
32
            $fields = implode(',', $field);
33
        }
34
        return $fields;
35
    }
36
37
    /**
38
     * 准备条件列
39
     *
40
     * @param array $where
41
     * @return array
42
     * @throws SQLException
43
     */
44
    protected function prepareWhere(array $where)
45
    {
46
        $and = [];
47
        $binders = [];
48
        foreach ($where as $name => $value) {
49
            $query = $this->getQueryForArray($name, $value);
50
            $and[] = $query->getQuery();
51
            $binders  = array_merge($binders, $query->getBinder());
52
        }
53
        return [implode(' AND ', $and), $binders];
54
    }
55
56
    /**
57
     * @param string $name
58
     * @param $value
59
     * @return Query
60
     * @throws SQLException
61
     */
62
    private function getQueryForArray(string $name, $value)
63
    {
64
        if ($value instanceof ArrayObject) {
65
            return $this->prepareIn($name, $value);
66
        } elseif (is_array($value)) {
67
            list($op, $val) = $value;
68
            $op = trim($op);
69
            return $this->createQueryOperation($name, $op, $val);
70
        } else {
71
            return $this->createQueryOperation($name, '=', $value);
72
        }
73
    }
74
75
    /**
76
     * @param string $name
77
     * @param string $operation
78
     * @param string $indexName
79
     * @param mixed $value
80
     * @return Query
81
     */
82
    private function createQueryOperation(string $name, string $operation, $value, string $indexName = '')
83
    {
84
        if ($value instanceof Query) {
85
            return new Query("`{$name}` {$operation} ".$value, $value->getBinder());
86
        }
87
        if ($value instanceof Statement) {
88
            return new Query("`{$name}` {$operation} (".$value->getQuery().')', $value->getBinder());
89
        }
90
        if (strlen($indexName) === 0) {
91
            $indexName = Binder::index($name);
92
        }
93
        return new Query("`{$name}` {$operation} :{$indexName}", [new Binder($indexName, $value)]);
94
    }
95
96
    /**
97
     * @param string $where
98
     * @param string $name
99
     * @param $value
100
     * @return Query
101
     * @throws SQLException
102
     */
103
    private function getQueryForString(string $where, string $name, $value)
104
    {
105
        if (is_array($value) || $value instanceof ArrayObject) {
106
            list($inSQL, $binders) = $this->prepareInParameter($value, $name);
107
            $name = ltrim($name, ':');
108
            $where = str_replace(':'.$name, $inSQL, $where);
109
            return new Query($where, $binders);
110
        } elseif ($value instanceof  Binder) {
111
            return new Query($where, [$value]);
112
        } else {
113
            return new Query($where, [new Binder($name, $value)]);
114
        }
115
    }
116
117
    /**
118
     * @param string $where
119
     * @param array $whereBinder
120
     * @return array
121
     * @throws SQLException
122
     */
123
    protected function prepareWhereString(string $where, array $whereBinder)
124
    {
125
        $newWhereBinder = [];
126
        foreach ($whereBinder as $name => $value) {
127
            $query = $this->getQueryForString($where, $name, $value);
128
            $where = $query->getQuery();
129
            $newWhereBinder = array_merge($newWhereBinder, $query->getBinder());
130
        }
131
        return [$where, $newWhereBinder];
132
    }
133
134
135
    /**
136
     * 准备In
137
     *
138
     * @param string $name
139
     * @param ArrayObject|array|Query|Statement $values
140
     * @return Query
141
     * @throws SQLException
142
     */
143
    protected function prepareIn(string $name, $values)
144
    {
145
        if ($values instanceof Query || $values instanceof Statement) {
146
            return $this->createQueryOperation($name, 'in', $values);
147
        }
148
        list($inSQL, $binders) = $this->prepareInParameter($values, $name);
149
        $sql = '`'.$name.'` IN ('.$inSQL.')';
150
        return new Query($sql, $binders);
151
    }
152
153
    /**
154
     * @param ArrayObject|array $values
155
     * @param string $name
156
     * @return array
157
     * @throws SQLException
158
     */
159
    protected function prepareInParameter($values, string $name)
160
    {
161
        if (count($values) <= 0) {
162
            throw new SQLException('on field '.$name.' value can\'t be empty array');
163
        }
164
        $names = [];
165
        $binders = [];
166
        foreach ($values as $value) {
167
            $_name = Binder::index($name);
168
            $binders[] = new Binder($_name, $value);
169
            $names[] = ':'.$_name;
170
        }
171
        return [implode(',', $names), $binders];
172
    }
173
174
    /**
175
     * 准备更新
176
     *
177
     * @param array $data
178
     * @return array
179
     */
180
    protected function prepareUpdateSet(array $data)
181
    {
182
        $binders = [];
183
        $sets = [];
184
        foreach ($data as $name => $value) {
185
            $_name = Binder::index($name);
186
            $binders[] = new Binder($_name, $value, $name);
187
            $sets[] = "`{$name}`=:{$_name}";
188
        }
189
        return [implode(',', $sets), $binders];
190
    }
191
192
    /**
193
     * 编译 ? 字符
194
     *
195
     * @param string $sql
196
     * @param array $parameter
197
     * @return array
198
     */
199
    protected function prepareQueryMark(string $sql, array $parameter)
200
    {
201
        $binders = [];
202
        $query = preg_replace_callback('/\?/', function ($match) use (&$binders, $parameter) {
203
            $index = count($binders);
204
            if (array_key_exists($index, $parameter)) {
205
                $name = Binder::index($index);
206
                if (is_array($parameter[$index]) || $parameter[$index] instanceof ArrayObject) {
207
                    list($inSQL, $inBinders) = $this->prepareInParameter($parameter[$index], $index);
208
                    $binders = array_merge($binders, $inBinders);
209
                    return $inSQL;
210
                } else {
211
                    $binder = new Binder($name, $parameter[$index]);
212
                    $binders[] = $binder;
213
                    return ':'.$binder->getName();
214
                }
215
            }
216
            return $match[0];
217
        }, $sql);
218
        return [$query, $binders];
219
    }
220
221
    /**
222
     * 合并绑定工具
223
     *
224
     * @param Binder[] $binderArray
225
     * @param array $parameter
226
     * @return Binder[]
227
     */
228
    protected function mergeBinder(array $binderArray, array $parameter)
229
    {
230
        foreach ($parameter as $key => $value) {
231
            if (! ($value instanceof Binder)) {
232
                $value = new Binder($key, $value);
233
            }
234
            if (!in_array($value, $binderArray)) {
235
                $binderArray[] = $value;
236
            }
237
        }
238
        return $binderArray;
239
    }
240
}
241