Passed
Push — master ( ae6dff...0062d3 )
by Jean-Christophe
09:44
created

DAOUpdatesTrait::update()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 26
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5.0634

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 22
c 2
b 0
f 0
dl 0
loc 26
ccs 19
cts 22
cp 0.8636
rs 9.2568
cc 5
nc 16
nop 2
crap 5.0634
1
<?php
2
3
namespace Ubiquity\orm\traits;
4
5
use Ubiquity\db\SqlUtils;
6
use Ubiquity\events\DAOEvents;
7
use Ubiquity\events\EventsManager;
8
use Ubiquity\log\Logger;
9
use Ubiquity\orm\OrmUtils;
10
use Ubiquity\orm\parser\ManyToManyParser;
11
use Ubiquity\orm\parser\Reflexion;
12
use Ubiquity\controllers\Startup;
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.6
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
		$className = \get_class ( $instance );
33 13
		$tableName = OrmUtils::getTableName ( $className );
34 13
		$keyAndValues = OrmUtils::getKeyFieldsAndValues ( $instance );
35 13
		return self::removeByKey_ ( $className, $tableName, $keyAndValues );
36
	}
37
38
	/**
39
	 *
40
	 * @param string $className
41
	 * @param string $tableName
42
	 * @param array $keyAndValues
43
	 * @return int the number of rows that were modified or deleted by the SQL statement you issued
44
	 */
45 13
	private static function removeByKey_($className, $tableName, $keyAndValues): ?int {
46 13
		$db = self::getDb ( $className );
47 13
		$sql = 'DELETE FROM ' . $db->quote . $tableName . $db->quote . ' WHERE ' . SqlUtils::getWhere ( $keyAndValues );
48 13
		Logger::info ( 'DAOUpdates', $sql, 'delete' );
49 13
		$statement = $db->prepareStatement ( $sql );
50
		try {
51 13
			if ($statement->execute ( $keyAndValues )) {
52 12
				return $statement->rowCount ();
53
			}
54 1
		} catch ( \PDOException $e ) {
55 1
			Logger::warn ( 'DAOUpdates', $e->getMessage (), 'delete' );
56 1
			return null;
57
		}
58
		return 0;
59
	}
60
61
	/**
62
	 *
63
	 * @param \Ubiquity\db\Database $db
64
	 * @param string $className
65
	 * @param string $tableName
66
	 * @param string $where
67
	 * @param array $params
68
	 * @return boolean|int the number of rows that were modified or deleted by the SQL statement you issued
69
	 */
70
	private static function remove_($db, $tableName, $where, $params) {
71
		$sql = 'DELETE FROM ' . $tableName . ' ' . SqlUtils::checkWhere ( $where );
72
		Logger::info ( 'DAOUpdates', $sql, 'delete' );
73
		$statement = $db->prepareStatement ( $sql );
74
		try {
75
			if ($statement->execute ( $params )) {
76
				return $statement->rowCount ();
77
			}
78
		} catch ( \PDOException $e ) {
79
			Logger::warn ( 'DAOUpdates', $e->getMessage (), 'delete' );
80
			return false;
81
		}
82
	}
83
84
	/**
85
	 * Deletes all instances from $modelName matching the condition $where
86
	 *
87
	 * @param string $modelName
88
	 * @param string $where
89
	 * @param array $params
90
	 * @return int|boolean
91
	 */
92
	public static function deleteAll($modelName, $where, $params = [ ]) {
93
		$db = self::getDb ( $modelName );
94
		$quote = $db->quote;
95
		$tableName = OrmUtils::getTableName ( $modelName );
96
		return self::remove_ ( $db, $quote . $tableName . $quote, $where, $params );
97
	}
98
99
	/**
100
	 * Deletes all instances from $modelName corresponding to $ids
101
	 *
102
	 * @param string $modelName
103
	 * @param array|int $ids
104
	 * @return int|boolean
105
	 */
