DAOUpdatesTrait::deleteAllChildren()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3.1707

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 18
ccs 11
cts 15
cp 0.7332
rs 9.7998
cc 3
nc 4
nop 1
crap 3.1707
1
<?php
2
3
namespace Ubiquity\orm\traits;
4
5
use Ubiquity\controllers\Startup;
6
use Ubiquity\db\SqlUtils;
7
use Ubiquity\events\DAOEvents;
8
use Ubiquity\events\EventsManager;
9
use Ubiquity\log\Logger;
10
use Ubiquity\orm\OrmUtils;
11
use Ubiquity\orm\parser\ManyToManyParser;
12
use Ubiquity\orm\parser\Reflexion;
13
14
/**
15
 * Trait for DAO Updates (Create, Update, Delete)
16
 * Ubiquity\orm\traits$DAOUpdatesTrait
17
 * This class is part of Ubiquity
18
 *
19
 * @author jcheron <[email protected]>
20
 * @version 1.1.8
21
 * @property \Ubiquity\db\Database $db
22
 *
23
 */
24
trait DAOUpdatesTrait {
25
26
	/**
27
	 * Deletes the object $instance from the database
28
	 *
29
	 * @param object $instance instance à supprimer
30
	 */
31 13
	public static function remove($instance): ?int {
32 13
		self::deleteAllChildren($instance);
33 13
		$className = \get_class($instance);
34 13
		$tableName = OrmUtils::getTableName($className);
35 13
		$keyAndValues = OrmUtils::getKeyFieldsAndValues($instance);
36 13
		return self::removeByKey_($className, $tableName, $keyAndValues);
37
	}
38
39
	/**
40
	 *
41
	 * @param string $className
42
	 * @param string $tableName
43
	 * @param array $keyAndValues
44
	 * @return int the number of rows that were modified or deleted by the SQL statement you issued
45
	 */
46 13
	private static function removeByKey_($className, $tableName, $keyAndValues): ?int {
47 13
		$db = self::getDb($className);
48 13
		$sql = 'DELETE FROM ' . $db->quote . $tableName . $db->quote . ' WHERE ' . SqlUtils::getWhere($keyAndValues);
49 13
		Logger::info('DAOUpdates', $sql, 'delete');
50 13
		$statement = $db->prepareStatement($sql);
51
		try {
52 13
			if ($statement->execute($keyAndValues)) {
53 12
				return $statement->rowCount();
54
			}
55 1
		} catch (\PDOException $e) {
56 1
			Logger::warn('DAOUpdates', $e->getMessage(), 'delete');
57 1
			return null;
58
		}
59
		return 0;
60
	}
61
62
	/**
63
	 *
64
	 * @param \Ubiquity\db\Database $db
65
	 * @param string $className
66
	 * @param string $tableName
67
	 * @param string $where
68
	 * @param array $params
69
	 * @return boolean|int the number of rows that were modified or deleted by the SQL statement you issued
70
	 */
71
	private static function remove_($db, $tableName, $where, $params) {
72
		$sql = 'DELETE FROM ' . $tableName . ' ' . SqlUtils::checkWhere($where);
73
		Logger::info('DAOUpdates', $sql, 'delete');
74
		$statement = $db->prepareStatement($sql);
75
		try {
76
			if ($statement->execute($params)) {
77
				return $statement->rowCount();
78
			}
79
		} catch (\PDOException $e) {
80
			Logger::warn('DAOUpdates', $e->getMessage(), 'delete');
81
			return false;
82
		}
83
	}
84
85
	/**
86
	 * Deletes all instances from $modelName matching the condition $where.
87
	 *
88
	 * @param string $modelName
89
	 * @param string $where
90
	 * @param array $params
91
	 * @return int|boolean
92
	 */
93
	public static function deleteAll($modelName, $where, $params = []) {
94
		$db = self::getDb($modelName);
95
		$quote = $db->quote;
96
		$tableName = OrmUtils::getTableName($modelName);
97
		return self::remove_($db, $quote . $tableName . $quote, $where, $params);
98
	}
99
100
	protected static function deleteManyToManyChildren(object $instance, string $memberName) {
101
		$modelName = \get_class($instance);
102
		$db = self::getDb($modelName);
103
		$manyParser = new ManyToManyParser($db, $instance, $memberName);
104
		$manyParser->init();
105
		$pkv = OrmUtils::getFirstKeyValue($instance);
106
		$quote = $db->quote;
107
		$tableName = $manyParser->getJoinTable();
108
		$fkManyField = $manyParser->getMyFkField();
109
		return self::remove_($db, $quote . $tableName . $quote, "$fkManyField= ?", [$pkv]);
110
	}
111
112
	protected static function deleteOneToManyChildren(object $instance, string $memberName) {
113
		$getter = 'get' . \ucfirst($memberName);
114
		$instances = $instance->{$getter}();
115
		foreach ($instances as $o) {
116
			self::remove($o);
117
		}
118
	}
119
120
121 13
	public static function deleteAllChildren(object $instance) {
122 13
		$classname = \get_class($instance);
123 13
		$oneToManyMembers = OrmUtils::getRemoveCascadeFields($classname);
124 13
		$i = 0;
125 13
		$count = \count($oneToManyMembers);
126 13
		while ($i < $count) {
127
			self::deleteOneToManyChildren($instance, $oneToManyMembers[$i]);
128
			$i++;
129
		}
130
131 13
		$manyToManyMembers = OrmUtils::getRemoveCascadeFields($classname, '#manyToMany');
132 13
		$j = 0;
133 13
		$count = \count($manyToManyMembers);
134 13
		while ($j < $count) {
135
			self::deleteManyToManyChildren($instance, $manyToManyMembers[$j]);
136
			$j++;
137
		}
138 13
		return $i + $j;
139
	}
140
141
	/**
142
	 * Mass update for $modelName matching the condition $where, with an associative array of $values.
143
	 *
144
	 * @param string $modelName
145
	 * @param array $values
146
	 * @param string $condition
147
	 * @param array $params
148
	 */
149
	public static function updateAll(string $modelName, array $values, string $condition, array $params) {
150
		$db = self::getDb($modelName);
151
		$quote = $db->quote;
152
		$tableName = OrmUtils::getTableName($modelName);
153
154
		$allParams = \array_merge($values, $params);
155
156
		$sql = "UPDATE {$quote}{$tableName}{$quote} SET " . SqlUtils::getUpdateFieldsKeyAndParams($values) . SqlUtils::checkWhereParams($condition, $params);
157
		if (Logger::isActive()) {
158
			Logger::info("DAOUpdates", $sql, "updateAll");
159
			Logger::info("DAOUpdates", \json_encode($allParams), "All params");
160
		}
161
		$statement = $db->getUpdateStatement($sql);
162
		try {
163
			return $statement->execute($allParams);
164
		} catch (\Exception $e) {
165
			Logger::warn("DAOUpdates", $e->getMessage(), "updateAll");
166
		}
167
		return false;
168
	}
169
170
	/**
171
	 * Deletes all instances from $modelName corresponding to $ids
172
	 *
173
	 * @param string $modelName
174
	 * @param array|int $ids
175
	 * @return int|boolean
176
	 */
177
	public static function delete($modelName, $ids) {
178
		$tableName = OrmUtils::getTableName($modelName);
179
		$db = self::getDb($modelName);
180
		$pk = OrmUtils::getFirstKey($modelName);
181
		if (!\is_array($ids)) {
182
			$ids = [$ids];
183
		}
184
		$quote = $db->quote;
185
		$count = \count($ids);
186
		$r = $quote . $pk . $quote . "= ?";
187
		return self::remove_($db, $quote . $tableName . $quote, \str_repeat("$r OR", $count - 1) . $r, $ids);
188
	}
189
190
	public static function deleteById($modelName, $id) {
191
		$tableName = OrmUtils::getTableName($modelName);
192
		if (!\is_array($id)) {
193
			$id = [OrmUtils::getFirstKey($modelName) => $id];
194
		}
195
		return self::removeByKey_($modelName, $tableName, $id);
196
	}
197
198
	/**
199
	 * Inserts a new instance $instance into the database
200
	 *
201
	 * @param object $instance the instance to insert
202
	 * @param boolean $insertMany if true, save instances related to $instance by a ManyToMany association
203
	 */
204 20
	public static function insert($instance, $insertMany = false) {
205 20
		EventsManager::trigger('dao.before.insert', $instance);
206 20
		$className = \get_class($instance);
207 20
		$db = self::getDb($className);
208 20
		$quote = $db->quote;
209 20
		$tableName = OrmUtils::getTableName($className);
210 20
		$keyAndValues = Reflexion::getPropertiesAndValues($instance);
211 20
		$keyAndValues = \array_merge($keyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
212 20
		$pk = OrmUtils::getFirstKey($className);
213 20
		$pkVal = $keyAndValues [$pk] ?? null;
214 20
		if (($pkVal) == null) {
215 20
			unset ($keyAndValues [$pk]);
216
		}
217 20
		$sql = "INSERT INTO {$quote}{$tableName}{$quote} (" . SqlUtils::getInsertFields($keyAndValues) . ') VALUES(' . SqlUtils::getInsertFieldsValues($keyAndValues) . ')';
218 20
		if (Logger::isActive()) {
219 20
			Logger::info('DAOUpdates', $sql, 'insert');
220 20
			Logger::info('DAOUpdates', \json_encode($keyAndValues), 'Key and values');
221
		}
222
223 20
		$statement = $db->getUpdateStatement($sql);
224
		try {
225 20
			$result = $statement->execute($keyAndValues);
226 20
			if ($result) {
227 20
				if ($pkVal == null) {
228 20
					$lastId = $db->lastInserId("{$tableName}_{$pk}_seq");
229 20
					if ($lastId != 0) {
230 20
						$propKey = OrmUtils::getFirstPropKey($className);
231 20
						$propKey->setValue($instance, $lastId);
232 20
						$pkVal = $lastId;
233
					}
234
				}
235 20
				$instance->_rest = $keyAndValues;
236 20
				$instance->_rest [$pk] = $pkVal;
237
238 20
				if ($insertMany) {
239 1
					self::insertOrUpdateAllManyToMany($instance);
240
				}
241
			}
242 20
			EventsManager::trigger(DAOEvents::AFTER_INSERT, $instance, $result);
243 20
			return $result;
244 1
		} catch (\Exception $e) {
245 1
			Logger::warn('DAOUpdates', $e->getMessage(), 'insert');
246 1
			if (Startup::$config ['debug']) {
247 1
				throw $e;
248
			}
249
		}
250
		return false;
251
	}
252
253
	/**
254
	 * Updates manyToMany members
255
	 *
256
	 * @param object $instance
257
	 */
258 1
	public static function insertOrUpdateAllManyToMany($instance) {
259 1
		$members = OrmUtils::getAnnotationInfo(get_class($instance), '#manyToMany');
260 1
		if ($members !== false) {
261
			$members = \array_keys($members);
262
			foreach ($members as $member) {
263
				self::insertOrUpdateManyToMany($instance, $member);
264
			}
265
		}
266
	}
267
268
	/**
269
	 * Updates the $member member of $instance annotated by a ManyToMany
270
	 *
271
	 * @param Object $instance
272
	 * @param String $member
273
	 */
274
	public static function insertOrUpdateManyToMany($instance, $member) {
275
		$db = self::getDb(\get_class($instance));
276
		$parser = new ManyToManyParser ($db, $instance, $member);
277
		if ($parser->init()) {
278
			$quote = $db->quote;
279
			$myField = $parser->getMyFkField();
280
			$field = $parser->getFkField();
281
			$sql = "INSERT INTO {$quote}" . $parser->getJoinTable() . "{$quote}({$quote}" . $myField . "{$quote},{$quote}" . $field . "{$quote}) VALUES (:" . $myField . ",:" . $field . ");";
282
			$memberAccessor = 'get' . \ucfirst($member);
283
			$memberValues = $instance->$memberAccessor ();
284
			$myKey = $parser->getMyPk();
285
			$myAccessorId = 'get' . \ucfirst($myKey);
286
			$accessorId = 'get' . \ucfirst($parser->getPk());
287
			$id = $instance->$myAccessorId ();
288
			if (!\is_null($memberValues)) {
289
				$db->execute("DELETE FROM {$quote}" . $parser->getJoinTable() . "{$quote} WHERE {$quote}{$myField}{$quote}='{$id}'");
290
				$statement = $db->prepareStatement($sql);
291
				foreach ($memberValues as $targetInstance) {
292
					$foreignId = $targetInstance->$accessorId ();
293
					$foreignInstances = self::getAll($parser->getTargetEntity(), $quote . $parser->getPk() . $quote . "='{$foreignId}'");
294
					if (!OrmUtils::exists($targetInstance, $parser->getPk(), $foreignInstances)) {
295
						self::insert($targetInstance, false);
296
						$foreignId = $targetInstance->$accessorId ();
297
						Logger::info('DAOUpdates', "Insertion d'une instance de " . get_class($instance), 'InsertMany');
298
					}
299
					$db->bindValueFromStatement($statement, $myField, $id);
300
					$db->bindValueFromStatement($statement, $field, $foreignId);
301
					$statement->execute();
302
					Logger::info('DAOUpdates', "Insertion des valeurs dans la table association '" . $parser->getJoinTable() . "'", 'InsertMany');
303
				}
304
			}
305
		}
306
	}
307
308
	/**
309
	 * Updates an existing $instance in the database.
310
	 * Be careful not to modify the primary key
311
	 *
312
	 * @param object $instance instance to modify
313
	 * @param boolean $updateMany Adds or updates ManyToMany members
314
	 */
315 3
	public static function update($instance, $updateMany = false) {
316 3
		EventsManager::trigger('dao.before.update', $instance);
317 3
		$className = \get_class($instance);
318 3
		$db = self::getDb($className);
319 3
		$quote = $db->quote;
320 3
		$tableName = OrmUtils::getTableName($className);
321 3
		$ColumnskeyAndValues = \array_merge(Reflexion::getPropertiesAndValues($instance), OrmUtils::getManyToOneMembersAndValues($instance));
322 3
		$keyFieldsAndValues = $instance->_pkv ?? OrmUtils::getKeyFieldsAndValues($instance, '___');
323 3
		$allParameterValues = $ColumnskeyAndValues + $keyFieldsAndValues;
324 3
		$sql = "UPDATE {$quote}{$tableName}{$quote} SET " . SqlUtils::getUpdateFieldsKeyAndParams($ColumnskeyAndValues) . ' WHERE ' . SqlUtils::getWherePK($keyFieldsAndValues);
325 3
		if (Logger::isActive()) {
326 3
			Logger::info("DAOUpdates", $sql, "update");
327 3
			Logger::info("DAOUpdates", \json_encode($allParameterValues), "Key and values");
328
		}
329 3
		$statement = $db->getUpdateStatement($sql);
330
		try {
331 3
			$result = $statement->execute($allParameterValues);
332 3
			if ($updateMany && $result) {
333 1
				self::insertOrUpdateAllManyToMany($instance);
334
			}
335 3
			EventsManager::trigger(DAOEvents::AFTER_UPDATE, $instance, $result);
336 3
			$instance->_rest = \array_merge($instance->_rest, $ColumnskeyAndValues);
337 3
			return $result;
338
		} catch (\Exception $e) {
339
			Logger::warn("DAOUpdates", $e->getMessage(), "update");
340
		}
341
		return false;
342
	}
343
344
	/**
345
	 * Updates an array of $instances in the database.
346
	 * Be careful not to modify the primary key
347
	 *
348
	 * @param array $instances instances to modify
349
	 * @param boolean $updateMany Adds or updates ManyToMany members
350
	 * @return boolean
351
	 */
352
	public static function updateGroup($instances, $updateMany = false) {
353
		if (\count($instances) > 0) {
354
			$instance = \current($instances);
355
			$className = \get_class($instance);
356
			$db = self::getDb($className);
357
			$quote = $db->quote;
358
			$tableName = OrmUtils::getTableName($className);
359
			$ColumnskeyAndValues = \array_merge(Reflexion::getPropertiesAndValues($instance), OrmUtils::getManyToOneMembersAndValues($instance));
360
			$keyFieldsAndValues = OrmUtils::getKeyFieldsAndValues($instance);
361
			$sql = "UPDATE {$quote}{$tableName}{$quote} SET " . SqlUtils::getUpdateFieldsKeyAndParams($ColumnskeyAndValues) . ' WHERE ' . SqlUtils::getWhere($keyFieldsAndValues);
362
363
			$statement = $db->getUpdateStatement($sql);
364
			try {
365
				$db->beginTransaction();
366
				foreach ($instances as $instance) {
367
					EventsManager::trigger('dao.before.update', $instance);
368
					$ColumnskeyAndValues = \array_merge(Reflexion::getPropertiesAndValues($instance), OrmUtils::getManyToOneMembersAndValues($instance));
369
					$result = $statement->execute($ColumnskeyAndValues);
370
					if ($updateMany && $result) {
371
						self::insertOrUpdateAllManyToMany($instance);
372
					}
373
					EventsManager::trigger(DAOEvents::AFTER_UPDATE, $instance, $result);
374
					$instance->_rest = \array_merge($instance->_rest, $ColumnskeyAndValues);
375
					if (Logger::isActive()) {
376
						Logger::info("DAOUpdates", $sql, "update");
377
						Logger::info("DAOUpdates", json_encode($ColumnskeyAndValues), "Key and values");
378
					}
379
				}
380
				$db->commit();
381
				return true;
382
			} catch (\Exception $e) {
383
				Logger::warn("DAOUpdates", $e->getMessage(), "update");
384
				$db->rollBack();
385
			}
386
		}
387
		return false;
388
	}
389
390
	/**
391
	 *
392
	 * @param object $instance
393
	 * @param boolean $updateMany
394
	 * @return boolean|int
395
	 */
396
	public static function save($instance, $updateMany = false) {
397
		if (isset ($instance->_rest)) {
398
			return self::update($instance, $updateMany);
399
		}
400
		return self::insert($instance, $updateMany);
401
	}
402
}
403