Completed
Push — master ( 4e6026...e0b9fa )
by Jean-Christophe
01:30
created

DAO::connect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Ubiquity\orm;
4
5
use Ubiquity\db\SqlUtils;
6
use Ubiquity\db\Database;
7
use Ubiquity\log\Logger;
8
use Ubiquity\orm\parser\ManyToManyParser;
9
use Ubiquity\orm\parser\Reflexion;
10
use Ubiquity\utils\JArray;
11
12
/**
13
 * Classe passerelle entre base de données et modèle objet
14
 * @author jc
15
 * @version 1.0.0.5
16
 * @package orm
17
 */
18
class DAO {
19
	public static $db;
20
21
	private static function getCondition($keyValues,$classname=NULL) {
22
		$retArray=array ();
23
		if (is_array($keyValues)) {
24
			if(!JArray::isAssociative($keyValues)){
25
				if(isset($classname)){
26
					$keys=OrmUtils::getKeyFields($classname);
27
					$keyValues=\array_combine($keys, $keyValues);
28
				}
29
			}
30
			foreach ( $keyValues as $key => $value ) {
31
				$retArray[]="`" . $key . "` = '" . $value . "'";
32
			}
33
			$condition=implode(" AND ", $retArray);
34
		} else
35
			$condition=$keyValues;
36
		return $condition;
37
	}
38
39
	/**
40
	 * Charge les membres associés à $instance par une relation de type ManyToOne
41
	 * @param object $instance
42
	 * @param mixed $value
43
	 * @param array $annotationArray
44
	 * @param boolean $useCache
45
	 */
46
	private static function getOneManyToOne($instance, $value, $annotationArray, $useCache=NULL) {
47
		$class=get_class($instance);
48
		$member=$annotationArray["member"];
49
		$key=OrmUtils::getFirstKey($annotationArray["className"]);
50
		$kv=array ($key => $value );
51
		$obj=self::getOne($annotationArray["className"], $kv, false, false, $useCache);
52
		if ($obj !== null) {
53
			Logger::log("getOneManyToOne", "Chargement de " . $member . " pour l'objet " . $class);
54
			$accesseur="set" . ucfirst($member);
55
			if (method_exists($instance, $accesseur)) {
56
				$instance->$accesseur($obj);
57
				$instance->_rest[$member]=$obj->_rest;
58
				return;
59
			}
60
		}
61
	}
62
63
	/**
64
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
65
	 * Si $array est null, les fils sont chargés depuis la base de données
66
	 * @param object $instance
67
	 * @param string $member Membre sur lequel doit être présent une annotation OneToMany
68
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
69
	 * @param boolean $useCache
70
	 * @param array $annot used internally
71
	 */
72
	public static function getOneToMany($instance, $member, $array=null, $useCache=NULL, $annot=null) {
73
		$ret=array ();
74
		$class=get_class($instance);
75
		if (!isset($annot))
76
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
77
		if ($annot !== false) {
78
			$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn", $annot["mappedBy"]);
79
			if ($fkAnnot !== false) {
80
				$fkv=OrmUtils::getFirstKeyValue($instance);
81
				if (is_null($array)) {
82
					$ret=self::getAll($annot["className"], $fkAnnot["name"] . "='" . $fkv . "'", true, false, $useCache);
83
				} else {
84
					self::getOneToManyFromArray($ret, $array, $fkv, $annot);
85
				}
86
				self::setToMember($member, $instance, $ret, $class, "getOneToMany");
87
			}
88
		}
89
		return $ret;
90
	}
91
92
	private static function getOneToManyFromArray(&$ret, $array, $fkv, $annot) {
93
		$elementAccessor="get" . ucfirst($annot["mappedBy"]);
94
		foreach ( $array as $element ) {
95
			$elementRef=$element->$elementAccessor();
96
			if (!is_null($elementRef)) {
97
				$idElementRef=OrmUtils::getFirstKeyValue($elementRef);
98
				if ($idElementRef == $fkv)
99
					$ret[]=$element;
100
			}
101
		}
102
	}
103
104
	private static function setToMember($member, $instance, $value, $class, $part) {
105
		$accessor="set" . ucfirst($member);
106
		if (method_exists($instance, $accessor)) {
107
			Logger::log($part, "Affectation de " . $member . " pour l'objet " . $class);
108
			$instance->$accessor($value);
109
			$instance->_rest[$member]=$value;
110
		} else {
111
			Logger::warn($part, "L'accesseur " . $accessor . " est manquant pour " . $class);
112
		}
113
	}
114
115
	/**
116
	 *
117
	 * @param object $instance
118
	 * @param ManyToManyParser $parser
119
	 * @return PDOStatement
120
	 */
121
	private static function getSQLForJoinTable($instance, ManyToManyParser $parser) {
122
		$accessor="get" . ucfirst($parser->getPk());
123
		$sql="SELECT * FROM `" . $parser->getJoinTable() . "` WHERE `" . $parser->getMyFkField() . "`='" . $instance->$accessor() . "'";
124
		Logger::log("ManyToMany", "Exécution de " . $sql);
125
		return self::$db->query($sql);
126
	}
127
128
	/**
129
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
130
	 * Si $array est null, les fils sont chargés depuis la base de données
131
	 * @param object $instance
132
	 * @param string $member Membre sur lequel doit être présent une annotation ManyToMany
133
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
134
	 * @param boolean $useCache
135
	 */
136
	public static function getManyToMany($instance, $member, $array=null, $useCache=NULL) {
137
		$ret=array ();
138
		$class=get_class($instance);
139
		$parser=new ManyToManyParser($instance, $member);
140
		if ($parser->init()) {
141
			if (is_null($array)) {
142
				$joinTableCursor=self::getSQLForJoinTable($instance, $parser);
143
				foreach ( $joinTableCursor as $row ) {
144
					$fkv=$row[$parser->getFkField()];
145
					$tmp=self::getOne($parser->getTargetEntity(), "`" . $parser->getPk() . "`='" . $fkv . "'", false, false, $useCache);
146
					array_push($ret, $tmp);
147
				}
148
			} else {
149
				self::getManyToManyFromArray($ret, $instance, $array, $class, $parser);
150
			}
151
			self::setToMember($member, $instance, $ret, $class, "getManyToMany");
152
		}
153
		return $ret;
154
	}
155
156
	private static function getManyToManyFromArray(&$ret, $instance, $array, $class, $parser) {
157
		$continue=true;
158
		$accessorToMember="get" . ucfirst($parser->getInversedBy());
159
		$myPkAccessor="get" . ucfirst($parser->getMyPk());
160
161
		if (!method_exists($instance, $myPkAccessor)) {
162
			Logger::warn("ManyToMany", "L'accesseur au membre clé primaire " . $myPkAccessor . " est manquant pour " . $class);
163
		}
164
		if (count($array) > 0)
165
			$continue=method_exists($array[0], $accessorToMember);
166
		if ($continue) {
167
			foreach ( $array as $targetEntityInstance ) {
168
				$instances=$targetEntityInstance->$accessorToMember();
169
				if (is_array($instances)) {
170
					foreach ( $instances as $inst ) {
171
						if ($inst->$myPkAccessor() == $instance->$myPkAccessor())
172
							array_push($ret, $targetEntityInstance);
173
					}
174
				}
175
			}
176
		} else {
177
			Logger::warn("ManyToMany", "L'accesseur au membre " . $parser->getInversedBy() . " est manquant pour " . $parser->getTargetEntity());
178
		}
179
	}
180
181
	/**
182
	 * Retourne un tableau d'objets de $className depuis la base de données
183
	 * @param string $className nom de la classe du model à charger
184
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
185
	 * @param boolean $loadManyToOne
186
	 * @param boolean $loadOneToMany
187
	 * @param boolean $useCache
188
	 * @return array
189
	 */
190
	public static function getAll($className, $condition='', $loadManyToOne=true, $loadOneToMany=false, $useCache=NULL) {
191
		$objects=array ();
192
		$invertedJoinColumns=null;
193
		$oneToManyFields=null;
194
		$metaDatas=OrmUtils::getModelMetadata($className);
195
		$tableName=$metaDatas["#tableName"];
196
		if ($loadManyToOne && isset($metaDatas["#invertedJoinColumn"]))
197
			$invertedJoinColumns=$metaDatas["#invertedJoinColumn"];
198
		if ($loadOneToMany && isset($metaDatas["#oneToMany"])) {
199
			$oneToManyFields=$metaDatas["#oneToMany"];
200
		}
201
		if ($condition != '')
202
			$condition=" WHERE " . $condition;
203
		$query=self::$db->prepareAndExecute($tableName, $condition, $useCache);
204
		Logger::log("getAll", "SELECT * FROM " . $tableName . $condition);
205
206
		$members=$metaDatas["#fieldNames"];
207
		foreach ( $query as $row ) {
208
			$objects[]=self::loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields,$members, $useCache);
209
		}
210
		return $objects;
211
	}