106
	public static function delete($modelName, $ids) {
107
		$tableName = OrmUtils::getTableName ( $modelName );
108
		$db = self::getDb ( $modelName );
109
		$pk = OrmUtils::getFirstKey ( $modelName );
110
		if (! \is_array ( $ids )) {
111
			$ids = [ $ids ];
112
		}
113
		$quote = $db->quote;
114
		$count = \count ( $ids );
115
		$r = $quote . $pk . $quote . "= ?";
116
		return self::remove_ ( $db, $quote . $tableName . $quote, \str_repeat ( "$r OR", $count - 1 ) . $r, $ids );
117
	}
118
119
	/**
120
	 * Inserts a new instance $instance into the database
121
	 *
122
	 * @param object $instance the instance to insert
123
	 * @param boolean $insertMany if true, save instances related to $instance by a ManyToMany association
124
	 */
125 20
	public static function insert($instance, $insertMany = false) {
126 20
		EventsManager::trigger ( 'dao.before.insert', $instance );
127 20
		$className = \get_class ( $instance );
128 20
		$db = self::getDb ( $className );
129 20
		$quote = $db->quote;
130 20
		$tableName = OrmUtils::getTableName ( $className );
131 20
		$keyAndValues = Reflexion::getPropertiesAndValues ( $instance );
132 20
		$keyAndValues = \array_merge ( $keyAndValues, OrmUtils::getManyToOneMembersAndValues ( $instance ) );
133 20
		$pk = OrmUtils::getFirstKey ( $className );
134 20
		$pkVal = $keyAndValues [$pk] ?? null;
135 20
		if (($pkVal) == null) {
136 20
			unset ( $keyAndValues [$pk] );
137
		}
138 20
		$sql = "INSERT INTO {$quote}{$tableName}{$quote} (" . SqlUtils::getInsertFields ( $keyAndValues ) . ') VALUES(' . SqlUtils::getInsertFieldsValues ( $keyAndValues ) . ')';
139 20
		if (Logger::isActive ()) {
140 20
			Logger::info ( 'DAOUpdates', $sql, 'insert' );
141 20
			Logger::info ( 'DAOUpdates', \json_encode ( $keyAndValues ), 'Key and values' );
142
		}
143
144 20
		$statement = $db->getUpdateStatement ( $sql );
145
		try {
146 20
			$result = $statement->execute ( $keyAndValues );
147 20
			if ($result) {
148 20
				if ($pkVal == null) {
149 20
					$lastId = $db->lastInserId ( "{$tableName}_{$pk}_seq" );
150 20
					if ($lastId != 0) {
151 20
						$propKey = OrmUtils::getFirstPropKey ( $className );
152 20
						$propKey->setValue ( $instance, $lastId );
153 20
						$pkVal = $lastId;
154
					}
155
				}
156 20
				$instance->_rest = $keyAndValues;
157 20
				$instance->_rest [$pk] = $pkVal;
158
159 20
				if ($insertMany) {
160 1
					self::insertOrUpdateAllManyToMany ( $instance );
161
				}
162
			}
163 20
			EventsManager::trigger ( DAOEvents::AFTER_INSERT, $instance, $result );
164 20
			return $result;
165 1
		} catch ( \Exception $e ) {
166 1
			Logger::warn ( 'DAOUpdates', $e->getMessage (), 'insert' );
167 1
			if (Startup::$config ['debug']) {
168 1
				throw $e;
169
			}
170
		}
171
		return false;
172
	}
173
174
	/**
175
	 * Updates manyToMany members
176
	 *
177
	 * @param object $instance
178
	 */
179 1
	public static function insertOrUpdateAllManyToMany($instance) {
180 1
		$members = OrmUtils::getAnnotationInfo ( get_class ( $instance ), '#manyToMany' );
181 1
		if ($members !== false) {
182
			$members = \array_keys ( $members );
183
			foreach ( $members as $member ) {
184
				self::insertOrUpdateManyToMany ( $instance, $member );
185
			}
186
		}
187 1
	}
