Completed
Push — master ( 7daa74...24b612 )
by Ron
45:43 queued 44:25
created

Insert::formatExtraArgs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 7
rs 9.4285
cc 2
eloc 5
nc 2
nop 2
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) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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) {
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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