Passed
Push — dev ( 4d1626...1e4d6c )
by 世昌
02:25
created

WherePrepareTrait::replaceQuote()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 4
rs 10
c 1
b 0
f 0
1
<?php
2
3
4
namespace suda\database\statement;
5
6
7
use Countable;
8
use IteratorAggregate;
9
use suda\database\Binder;
10
use suda\database\exception\SQLException;
11
12
trait WherePrepareTrait
13
{
14
15
    /**
16
     * 处理?模板
17
     *
18
     * @param string $sql
19
     * @param array $parameter
20
     * @return array
21
     */
22
    public function prepareQueryMark(string $sql, array $parameter)
23
    {
24
        $binders = [];
25
        $query = preg_replace_callback('/\?/', function ($match) use (&$binders, $parameter) {
26
            $index = count($binders);
27
            if (array_key_exists($index, $parameter)) {
28
                $name = Binder::index($index);
29
                if (is_array($parameter[$index]) || $parameter[$index] instanceof IteratorAggregate) {
30
                    list($inSQL, $inBinders) = $this->prepareInParameter($parameter[$index], $index);
31
                    $binders = array_merge($binders, $inBinders);
32
                    return $inSQL;
33
                } else {
34
                    $binder = new Binder($name, $parameter[$index]);
35
                    $binders[] = $binder;
36
                    return ':' . $binder->getName();
37
                }
38
            }
39
            return $match[0];
40
        }, $sql);
41
        return [$query, $binders];
42
    }
43
44
    /**
45
     * 处理In语句
46
     * @param IteratorAggregate|array $values
47
     * @param string $name
48
     * @return array
49
     * @throws SQLException
50
     */
51
    public function prepareInParameter($values, string $name)
52
    {
53
        if ($this->count($values) <= 0) {
54
            throw new SQLException('on field ' . $name . ' value can\'t be empty array');
55
        }
56
        $names = [];
57
        $binders = [];
58
        foreach ($values as $value) {
59
            $_name = Binder::index($name);
60
            $binders[] = new Binder($_name, $value);
61
            $names[] = ':' . $_name;
62
        }
63
        return [implode(',', $names), $binders];
64
    }
65
66
    /**
67
     * @param array|Countable|IteratorAggregate $value
68
     * @return int
69
     */
70
    public function count($value)
71
    {
72
        if (is_array($value) || $value instanceof Countable) {
73
            return count($value);
74
        }
75
        return iterator_count($value);
76
    }
77
78
    /**
79
     * @param string $name
80
     * @param string $operation
81
     * @param mixed $value
82
     * @param string $indexName
83
     * @return Query
84
     * @throws SQLException
85
     */
86
    public function createQueryOperation(string $name, string $operation, $value, string $indexName = '')
87
    {
88
        if ($value instanceof Query) {
89
            return new Query("`{$name}` {$operation} " . $value, $value->getBinder());
90
        }
91
        if ($value instanceof Statement) {
92
            return new Query("`{$name}` {$operation} (" . $value->getQuery() . ')', $value->getBinder());
93
        }
94
        if ($value instanceof IteratorAggregate || is_array($value)) {
95
            return $this->prepareIn($name, $operation, $value);
96
        }
97
        if (strlen($indexName) === 0) {
98
            $indexName = Binder::index($name);
99
        }
100
        return new Query("`{$name}` {$operation} :{$indexName}", [new Binder($indexName, $value)]);
101
    }
102
103
    /**
104
     * @param string $name
105
     * @param $value
106
     * @return Query
107
     * @throws SQLException
108
     */
109
    public function getQueryForArray(string $name, $value)
110
    {
111
        if ($value instanceof IteratorAggregate) {
112
            return $this->prepareIn($name, 'IN', $value);
113
        } elseif (is_array($value)) {
114
            list($op, $val) = $value;
115
            $op = trim($op);
116
            return $this->createQueryOperation($name, $op, $val);
117
        } else {
118
            return $this->createQueryOperation($name, '=', $value);
119
        }
120
    }
121
122
    /**
123
     * @param string $where
124
     * @param array $whereBinder
125
     * @return array
126
     * @throws SQLException
127
     */
128
    public function prepareWhereString(string $where, array $whereBinder)
129
    {
130
        $newWhereBinder = [];
131
        foreach ($whereBinder as $name => $value) {
132
            $query = $this->getQueryForString($where, $name, $value);
133
            $where = $query->getQuery();
134
            $newWhereBinder = array_merge($newWhereBinder, $query->getBinder());
135
        }
136
        return [$where, $newWhereBinder];
137
    }
138
139
    /**
140
     * 准备条件列
141
     *
142
     * @param array $where
143
     * @return array
144
     * @throws SQLException
145
     */
146
    public function prepareWhere(array $where)
147
    {
148
        $and = [];
149
        $binders = [];
150
        foreach ($where as $name => $value) {
151
            $query = $this->getQueryForArray($name, $value);
152
            $and[] = $query->getQuery();
153
            $binders = array_merge($binders, $query->getBinder());
154
        }
155
        return [implode(' AND ', $and), $binders];
156
    }
157
158
    /**
159
     * @param string $where
160
     * @param string $name
161
     * @param $value
162
     * @return Query
163
     * @throws SQLException
164
     */
165
    public function getQueryForString(string $where, string $name, $value)
166
    {
167
        if (is_array($value) || $value instanceof IteratorAggregate) {
168
            list($inSQL, $binders) = $this->prepareInParameter($value, $name);
169
            $where = $this->replaceQuote($name, $inSQL, $where);
170
            return new Query($where, $binders);
171
        } elseif ($value instanceof Binder) {
172
            return new Query($where, [$value]);
173
        } else {
174
            return new Query($where, [new Binder($name, $value)]);
175
        }
176
    }
177
178
    /**
179
     * 准备In
180
     *
181
     * @param string $name
182
     * @param string $operation
183
     * @param IteratorAggregate|array|Query|Statement $values
184
     * @return Query
185
     * @throws SQLException
186
     */
187
    public function prepareIn(string $name, string $operation, $values)
188
    {
189
        if ($values instanceof Query || $values instanceof Statement) {
190
            return $this->createQueryOperation($name, 'in', $values);
191
        }
192
        list($inSQL, $binders) = $this->prepareInParameter($values, $name);
193
        $sql = '`' . $name . '` ' . strtoupper($operation) . ' (' . $inSQL . ')';
194
        return new Query($sql, $binders);
195
    }
196
197
    /**
198
     * 替换占位符
199
     *
200
     * @param string $name
201
     * @param string $replace
202
     * @param string $target
203
     * @return string
204
     */
205
    public function replaceQuote(string $name, string $replace, string $target)
206
    {
207
        $name = ltrim($name, ':');
208
        return preg_replace('/(?<!_):' . preg_quote($name) . '/', $replace, $target);
209
    }
210
}