212
213
	private static function loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields, $members,$useCache=NULL) {
214
		$o=new $className();
215
		foreach ( $row as $k => $v ) {
216
			$field=\array_search($k, $members);
217
			$accesseur="set" . ucfirst($field);
218
			if (method_exists($o, $accesseur)) {
219
				$o->$accesseur($v);
220
				$o->_rest[$field]=$v;
221
			}
222
			if (isset($invertedJoinColumns) && isset($invertedJoinColumns[$k])) {
223
				self::getOneManyToOne($o, $v, $invertedJoinColumns[$k], $useCache);
224
			}
225
		}
226
		if (isset($oneToManyFields)) {
227
			foreach ( $oneToManyFields as $k => $annot ) {
228
				self::getOneToMany($o, $k, null, $useCache, $annot);
229
			}
230
		}
231
		return $o;
232
	}
233
234
	/**
235
	 * Retourne le nombre d'objets de $className depuis la base de données respectant la condition éventuellement passée en paramètre
236
	 * @param string $className nom de la classe du model à charger
237
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
238
	 */
239
	public static function count($className, $condition='') {
240
		$tableName=OrmUtils::getTableName($className);
241
		if ($condition != '')
242
			$condition=" WHERE " . $condition;
243
		return self::$db->query("SELECT COUNT(*) FROM " . $tableName . $condition)->fetchColumn();
244
	}
