Completed
Push — master ( 552d53...b8eb91 )
by Jean-Christophe
02:02
created

DAO::getInstanceIdInObjects()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
namespace micro\orm;
3
use micro\db\SqlUtils;
4
use micro\db\Database;
5
use micro\log\Logger;
6
use micro\orm\parser\ManyToManyParser;
7
use micro\orm\parser\Reflexion;
8
9
/**
10
 * Classe passerelle entre base de données et modèle objet
11
 * @author jc
12
 * @version 1.0.0.5
13
 * @package orm
14
 */
15
class DAO {
16
	public static $db;
17
18
	private static function getCondition($keyValues){
19
		$retArray=array();
20
		if(is_array($keyValues)){
21
			foreach ($keyValues as $key=>$value){
22
				$retArray[]="`".$key."` = '".$value."'";
23
			}
24
			$condition=implode(" AND ", $retArray);
25
		}else
26
			$condition=$keyValues;
27
		return $condition;
28
	}
29
30
	/**
31
	 * Charge les membres associés à $instance par une relation de type ManyToOne
32
	 * @param object $instance
33
	 * @param mixed $value
34
	 * @param array $annotationArray
35
	 * @param boolean $useCache
36
	 */
37
	private static function getOneManyToOne($instance,$value,$annotationArray,$useCache=NULL){
38
		$class=get_class($instance);
39
		$member=$annotationArray["member"];
40
		$key=OrmUtils::getFirstKey($annotationArray["className"]);
41
		$kv=array($key=>$value);
42
		$obj=self::getOne($annotationArray["className"], $kv,false,false,$useCache);
43
		if($obj!==null){
44
			Logger::log("getOneManyToOne", "Chargement de ".$member." pour l'objet ".$class);
45
			$accesseur="set".ucfirst($member);
46
			if(method_exists($instance,$accesseur)){
47
				$instance->$accesseur($obj);
48
				return;
49
			}
50
		}
51
	}
52
53
	/**
54
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
55
	 * Si $array est null, les fils sont chargés depuis la base de données
56
	 * @param object $instance
57
	 * @param string $member Membre sur lequel doit être présent une annotation OneToMany
58
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
59
	 * @param boolean $useCache
60
	 * @param array $annot used internally
61
	 */
62
	public static function getOneToMany($instance,$member,$array=null,$useCache=NULL,$annot=null){
63
		$ret=array();
64
		$class=get_class($instance);
65
		if(!isset($annot))
66
			$annot=OrmUtils::getAnnotationInfoMember($class,"#oneToMany", $member);
67
		if($annot!==false){
68
			$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn",$annot["mappedBy"]);
69
			if($fkAnnot!==false){
70
				$fkv=OrmUtils::getFirstKeyValue($instance);
71
				if(is_null($array)){
72
					$ret=self::getAll($annot["className"],$fkAnnot["name"]."='".$fkv."'",true,false,$useCache);
73
				}else{
74
					self::getOneToManyFromArray($ret, $array, $fkv, $annot);
75
				}
76
				self::setToMember($member, $instance, $ret, $class, "getOneToMany");
77
				}
78
			}
79
		return $ret;
80
	}
81
82
	private static function getOneToManyFromArray(&$ret,$array,$fkv,$annot){
83
		$elementAccessor="get".ucfirst($annot["mappedBy"]);
84
		foreach ($array as $element){
85
			$elementRef=$element->$elementAccessor();
86
			if(!is_null($elementRef)){
87
				$idElementRef=OrmUtils::getFirstKeyValue($elementRef);
88
				if($idElementRef==$fkv)
89
					$ret[]=$element;
90
			}
91
		}
92
	}
93
94
	private static function setToMember($member,$instance,$value,$class,$part){
95
		$accessor="set".ucfirst($member);
96
		if(method_exists($instance,$accessor)){
97
			Logger::log($part, "Affectation de ".$member." pour l'objet ".$class);
98
			$instance->$accessor($value);
99
		}else{
100
			Logger::warn($part, "L'accesseur ".$accessor." est manquant pour ".$class);
101
		}
102
	}
103
	/**
104
	 * @param object $instance
105
	 * @param ManyToManyParser $parser
106
	 * @return PDOStatement
107
	 */
108
	private static function getSQLForJoinTable($instance,ManyToManyParser $parser){
109
		$accessor="get".ucfirst($parser->getPk());
110
		$sql="SELECT * FROM `".$parser->getJoinTable()."` WHERE `".$parser->getMyFkField()."`='".$instance->$accessor()."'";
111
		Logger::log("ManyToMany", "Exécution de ".$sql);
112
		return self::$db->query($sql);
113
	}
114
	/**
115
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
116
	 * Si $array est null, les fils sont chargés depuis la base de données
117
	 * @param object $instance
118
	 * @param string $member Membre sur lequel doit être présent une annotation ManyToMany
119
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
120
	 * @param boolean $useCache
121
	 */
122
	public static function getManyToMany($instance,$member,$array=null,$useCache=NULL){
123
		$ret=array();
124
		$class=get_class($instance);
125
		$parser=new ManyToManyParser($instance, $member);
126
		if($parser->init()){
127
			if(is_null($array)){
128
				$joinTableCursor=self::getSQLForJoinTable($instance,$parser);
129
				foreach($joinTableCursor as $row){
130
					$fkv=$row[$parser->getFkField()];
131
					$tmp=self::getOne($parser->getTargetEntity(),"`".$parser->getPk()."`='".$fkv."'",false,false,$useCache);
132
					array_push($ret,$tmp);
133
				}
134
			}
135
			else{
136
				self::getManyToManyFromArray($ret, $instance, $array, $class, $parser);
137
			}
138
			self::setToMember($member, $instance, $ret, $class, "getManyToMany");
139
		}
140
		return $ret;
141
	}
142
143
	private static function getManyToManyFromArray(&$ret,$instance,$array,$class,$parser){
144
		$continue=true;
145
		$accessorToMember="get".ucfirst($parser->getInversedBy());
146
		$myPkAccessor="get".ucfirst($parser->getMyPk());
147
148
		if(!method_exists($instance, $myPkAccessor)){
149
			Logger::warn("ManyToMany", "L'accesseur au membre clé primaire ".$myPkAccessor." est manquant pour ".$class);
150
		}
151
		if(count($array)>0)
152
			$continue=method_exists($array[0], $accessorToMember);
153
			if($continue){
154
				foreach($array as $targetEntityInstance){
155
					$instances=$targetEntityInstance->$accessorToMember();
156
					if(is_array($instances)){
157
						foreach ($instances as $inst){
158
							if($inst->$myPkAccessor()==$instance->$myPkAccessor())
159
								array_push($ret, $targetEntityInstance);
160
						}
161
					}
162
				}
163
			}else{
164
				Logger::warn("ManyToMany", "L'accesseur au membre ".$parser->getInversedBy()." est manquant pour ".$parser->getTargetEntity());
165
			}
166
	}
167
	/**
168
	 * Retourne un tableau d'objets de $className depuis la base de données
169
	 * @param string $className nom de la classe du model à charger
170
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
171
	 * @param boolean $loadManyToOne
172
	 * @param boolean $loadOneToMany
173
	 * @param boolean $useCache
174
	 * @return array
175
	 */
176
	public static function getAll($className,$condition='',$loadManyToOne=true,$loadOneToMany=false,$useCache=NULL){
177
		$objects=array();
178
		$invertedJoinColumns=null; $oneToManyFields=null;
179
		$tableName=OrmUtils::getTableName($className);
180
		$metaDatas=OrmUtils::getModelMetadata($className);
181
		if($loadManyToOne && isset($metaDatas["#invertedJoinColumn"]))
182
			$invertedJoinColumns=$metaDatas["#invertedJoinColumn"];
183
		if($loadOneToMany && isset($metaDatas["#oneToMany"])){
184
			$oneToManyFields=$metaDatas["#oneToMany"];
185
		}
186
		if($condition!='')
187
			$condition=" WHERE ".$condition;
188
		$query=self::$db->prepareAndExecute("SELECT * FROM ".$tableName.$condition,$useCache);
189
		Logger::log("getAll","SELECT * FROM ".$tableName.$condition);
190
		foreach ($query as $row){
191
			$o=self::loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields,$useCache);
192
			$objects[]=$o;
193
		}
194
		return $objects;
195
	}
