Passed
Push — dev ( 8a2cc4...37ecbf )
by 世昌
02:42
created

PrepareTrait::createQueryOperation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 4
dl 0
loc 9
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
        $_name = Binder::index($name);
65
        if ($value instanceof ArrayObject) {
66
            return $this->prepareIn($name, $value);
67
        } elseif (is_array($value)) {
68
            list($op, $val) = $value;
69
            $op = trim($op);
70
            return $this->createQueryOperation($name, $op, $val, $_name);
71
        } else {
72
            return $this->createQueryOperation($name, '=', $value, $_name);
73
        }
74
    }
75
76
    /**
77
     * @param string $name
78
     * @param string $operation
79
     * @param string $indexName
80
     * @param mixed $value
81
     * @return Query
82
     */
83
    private function createQueryOperation(string $name, string $operation, $value, ?string $indexName = null)
84
    {
85
        if ($value instanceof Query) {
86
            return new Query("`{$name}` {$operation} ".$value, $value->getBinder());
87
        }
88
        if ($value instanceof Statement) {
89
            return new Query("`{$name}` {$operation} (".$value->getQuery().')', $value->getBinder());
90
        }
91
        return new Query("`{$name}` {$operation} :{$indexName}", [new Binder($indexName, $value)]);
0 ignored issues
show
Bug introduced by
It seems like $indexName can also be of type null; however, parameter $name of suda\database\Binder::__construct() 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

91
        return new Query("`{$name}` {$operation} :{$indexName}", [new Binder(/** @scrutinizer ignore-type */ $indexName, $value)]);
Loading history...
92
    }
93
94
    /**
95
     * @param string $where
96
     * @param string $name
97
     * @param $value
98
     * @return Query
99
     * @throws SQLException
100
     */
101
    private function getQueryForString(string $where, string $name, $value)
102
    {
103
        if (is_array($value) || $value instanceof ArrayObject) {
104
            list($inSQL, $binders) = $this->prepareInParameter($value, $name);
105
            $name = ltrim($name, ':');
106
            $where = str_replace(':'.$name, $inSQL, $where);
107
            return new Query($where, $binders);
108
        } elseif ($value instanceof  Binder) {
109
            return new Query($where, [$value]);
110
        } else {
111
            return new Query($where, [new Binder($name, $value)]);
112
        }
113
    }
114
115
    /**
116
     * @param string $where
117
     * @param array $whereBinder
118
     * @return array
119
     * @throws SQLException
120
     */
121
    protected function prepareWhereString(string $where, array $whereBinder)
122
    {
123
        $newWhereBinder = [];
124
        foreach ($whereBinder as $name => $value) {
125
            $query = $this->getQueryForString($where, $name, $value);
126
            $where = $query->getQuery();
127
            $newWhereBinder = array_merge($newWhereBinder, $query->getBinder());
128
        }
129
        return [$where, $newWhereBinder];
130
    }
131
132
133
    /**
134
     * 准备In
135
     *
136
     * @param string $name
137
     * @param ArrayObject|array|Query|Statement $values
138
     * @return Query
139
     * @throws SQLException
140
     */
141
    protected function prepareIn(string $name, $values)
142
    {
143
        if ($values instanceof Query || $values instanceof Statement) {
144
            return $this->createQueryOperation($name, 'in', $values);
145
        }
146
        list($inSQL, $binders) = $this->prepareInParameter($values, $name);
147
        $sql = '`'.$name.'` IN ('.$inSQL.')';
148
        return new Query($sql, $binders);
149
    }
150
151
    /**
152
     * @param ArrayObject|array $values
153
     * @param string $name
154
     * @return array
155
     * @throws SQLException
156
     */
157
    protected function prepareInParameter($values, string $name)
158
    {
159
        if (count($values) <= 0) {
160
            throw new SQLException('on field '.$name.' value can\'t be empty array');
161
        }
162
        $names = [];
163
        $binders = [];
164
        foreach ($values as $value) {
165
            $_name = Binder::index($name);
166
            $binders[] = new Binder($_name, $value);
167
            $names[] = ':'.$_name;
168
        }
169
        return [implode(',', $names), $binders];
170
    }
171
172
    /**
173
     * 准备更新
174
     *
175
     * @param array $data
176
     * @return array
177
     */
178
    protected function prepareUpdateSet(array $data)
179
    {
180
        $binders = [];
181
        $sets = [];
182
        foreach ($data as $name => $value) {
183
            $_name = Binder::index($name);
184
            $binders[] = new Binder($_name, $value, $name);
185
            $sets[] = "`{$name}`=:{$_name}";
186
        }
187
        return [implode(',', $sets), $binders];
188
    }
189
190
    /**
191
     * 编译 ? 字符
192
     *
193
     * @param string $sql
194
     * @param array $parameter
195
     * @return array
196
     */
197
    protected function prepareQueryMark(string $sql, array $parameter)
198
    {
199
        $binders = [];
200
        $query = preg_replace_callback('/\?/', function ($match) use (&$binders, $parameter) {
201
            $index = count($binders);
202
            if (array_key_exists($index, $parameter)) {
203
                $name = Binder::index($index);
204
                if (is_array($parameter[$index]) || $parameter[$index] instanceof ArrayObject) {
205
                    list($inSQL, $inBinders) = $this->prepareInParameter($parameter[$index], $index);
206
                    $binders = array_merge($binders, $inBinders);
207
                    return $inSQL;
208
                } else {
209
                    $binder = new Binder($name, $parameter[$index]);
210
                    $binders[] = $binder;
211
                    return ':'.$binder->getName();
212
                }
213
            }
214
            return $match[0];
215
        }, $sql);
216
        return [$query, $binders];
217
    }
218
219
    /**
220
     * 合并绑定工具
221
     *
222
     * @param Binder[] $binderArray
223
     * @param array $parameter
224
     * @return Binder[]
225
     */
226
    protected function mergeBinder(array $binderArray, array $parameter)
227
    {
228
        foreach ($parameter as $key => $value) {
229
            if (! ($value instanceof Binder)) {
230
                $value = new Binder($key, $value);
231
            }
232
            if (!in_array($value, $binderArray)) {
233
                $binderArray[] = $value;
234
            }
235
        }
236
        return $binderArray;
237
    }
238
}
239