1
|
|
|
<?php |
2
|
|
|
namespace Kir\MySQL\Builder; |
3
|
|
|
|
4
|
|
|
use Kir\MySQL\Tools\AliasReplacer; |
5
|
|
|
use UnexpectedValueException; |
6
|
|
|
|
7
|
|
|
class Insert extends InsertUpdateStatement { |
8
|
|
|
/** @var array */ |
9
|
|
|
private $fields = array(); |
10
|
|
|
/** @var array */ |
11
|
|
|
private $update = array(); |
12
|
|
|
/** @var string */ |
13
|
|
|
private $table = null; |
14
|
|
|
/** @var string */ |
15
|
|
|
private $keyField = null; |
16
|
|
|
/** @var bool */ |
17
|
|
|
private $ignore = false; |
18
|
|
|
/** @var Select */ |
19
|
|
|
private $from = null; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @param string $table |
23
|
|
|
* @return $this |
24
|
|
|
*/ |
25
|
|
|
public function into($table) { |
26
|
|
|
$this->table = $table; |
27
|
|
|
return $this; |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @param bool $value |
32
|
|
|
* @return $this |
33
|
|
|
*/ |
34
|
|
|
public function setIgnore($value = true) { |
35
|
|
|
$this->ignore = $value; |
36
|
|
|
return $this; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Legt den Primaerschluessel fest. |
41
|
|
|
* Wenn bei einem Insert der Primaerschluessel mitgegeben wird, dann wird dieser statt der LastInsertId zurueckgegeben |
42
|
|
|
* |
43
|
|
|
* @param string $field |
44
|
|
|
* @return $this |
45
|
|
|
*/ |
46
|
|
|
public function setKey($field) { |
47
|
|
|
$this->keyField = $field; |
48
|
|
|
return $this; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @param string $field |
53
|
|
|
* @param bool|int|float|string $value |
54
|
|
|
* @throws UnexpectedValueException |
55
|
|
|
* @return $this |
56
|
|
|
*/ |
57
|
|
|
public function add($field, $value) { |
58
|
|
|
$this->fields = $this->addTo($this->fields, $field, $value); |
59
|
|
|
return $this; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @param string $field |
64
|
|
|
* @param bool|int|float|string $value |
65
|
|
|
* @throws UnexpectedValueException |
66
|
|
|
* @return $this |
67
|
|
|
*/ |
68
|
|
|
public function update($field, $value) { |
69
|
|
|
$this->update = $this->addTo($this->update, $field, $value); |
70
|
|
|
return $this; |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @param string $field |
75
|
|
|
* @param bool|int|float|string $value |
76
|
|
|
* @throws UnexpectedValueException |
77
|
|
|
* @return $this |
78
|
|
|
*/ |
79
|
|
|
public function addOrUpdate($field, $value) { |
80
|
|
|
$this->add($field, $value); |
81
|
|
|
$this->update($field, $value); |
82
|
|
|
return $this; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @param string $str |
87
|
|
|
* @param string ...$params |
88
|
|
|
* @return $this |
89
|
|
|
*/ |
90
|
|
View Code Duplication |
public function addExpr($str) { |
|
|
|
|
91
|
|
|
if(count(func_get_args()) > 1) { |
92
|
|
|
$this->fields[] = func_get_args(); |
93
|
|
|
} else { |
94
|
|
|
$this->fields[] = $str; |
95
|
|
|
} |
96
|
|
|
return $this; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @param string $str |
101
|
|
|
* @param string ...$params |
102
|
|
|
* @return $this |
103
|
|
|
*/ |
104
|
|
View Code Duplication |
public function updateExpr($str) { |
|
|
|
|
105
|
|
|
if(count(func_get_args()) > 1) { |
106
|
|
|
$this->update[] = func_get_args(); |
107
|
|
|
} else { |
108
|
|
|
$this->update[] = $str; |
109
|
|
|
} |
110
|
|
|
return $this; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @param string $str |
115
|
|
|
* @return $this |
116
|
|
|
*/ |
117
|
|
|
public function addOrUpdateExpr($str) { |
118
|
|
|
if(count(func_get_args()) > 1) { |
119
|
|
|
$this->fields[] = func_get_args(); |
120
|
|
|
$this->update[] = func_get_args(); |
121
|
|
|
} else { |
122
|
|
|
$this->fields[] = $str; |
123
|
|
|
$this->update[] = $str; |
124
|
|
|
} |
125
|
|
|
return $this; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @param array $data |
130
|
|
|
* @param array $mask |
131
|
|
|
* @param array $excludeFields |
132
|
|
|
* @return $this |
133
|
|
|
*/ |
134
|
|
|
public function addAll(array $data, array $mask = null, array $excludeFields = null) { |
135
|
|
|
$this->addAllTo($data, $mask, $excludeFields, function ($field, $value) { |
136
|
|
|
$this->add($field, $value); |
137
|
|
|
}); |
138
|
|
|
return $this; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* @param array $data |
143
|
|
|
* @param array $mask |
144
|
|
|
* @param array $excludeFields |
145
|
|
|
* @return $this |
146
|
|
|
*/ |
147
|
|
|
public function updateAll(array $data, array $mask = null, array $excludeFields = null) { |
148
|
|
|
$this->addAllTo($data, $mask, $excludeFields, function ($field, $value) { |
149
|
|
|
if ($field !== $this->keyField) { |
150
|
|
|
$this->update($field, $value); |
151
|
|
|
} |
152
|
|
|
}); |
153
|
|
|
return $this; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @param array $data |
158
|
|
|
* @param array $mask |
159
|
|
|
* @param array $excludeFields |
160
|
|
|
* @return $this |
161
|
|
|
*/ |
162
|
|
|
public function addOrUpdateAll(array $data, array $mask = null, array $excludeFields = null) { |
163
|
|
|
$this->addAll($data, $mask, $excludeFields); |
164
|
|
|
$this->updateAll($data, $mask, $excludeFields); |
165
|
|
|
return $this; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param Select $select |
170
|
|
|
* @return $this |
171
|
|
|
*/ |
172
|
|
|
public function from(Select $select) { |
173
|
|
|
$this->from = $select; |
174
|
|
|
return $this; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* @throws Exception |
179
|
|
|
* @return string |
180
|
|
|
*/ |
181
|
|
|
public function __toString() { |
182
|
|
|
if ($this->table === null) { |
183
|
|
|
throw new Exception('Specify a table-name'); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
$tableName = (new AliasReplacer($this->db()->getAliasRegistry()))->replace($this->table); |
187
|
|
|
|
188
|
|
|
$queryArr = array(); |
189
|
|
|
$ignoreStr = $this->ignore ? ' IGNORE' : ''; |
190
|
|
|
$queryArr[] = "INSERT{$ignoreStr} INTO\n\t{$tableName}\n"; |
191
|
|
|
|
192
|
|
|
if($this->from !== null) { |
193
|
|
|
$fields = $this->from->getFields(); |
194
|
|
|
$queryArr[] = sprintf("\t(%s)\n", join(', ', array_keys($fields))); |
195
|
|
|
$queryArr[] = $this->from; |
196
|
|
|
} else { |
197
|
|
|
$fields = $this->fields; |
198
|
|
|
$insertData = $this->buildFieldList($fields); |
199
|
|
|
if (!count($insertData)) { |
200
|
|
|
throw new Exception('No field-data found'); |
201
|
|
|
} |
202
|
|
|
$queryArr[] = sprintf("SET\n%s\n", join(",\n", $insertData)); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
$updateData = $this->buildUpdate(); |
206
|
|
|
if($updateData) { |
207
|
|
|
$queryArr[] = "{$updateData}\n"; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
$query = join('', $queryArr); |
211
|
|
|
|
212
|
|
|
return $query; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @param array $fields |
217
|
|
|
* @param string $field |
218
|
|
|
* @param bool|int|float|string $value |
219
|
|
|
* @return array |
220
|
|
|
*/ |
221
|
|
|
private function addTo(array $fields, $field, $value) { |
222
|
|
|
if ($this->isFieldNameValid($field)) { |
223
|
|
|
throw new UnexpectedValueException('Field name is invalid'); |
224
|
|
|
} |
225
|
|
|
$sqlField = $field; |
226
|
|
|
$sqlValue = $this->db()->quote($value); |
227
|
|
|
$fields[$sqlField] = $sqlValue; |
228
|
|
|
return $fields; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* @param array $data |
233
|
|
|
* @param array $mask |
234
|
|
|
* @param array $excludeFields |
235
|
|
|
* @param callable $fn |
236
|
|
|
* @return $this |
237
|
|
|
*/ |
238
|
|
|
private function addAllTo(array $data, array $mask = null, array $excludeFields = null, $fn) { |
239
|
|
|
if($mask !== null) { |
240
|
|
|
$data = array_intersect_key($data, array_combine($mask, $mask)); |
241
|
|
|
} |
242
|
|
|
if($excludeFields !== null) { |
243
|
|
|
foreach($excludeFields as $excludeField) { |
244
|
|
|
if(array_key_exists($excludeField, $data)) { |
245
|
|
|
unset($data[$excludeField]); |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
$data = $this->clearValues($data); |
250
|
|
|
foreach ($data as $field => $value) { |
251
|
|
|
call_user_func($fn, $field, $value); |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @return string |
257
|
|
|
*/ |
258
|
|
|
private function buildUpdate() { |
259
|
|
|
$queryArr = array(); |
260
|
|
|
if(!empty($this->update)) { |
261
|
|
|
$queryArr[] = "ON DUPLICATE KEY UPDATE\n"; |
262
|
|
|
$updateArr = array(); |
263
|
|
|
if($this->keyField !== null) { |
264
|
|
|
$updateArr[] = "\t`{$this->keyField}` = LAST_INSERT_ID({$this->keyField})"; |
265
|
|
|
} |
266
|
|
|
$updateArr = $this->buildFieldList($this->update, $updateArr); |
267
|
|
|
|
268
|
|
|
$queryArr[] = join(",\n", $updateArr); |
269
|
|
|
} |
270
|
|
|
return join('', $queryArr); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* @param string $fieldName |
275
|
|
|
* @return bool |
276
|
|
|
*/ |
277
|
|
|
private function isFieldNameValid($fieldName) { |
278
|
|
|
return is_numeric($fieldName) || !is_scalar($fieldName); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* @param array $values |
283
|
|
|
* @return array |
284
|
|
|
* @throws Exception |
285
|
|
|
*/ |
286
|
|
|
private function clearValues(array $values) { |
287
|
|
|
if(!count($values)) { |
288
|
|
|
return []; |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
$tableName = (new AliasReplacer($this->db()->getAliasRegistry()))->replace($this->table); |
292
|
|
|
$fields = $this->db()->getTableFields($tableName); |
293
|
|
|
$result = array(); |
294
|
|
|
|
295
|
|
|
foreach ($values as $fieldName => $fieldValue) { |
296
|
|
|
if(in_array($fieldName, $fields)) { |
297
|
|
|
$result[$fieldName] = $fieldValue; |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
return $result; |
302
|
|
|
} |
303
|
|
|
} |
304
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.