196
197
	private static function loadObjectFromRow($row,$className,$invertedJoinColumns,$oneToManyFields,$useCache=NULL){
198
		$o=new $className();
199
		foreach ($row as $k=>$v){
200
			$accesseur="set".ucfirst($k);
201
			if(method_exists($o,$accesseur)){
202
				$o->$accesseur($v);
203
			}
204
			if(isset($invertedJoinColumns) && isset($invertedJoinColumns[$k])) {
205
				self::getOneManyToOne($o,$v, $invertedJoinColumns[$k],$useCache);
206
			}
207
		}
208
		if(isset($oneToManyFields)){
209
			foreach ($oneToManyFields as $k=>$annot){
210
				self::getOneToMany($o, $k,null,$useCache,$annot);
211
			}
212
		}
213
		return $o;
214
	}
215
	/**
216
	 * Retourne le nombre d'objets de $className depuis la base de données respectant la condition éventuellement passée en paramètre
217
	 * @param string $className nom de la classe du model à charger
218
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
219
	 */
220
	public static function count($className,$condition=''){
221
		$tableName=OrmUtils::getTableName($className);
222
		if($condition!='')
223
			$condition=" WHERE ".$condition;
224
		return self::$db->query("SELECT COUNT(*) FROM ".$tableName.$condition)->fetchColumn();
225
	}