245
246
	/**
247
	 * Retourne une instance de $className depuis la base de données, à  partir des valeurs $keyValues de la clé primaire
248
	 * @param String $className nom de la classe du model à charger
249
	 * @param Array|string $keyValues valeurs des clés primaires ou condition
250
	 * @param boolean $useCache
251
	 */
252
	public static function getOne($className, $keyValues, $loadManyToOne=true, $loadOneToMany=false, $useCache=NULL) {
253
		if (!is_array($keyValues)) {
254
			if (strrpos($keyValues, "=") === false) {
255
				$keyValues="`" . OrmUtils::getFirstKey($className) . "`='" . $keyValues . "'";
256
			} elseif ($keyValues == "")
257
				$keyValues="";
258
		}
259
		$condition=self::getCondition($keyValues,$className);
260
		$retour=self::getAll($className, $condition, $loadManyToOne, $loadOneToMany, $useCache);
261
		if (sizeof($retour) < 1)
262
			return null;
263
		else
264
			return $retour[0];
265
	}
266
267
	/**
268
	 * Supprime $instance dans la base de données
269
	 * @param Classe $instance instance à supprimer
270
	 */
271
	public static function remove($instance) {
272
		$tableName=OrmUtils::getTableName(get_class($instance));
273
		$keyAndValues=OrmUtils::getKeyFieldsAndValues($instance);
274
		$sql="DELETE FROM " . $tableName . " WHERE " . SqlUtils::getWhere($keyAndValues);
275
		Logger::log("delete", $sql);
276
		$statement=self::$db->prepareStatement($sql);
277
		foreach ( $keyAndValues as $key => $value ) {
278
			self::$db->bindValueFromStatement($statement, $key, $value);
279
		}
280
		return $statement->execute();
281
	}
282
283
	/**
284
	 * Insère $instance dans la base de données
285
	 * @param object $instance instance à insérer
286
	 * @param $insertMany si vrai, sauvegarde des instances reliées à $instance par un ManyToMany
287
	 */