188
189
	/**
190
	 * Updates the $member member of $instance annotated by a ManyToMany
191
	 *
192
	 * @param Object $instance
193
	 * @param String $member
194
	 */
195
	public static function insertOrUpdateManyToMany($instance, $member) {
196
		$db = self::getDb ( \get_class ( $instance ) );
197
		$parser = new ManyToManyParser ( $db, $instance, $member );
198
		if ($parser->init ()) {
199
			$quote = $db->quote;
200
			$myField = $parser->getMyFkField ();
201
			$field = $parser->getFkField ();
202
			$sql = "INSERT INTO {$quote}" . $parser->getJoinTable () . "{$quote}({$quote}" . $myField . "{$quote},{$quote}" . $field . "{$quote}) VALUES (:" . $myField . ",:" . $field . ");";
203
			$memberAccessor = 'get' . \ucfirst ( $member );
204
			$memberValues = $instance->$memberAccessor ();
205
			$myKey = $parser->getMyPk ();
206
			$myAccessorId = 'get' . \ucfirst ( $myKey );
207
			$accessorId = 'get' . \ucfirst ( $parser->getPk () );
208
			$id = $instance->$myAccessorId ();
209
			if (! \is_null ( $memberValues )) {
210
				$db->execute ( "DELETE FROM {$quote}" . $parser->getJoinTable () . "{$quote} WHERE {$quote}{$myField}{$quote}='{$id}'" );
211
				$statement = $db->prepareStatement ( $sql );
212
				foreach ( $memberValues as $targetInstance ) {
213
					$foreignId = $targetInstance->$accessorId ();
214
					$foreignInstances = self::getAll ( $parser->getTargetEntity (), $quote . $parser->getPk () . $quote . "='{$foreignId}'" );
215
					if (! OrmUtils::exists ( $targetInstance, $parser->getPk (), $foreignInstances )) {
216
						self::insert ( $targetInstance, false );
217
						$foreignId = $targetInstance->$accessorId ();
218
						Logger::info ( 'DAOUpdates', "Insertion d'une instance de " . get_class ( $instance ), 'InsertMany' );
219
					}
220
					$db->bindValueFromStatement ( $statement, $myField, $id );
221
					$db->bindValueFromStatement ( $statement, $field, $foreignId );
222
					$statement->execute ();
223
					Logger::info ( 'DAOUpdates', "Insertion des valeurs dans la table association '" . $parser->getJoinTable () . "'", 'InsertMany' );
224
				}
225
			}
226
		}
227
	}
228
229
	/**
230
	 * Updates an existing $instance in the database.
231
	 * Be careful not to modify the primary key
232
	 *
233
	 * @param object $instance instance to modify
234
	 * @param boolean $updateMany Adds or updates ManyToMany members
235
	 */