226
227
	/**
228
	 * Retourne une instance de $className depuis la base de données, à  partir des valeurs $keyValues de la clé primaire
229
	 * @param String $className nom de la classe du model à charger
230
	 * @param Array|string $keyValues valeurs des clés primaires ou condition
231
	 * @param boolean $useCache
232
	 */
233
	public static function getOne($className,$keyValues,$loadManyToOne=true,$loadOneToMany=false,$useCache=NULL){
234
		if(!is_array($keyValues)){
235
			if(strrpos($keyValues,"=")===false){
236
				$keyValues="`".OrmUtils::getFirstKey($className)."`='".$keyValues."'";
237
			}elseif ($keyValues=="")
238
				$keyValues="";
239
		}
240
		$condition=self::getCondition($keyValues);
241
		$retour=self::getAll($className,$condition,$loadManyToOne,$loadOneToMany,$useCache);
242
		if(sizeof($retour)<1)
243
			return null;
244
		else
245
			return $retour[0];
246
		return $retour;
0 ignored issues
show
Unused Code introduced by
return $retour; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
247
248
	}
249
250
	/**
251
	 * Supprime $instance dans la base de données
252
	 * @param Classe $instance instance à supprimer
253
	 */
254
	public static function remove($instance){
255
		$tableName=OrmUtils::getTableName(get_class($instance));
256
		$keyAndValues=OrmUtils::getKeyFieldsAndValues($instance);
257
		$sql="DELETE FROM ".$tableName." WHERE ".SqlUtils::getWhere($keyAndValues);
258
		Logger::log("delete", $sql);
259
		$statement=self::$db->prepareStatement($sql);
260
		foreach ($keyAndValues as $key=>$value){
261
			self::$db->bindValueFromStatement($statement,$key,$value);
262
		}
263
		return $statement->execute();
264
	}
265
266
	/**
267
	 * Insère $instance dans la base de données
268
	 * @param object $instance instance à insérer
269
	 * @param $insertMany si vrai, sauvegarde des instances reliées à $instance par un ManyToMany
270
	 */