288
	public static function insert($instance, $insertMany=false) {
289
		$tableName=OrmUtils::getTableName(get_class($instance));
290
		$keyAndValues=Reflexion::getPropertiesAndValues($instance);
291
		$keyAndValues=array_merge($keyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
292
		$sql="INSERT INTO " . $tableName . "(" . SqlUtils::getInsertFields($keyAndValues) . ") VALUES(" . SqlUtils::getInsertFieldsValues($keyAndValues) . ")";
293
		Logger::log("insert", $sql);
294
		Logger::log("Key and values", json_encode($keyAndValues));
295
		$statement=self::$db->prepareStatement($sql);
296
		foreach ( $keyAndValues as $key => $value ) {
297
			self::$db->bindValueFromStatement($statement, $key, $value);
298
		}
299
		$result=$statement->execute();
300
		if ($result) {
301
			$accesseurId="set" . ucfirst(OrmUtils::getFirstKey(get_class($instance)));
302
			$instance->$accesseurId(self::$db->lastInserId());
303
			if ($insertMany) {
304
				self::insertOrUpdateAllManyToMany($instance);
305
			}
306
		}
307
		return $result;
308
	}
309
310
	/**
311
	 * Met à jour les membres de $instance annotés par un ManyToMany
312
	 * @param object $instance
313
	 */
314
	public static function insertOrUpdateAllManyToMany($instance) {
315
		$members=OrmUtils::getAnnotationInfo(get_class($instance), "#manyToMany");
316
		if ($members !== false) {
317
			$members=\array_keys($members);
318
			foreach ( $members as $member ) {
319
				self::insertOrUpdateManyToMany($instance, $member);
320
			}
321
		}
322
	}
323
324
	/**
325
	 * Met à jour le membre $member de $instance annoté par un ManyToMany
326
	 * @param Object $instance
327
	 * @param String $member
328
	 */
329
	public static function insertOrUpdateManyToMany($instance, $member) {
330
		$parser=new ManyToManyParser($instance, $member);
331
		if ($parser->init()) {
332
			$myField=$parser->getMyFkField();
333
			$field=$parser->getFkField();
334
			$sql="INSERT INTO `" . $parser->getJoinTable() . "`(`" . $myField . "`,`" . $field . "`) VALUES (:" . $myField . ",:" . $field . ");";
335
			$memberAccessor="get" . ucfirst($member);
336
			$memberValues=$instance->$memberAccessor();
337
			$myKey=$parser->getMyPk();
338
			$myAccessorId="get" . ucfirst($myKey);
339
			$accessorId="get" . ucfirst($parser->getPk());
340
			$id=$instance->$myAccessorId();
341
			if (!is_null($memberValues)) {
342
				self::$db->execute("DELETE FROM `" . $parser->getJoinTable() . "` WHERE `" . $myField . "`='" . $id . "'");
343
				$statement=self::$db->prepareStatement($sql);
344
				foreach ( $memberValues as $targetInstance ) {
345
					$foreignId=$targetInstance->$accessorId();
346
					$foreignInstances=self::getAll($parser->getTargetEntity(), "`" . $parser->getPk() . "`" . "='" . $foreignId . "'");
347
					if (!OrmUtils::exists($targetInstance, $parser->getPk(), $foreignInstances)) {
348
						self::insert($targetInstance, false);
349
						$foreignId=$targetInstance->$accessorId();
350
						Logger::log("InsertMany", "Insertion d'une instance de " . get_class($instance));
351
					}
352
					self::$db->bindValueFromStatement($statement, $myField, $id);
353
					self::$db->bindValueFromStatement($statement, $field, $foreignId);
354
					$statement->execute();
355
					Logger::log("InsertMany", "Insertion des valeurs dans la table association '" . $parser->getJoinTable() . "'");
356
				}
357
			}
358
		}
359
	}
360
361
	/**
362
	 * Met à jour $instance dans la base de données.
363
	 * Attention de ne pas modifier la clé primaire
364
	 * @param Classe $instance instance à modifier
365
	 * @param $updateMany Ajoute ou met à jour les membres ManyToMany
366
	 */
367
	public static function update($instance, $updateMany=false) {
368
		$tableName=OrmUtils::getTableName(get_class($instance));
369
		$ColumnskeyAndValues=Reflexion::getPropertiesAndValues($instance);
370
		$ColumnskeyAndValues=array_merge($ColumnskeyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
371
		$keyFieldsAndValues=OrmUtils::getKeyFieldsAndValues($instance);
372
		$sql="UPDATE " . $tableName . " SET " . SqlUtils::getUpdateFieldsKeyAndValues($ColumnskeyAndValues) . " WHERE " . SqlUtils::getWhere($keyFieldsAndValues);
373
		Logger::log("update", $sql);
374
		Logger::log("Key and values", json_encode($ColumnskeyAndValues));
375
		$statement=self::$db->prepareStatement($sql);
376
		foreach ( $ColumnskeyAndValues as $key => $value ) {
377
			self::$db->bindValueFromStatement($statement, $key, $value);
378
		}
379
		$result=$statement->execute();
380
		if ($result && $updateMany)
381
			self::insertOrUpdateAllManyToMany($instance);
382
		return $result;
383
	}
384
385
	/**
386
	 * Réalise la connexion à la base de données en utilisant les paramètres passés
387
	 * @param string $dbType
388
	 * @param string $dbName
389
	 * @param string $serverName
390
	 * @param string $port
391
	 * @param string $user
392
	 * @param string $password
393
	 * @param array $options
394
	 * @param boolean|string $cache
395
	 */
396
	public static function connect($dbType,$dbName, $serverName="127.0.0.1", $port="3306", $user="root", $password="", $options=[],$cache=false) {
397
		self::$db=new Database($dbType,$dbName, $serverName, $port, $user, $password, $options,$cache);
398
		try {
399
			self::$db->connect();
400
		} catch (\Exception $e) {
401
			Logger::error("DAO", $e->getMessage());
402
			throw $e;
403
		}
404
	}
405
406
	public static function isConnected(){
407
		return self::$db!==null && (self::$db instanceof Database) && self::$db->isConnected();
408
	}
409
}
410