236 3
	public static function update($instance, $updateMany = false) {
237 3
		EventsManager::trigger ( 'dao.before.update', $instance );
238 3
		$className = \get_class ( $instance );
239 3
		$db = self::getDb ( $className );
240 3
		$quote = $db->quote;
241 3
		$tableName = OrmUtils::getTableName ( $className );
242 3
		$ColumnskeyAndValues = \array_merge ( Reflexion::getPropertiesAndValues ( $instance ), OrmUtils::getManyToOneMembersAndValues ( $instance ) );
243 3
		$keyFieldsAndValues = OrmUtils::getKeyFieldsAndValues ( $instance );
244 3
		$sql = "UPDATE {$quote}{$tableName}{$quote} SET " . SqlUtils::getUpdateFieldsKeyAndParams ( $ColumnskeyAndValues ) . ' WHERE ' . SqlUtils::getWhere ( $keyFieldsAndValues );
245 3
		if (Logger::isActive ()) {
246 3
			Logger::info ( "DAOUpdates", $sql, "update" );
247 3
			Logger::info ( "DAOUpdates", \json_encode ( $ColumnskeyAndValues ), "Key and values" );
248
		}
249 3
		$statement = $db->getUpdateStatement ( $sql );
250
		try {
251 3
			$result = $statement->execute ( $ColumnskeyAndValues );
252 3
			if ($updateMany && $result) {
253 1
				self::insertOrUpdateAllManyToMany ( $instance );
254
			}
255 3
			EventsManager::trigger ( DAOEvents::AFTER_UPDATE, $instance, $result );
256 3
			$instance->_rest = \array_merge ( $instance->_rest, $ColumnskeyAndValues );
257 3
			return $result;
258
		} catch ( \Exception $e ) {
259
			Logger::warn ( "DAOUpdates", $e->getMessage (), "update" );
260
		}
261
		return false;
262
	}
263
264
	/**
265
	 * Updates an array of $instances in the database.
266
	 * Be careful not to modify the primary key
267
	 *
268
	 * @param array $instances instances to modify
269
	 * @param boolean $updateMany Adds or updates ManyToMany members
270
	 * @return boolean
271
	 */
272
	public static function updateGroup($instances, $updateMany = false) {
273
		if (\count ( $instances ) > 0) {
274
			$instance = \current ( $instances );
275
			$className = \get_class ( $instance );
276
			$db = self::getDb ( $className );
277
			$quote = $db->quote;
278
			$tableName = OrmUtils::getTableName ( $className );
279
			$ColumnskeyAndValues = \array_merge ( Reflexion::getPropertiesAndValues ( $instance ), OrmUtils::getManyToOneMembersAndValues ( $instance ) );
280
			$keyFieldsAndValues = OrmUtils::getKeyFieldsAndValues ( $instance );
281
			$sql = "UPDATE {$quote}{$tableName}{$quote} SET " . SqlUtils::getUpdateFieldsKeyAndParams ( $ColumnskeyAndValues ) . ' WHERE ' . SqlUtils::getWhere ( $keyFieldsAndValues );
282
283
			$statement = $db->getUpdateStatement ( $sql );
284
			try {
285
				$db->beginTransaction ();
286
				foreach ( $instances as $instance ) {
287
					EventsManager::trigger ( 'dao.before.update', $instance );
288
					$ColumnskeyAndValues = \array_merge ( Reflexion::getPropertiesAndValues ( $instance ), OrmUtils::getManyToOneMembersAndValues ( $instance ) );
289
					$result = $statement->execute ( $ColumnskeyAndValues );
290
					if ($updateMany && $result) {
291
						self::insertOrUpdateAllManyToMany ( $instance );
292
					}
293
					EventsManager::trigger ( DAOEvents::AFTER_UPDATE, $instance, $result );
294
					$instance->_rest = \array_merge ( $instance->_rest, $ColumnskeyAndValues );
295
					if (Logger::isActive ()) {
296
						Logger::info ( "DAOUpdates", $sql, "update" );
297
						Logger::info ( "DAOUpdates", json_encode ( $ColumnskeyAndValues ), "Key and values" );
298
					}
299
				}
300
				$db->commit ();
301
				return true;
302
			} catch ( \Exception $e ) {
303
				Logger::warn ( "DAOUpdates", $e->getMessage (), "update" );
304
				$db->rollBack ();
305
			}
306
		}
307
		return false;
308
	}
309
310
	/**
311
	 *
312
	 * @param object $instance
313
	 * @param boolean $updateMany
314
	 * @return boolean|int
315
	 */
316
	public static function save($instance, $updateMany = false) {
317
		if (isset ( $instance->_rest )) {
318
			return self::update ( $instance, $updateMany );
319
		}
320
		return self::insert ( $instance, $updateMany );
321
	}
322
}
323