271
	public static function insert($instance,$insertMany=false){
272
		$tableName=OrmUtils::getTableName(get_class($instance));
273
		$keyAndValues=Reflexion::getPropertiesAndValues($instance);
274
		$keyAndValues=array_merge($keyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
275
		$sql="INSERT INTO ".$tableName."(".SqlUtils::getInsertFields($keyAndValues).") VALUES(".SqlUtils::getInsertFieldsValues($keyAndValues).")";
276
		Logger::log("insert", $sql);
277
		Logger::log("Key and values", json_encode($keyAndValues));
278
		$statement=self::$db->prepareStatement($sql);
279
		foreach ($keyAndValues as $key=>$value){
280
				self::$db->bindValueFromStatement($statement,$key,$value);
281
		}
282
		$result=$statement->execute();
283
		if($result){
284
			$accesseurId="set".ucfirst(OrmUtils::getFirstKey(get_class($instance)));
285
			$instance->$accesseurId(self::$db->lastInserId());
286
			if($insertMany){
287
				self::insertOrUpdateAllManyToMany($instance);
288
			}
289
		}
290
		return $result;
291
	}
292
293
	/**
294
	 * Met à jour les membres de $instance annotés par un ManyToMany
295
	 * @param object $instance
296
	 */
297
	public static function insertOrUpdateAllManyToMany($instance){
298
		$members=OrmUtils::getAnnotationInfo(get_class($instance), "#manyToMany");
299
		if($members!==false){
300
			$members=\array_keys($members);
301
			foreach ($members as $member){
302
				self::insertOrUpdateManyToMany($instance, $member);
303
			}
304
		}
305
	}
306
307
	/**
308
	 * Met à jour le membre $member de $instance annoté par un ManyToMany
309
	 * @param Object $instance
310
	 * @param String $member
311
	 */
312
	public static function insertOrUpdateManyToMany($instance,$member){
313
		$parser=new ManyToManyParser($instance, $member);
314
		if($parser->init()){
315
			$myField=$parser->getMyFkField();
316
			$field=$parser->getFkField();
317
			$sql="INSERT INTO `".$parser->getJoinTable()."`(`".$myField."`,`".$field."`) VALUES (:".$myField.",:".$field.");";
318
			$memberAccessor="get".ucfirst($member);
319
			$memberValues=$instance->$memberAccessor();
320
			$myKey=$parser->getMyPk();
321
			$myAccessorId="get".ucfirst($myKey);
322
			$accessorId="get".ucfirst($parser->getPk());
323
			$id=$instance->$myAccessorId();
324
			if(!is_null($memberValues)){
325
				self::$db->execute("DELETE FROM `".$parser->getJoinTable()."` WHERE `".$myField."`='".$id."'");
326
				$statement=self::$db->prepareStatement($sql);
327
				foreach ($memberValues as $targetInstance){
328
					$foreignId=$targetInstance->$accessorId();
329
					$foreignInstances=self::getAll($parser->getTargetEntity(), "`".$parser->getPk()."`"."='".$foreignId."'");
330
					if(!OrmUtils::exists($targetInstance, $parser->getPk(), $foreignInstances)){
331
						self::insert($targetInstance,false);
332
						$foreignId=$targetInstance->$accessorId();
333
						Logger::log("InsertMany", "Insertion d'une instance de ".get_class($instance));
334
					}
335
					self::$db->bindValueFromStatement($statement,$myField,$id);
336
					self::$db->bindValueFromStatement($statement,$field,$foreignId);
337
					$statement->execute();
338
					Logger::log("InsertMany", "Insertion des valeurs dans la table association '".$parser->getJoinTable()."'");
339
				}
340
			}
341
		}
342
	}
343
	/**
344
	 * Met à jour $instance dans la base de données.
345
	 * Attention de ne pas modifier la clé primaire
346
	 * @param Classe $instance instance à modifier
347
	 * @param $updateMany Ajoute ou met à jour les membres ManyToMany
348
	 */
349
	public static function update($instance,$updateMany=false){
350
		$tableName=OrmUtils::getTableName(get_class($instance));
351
		$ColumnskeyAndValues=Reflexion::getPropertiesAndValues($instance);
352
		$ColumnskeyAndValues=array_merge($ColumnskeyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
353
		$keyFieldsAndValues=OrmUtils::getKeyFieldsAndValues($instance);
354
		$sql="UPDATE ".$tableName." SET ".SqlUtils::getUpdateFieldsKeyAndValues($ColumnskeyAndValues)." WHERE ".SqlUtils::getWhere($keyFieldsAndValues);
355
		Logger::log("update", $sql);
356
		Logger::log("Key and values", json_encode($ColumnskeyAndValues));
357
		$statement=self::$db->prepareStatement($sql);
358
		foreach ($ColumnskeyAndValues as $key=>$value){
359
				self::$db->bindValueFromStatement($statement,$key,$value);
360
		}
361
		$result= $statement->execute();
362
		if($result && $updateMany)
363
			self::insertOrUpdateAllManyToMany($instance);
364
		return $result;
365
	}
366
367
	/**
368
	 * Réalise la connexion à la base de données en utilisant les paramètres passés
369
	 * @param string $dbName
370
	 * @param string $serverName
371
	 * @param string $port
372
	 * @param string $user
373
	 * @param string $password
374
	 */
375
	public static function connect($dbName,$serverName="127.0.0.1",$port="3306",$user="root",$password=""){
376
		self::$db=new Database($dbName,$serverName,$port,$user,$password);
377
		self::$db->connect();
378
	}
379
}
380