Completed
Push — master ( 1f90e4...0f8170 )
by Jean-Christophe
02:14
created

DAO::connect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
eloc 3
nc 1
nop 5
1
<?php
2
namespace micro\orm;
3
use micro\annotations\ManyToManyParser;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, micro\orm\ManyToManyParser.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
4
use micro\db\SqlUtils;
5
use micro\db\Database;
6
use micro\log\Logger;
7
8
/**
9
 * Classe passerelle entre base de données et modèle objet
10
 * @author jc
11
 * @version 1.0.0.5
12
 * @package orm
13
 */
14
class DAO {
15
	public static $db;
16
	private static $objects;
17
18
	private static function getObjects(){
19
		if(is_null(self::$objects)){
20
			self::$objects=array();
21
			Logger::log("getObjects","Instanciation de Objects");
22
		}
23
		return self::$objects;
24
	}
25
26
	private static function getInstanceIdInObjects($instance){
27
		$condition=self::getCondition(OrmUtils::getKeyFieldsAndValues($instance));
28
		$condition=preg_replace('/\s|\'+/', '', $condition);
29
		return get_class($instance)."#".$condition;
30
	}
31
32
	private static function getCondition($keyValues){
33
		$retArray=array();
34
		if(is_array($keyValues)){
35
			foreach ($keyValues as $key=>$value){
36
				$retArray[]="`".$key."` = '".$value."'";
37
			}
38
			$condition=implode(" AND ", $retArray);
39
		}else
40
			$condition=$keyValues;
41
		return $condition;
42
	}
43
44
	private static function addInstanceInObjects($instance){
45
		self::getObjects();
46
		self::$objects[self::getInstanceIdInObjects($instance)]=$instance;
47
	}
48
49
	private static function getInstanceInObjects($className,$keyValue){
50
		$objects=self::getObjects();
51
		$condition=self::getCondition($keyValue);
52
		$condition=preg_replace('/\s|\'+/', '', $condition);
53
		$key=$className."#".$condition;
54
		if(array_key_exists($key,$objects)){
55
			Logger::log("getInstanceInObjects", "Récupération d'une instance de ".$className."(".$condition.") dans objects");
56
			return $objects[$key];
57
		}
58
		return null;
59
	}
60
61
	/**
62
	 * Charge les membres associés à $instance par une relation de type ManyToOne
63
	 * @param object $instance
64
	 * @param string $key
0 ignored issues
show
Bug introduced by
There is no parameter named $key. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
65
	 * @param mixed $value
66
	 * @param array $annotationArray
67
	 */
68
	private static function getOneManyToOne($instance,$value,$annotationArray){
69
		$class=get_class($instance);
70
		$member=$annotationArray["member"];
71
		$key=OrmUtils::getFirstKey($annotationArray["className"]);
72
		$kv=array($key=>$value);
73
		$obj=self::getOne($annotationArray["className"], $kv,false);
74
		if($obj!==null){
75
			Logger::log("getOneManyToOne", "Chargement de ".$member." pour l'objet ".$class);
76
			$accesseur="set".ucfirst($member);
77
			if(method_exists($instance,$accesseur)){
78
				$instance->$accesseur($obj);
79
				return;
80
			}
81
		}
82
	}
83
84
	/**
85
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
86
	 * Si $array est null, les fils sont chargés depuis la base de données
87
	 * @param object $instance
88
	 * @param string $member Membre sur lequel doit être présent une annotation OneToMany
89
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
90
	 * @param array $annot used internally
91
	 */
92
	public static function getOneToMany($instance,$member,$array=null,$annot=null){
93
		$ret=array();
94
		$class=get_class($instance);
95
		if(!isset($annot))
96
			$annot=OrmUtils::getAnnotationInfoMember($class,"#oneToMany", $member);
97
		if($annot!==false){
98
			$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn",$annot["mappedBy"]);
99
			if($fkAnnot!==false){
100
				$fkv=OrmUtils::getFirstKeyValue($instance);
101
				if(is_null($array)){
102
					$ret=self::getAll($annot["className"],$fkAnnot["name"]."='".$fkv."'");
103
				}else{
104
					$elementAccessor="get".ucfirst($annot->mappedBy);
105
					foreach ($array as $element){
106
						$elementRef=$element->$elementAccessor();
107
						if(!is_null($elementRef)){
108
							$idElementRef=OrmUtils::getFirstKeyValue($elementRef);
109
							if($idElementRef==$fkv)
110
								$ret[]=$element;
111
						}
112
					}
113
				}
114
				self::setToMember($member, $instance, $ret, $class, "getOneToMany");
115
				}
116
			}
117
		return $ret;
118
	}
119
120
	private static function setToMember($member,$instance,$value,$class,$part){
121
		$accessor="set".ucfirst($member);
122
		if(method_exists($instance,$accessor)){
123
			Logger::log($part, "Affectation de ".$member." pour l'objet ".$class);
124
			$instance->$accessor($value);
125
		}else{
126
			Logger::warn($part, "L'accesseur ".$accessor." est manquant pour ".$class);
127
		}
128
	}
129
	/**
130
	 * @param object $instance
131
	 * @param ManyToManyParser $parser
132
	 * @return PDOStatement
133
	 */
134
	private static function getSQLForJoinTable($instance,ManyToManyParser $parser){
135
		$accessor="get".ucfirst($parser->getPk());
136
		$sql="SELECT * FROM `".$parser->getJoinTable()."` WHERE `".$parser->getMyFkField()."`='".$instance->$accessor()."'";
137
		Logger::log("ManyToMany", "Exécution de ".$sql);
138
		return self::$db->query($sql);
139
	}
140
	/**
141
	 * Affecte/charge les enregistrements fils dans le membre $member de $instance.
142
	 * Si $array est null, les fils sont chargés depuis la base de données
143
	 * @param object $instance
144
	 * @param string $member Membre sur lequel doit être présent une annotation OneToMany
145
	 * @param array $array paramètre facultatif contenant la liste des fils possibles
146
	 */
147
	public static function getManyToMany($instance,$member,$array=null){
148
		$ret=array();
149
		$class=get_class($instance);
150
		$parser=new ManyToManyParser($instance, $member);
151
		if($parser->init()){
152
			$joinTableCursor=self::getSQLForJoinTable($instance,$parser);
153
			if(is_null($array)){
154
				foreach($joinTableCursor as $row){
155
					$fkv=$row[$parser->getFkField()];
156
					$tmp=self::getOne($parser->getTargetEntity(),"`".$parser->getPk()."`='".$fkv."'");
157
					array_push($ret,$tmp);
158
				}
159
			}
160
			else{
161
				$continue=true;
162
				$accessorToMember="get".ucfirst($parser->getInversedBy());
163
				$myPkAccessor="get".ucfirst($parser->getMyPk());
164
165
				if(!method_exists($instance, $myPkAccessor)){
166
					Logger::warn("ManyToMany", "L'accesseur au membre clé primaire ".$myPkAccessor." est manquant pour ".$class);
167
				}
168
				if(count($array)>0)
169
					$continue=method_exists($array[0], $accessorToMember);
170
				if($continue){
171
					foreach($joinTableCursor as $row){
172
						$fkv=$row[$parser->getFkField()];
0 ignored issues
show
Unused Code introduced by
$fkv is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
173
						foreach($array as $targetEntityInstance){
174
							$instances=$targetEntityInstance->$accessorToMember();
175
							if(is_array($instances)){
176
								foreach ($instances as $inst){
177
									if($inst->$myPkAccessor==$instance->$myPkAccessor)
178
										array_push($array, $targetEntityInstance);
179
								}
180
							}
181
						}
182
					}
183
				}else{
184
					Logger::warn("ManyToMany", "L'accesseur au membre ".$parser->getInversedBy()." est manquant pour ".$parser->getTargetEntity());
185
				}
186
			}
187
			self::setToMember($member, $instance, $ret, $class, "getManyToMany");
188
		}
189
		return $ret;
190
	}
191
	/**
192
	 * Retourne un tableau d'objets de $className depuis la base de données
193
	 * @param string $className nom de la classe du model à charger
194
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
195
	 * @return array
196
	 */
197
	public static function getAll($className,$condition='',$loadManyToOne=true,$loadOneToMany=false){
198
		$objects=array();
199
		$tableName=OrmUtils::getTableName($className);
200
		$metaDatas=OrmUtils::getModelMetadata($className);
201
		if($loadManyToOne && isset($metaDatas["#invertedJoinColumn"]))
202
			$invertedJoinColumns=$metaDatas["#invertedJoinColumn"];
203
		if($loadOneToMany && isset($metaDatas["#oneToMany"])){
204
			$oneToManyFields=$metaDatas["#oneToMany"];
205
		}
206
		if($condition!='')
207
			$condition=" WHERE ".$condition;
208
		$query=self::$db->prepareAndExecute("SELECT * FROM ".$tableName.$condition);
209
		Logger::log("getAll","SELECT * FROM ".$tableName.$condition);
210
		foreach ($query as $row){
211
			$o=new $className();
212
			$objects[]=$o;
213
			foreach ($row as $k=>$v){
214
				$accesseur="set".ucfirst($k);
215
				if(method_exists($o,$accesseur)){
216
					$o->$accesseur($v);
217
				}
218
				if(isset($invertedJoinColumns) && isset($invertedJoinColumns[$k])) {
219
					self::getOneManyToOne($o,$v, $invertedJoinColumns[$k]);
220
				}
221
			}
222
			if(isset($oneToManyFields)){
223
				foreach ($oneToManyFields as $k=>$annot){
224
					self::getOneToMany($o, $k,null,$annot);
225
				}
226
			}
227
			self::addInstanceInObjects($o);
228
		}
229
		return $objects;
230
	}
231
	/**
232
	 * Retourne le nombre d'objets de $className depuis la base de données respectant la condition éventuellement passée en paramètre
233
	 * @param string $className nom de la classe du model à charger
234
	 * @param string $condition Partie suivant le WHERE d'une instruction SQL
235
	 */
236
	public static function count($className,$condition=''){
237
		$tableName=OrmUtils::getTableName($className);
238
		if($condition!='')
239
			$condition=" WHERE ".$condition;
240
		return self::$db->query("SELECT COUNT(*) FROM ".$tableName.$condition)->fetchColumn();
241
	}
242
243
	/**
244
	 * Retourne une instance de $className depuis la base de données, à  partir des valeurs $keyValues de la clé primaire
245
	 * @param String $className nom de la classe du model à charger
246
	 * @param Array|string $keyValues valeurs des clés primaires ou condition
247
	 */
248
	public static function getOne($className,$keyValues,$loadManyToOne=true){
249
		if(!is_array($keyValues)){
250
			if(strrpos($keyValues,"=")===false){
251
				$keyValues="`".OrmUtils::getFirstKey($className)."`='".$keyValues."'";
252
			}elseif ($keyValues=="")
253
				$keyValues="";
254
		}
255
		$condition=self::getCondition($keyValues);
256
		$retour=self::getInstanceInObjects($className,$condition);
257
		if(!isset($retour)){
258
			$retour=self::getAll($className,$condition,$loadManyToOne);
259
			if(sizeof($retour)<1)
260
				return null;
261
			else
262
				return $retour[0];
263
		}
264
		return $retour;
265
266
	}
267
268
	/**
269
	 * Supprime $instance dans la base de données
270
	 * @param Classe $instance instance à supprimer
271
	 */
272
	public static function remove($instance){
273
		$tableName=OrmUtils::getTableName(get_class($instance));
274
		$keyAndValues=OrmUtils::getKeyFieldsAndValues($instance);
275
		$sql="DELETE FROM ".$tableName." WHERE ".SqlUtils::getWhere($keyAndValues);
276
		Logger::log("delete", $sql);
277
		$statement=self::$db->prepareStatement($sql);
278
		foreach ($keyAndValues as $key=>$value){
279
			self::$db->bindValueFromStatement($statement,$key,$value);
280
		}
281
		return $statement->execute();
282
	}
283
284
	/**
285
	 * Insère $instance dans la base de données
286
	 * @param object $instance instance à insérer
287
	 * @param $insertMany si vrai, sauvegarde des instances reliées à $instance par un ManyToMany
288
	 */
289
	public static function insert($instance,$insertMany=false){
290
		$tableName=OrmUtils::getTableName(get_class($instance));
291
		$keyAndValues=Reflexion::getPropertiesAndValues($instance);
292
		$keyAndValues=array_merge($keyAndValues, OrmUtils::getManyToOneMembersAndValues($instance));
293
		$sql="INSERT INTO ".$tableName."(".SqlUtils::getInsertFields($keyAndValues).") VALUES(".SqlUtils::getInsertFieldsValues($keyAndValues).")";
294
		Logger::log("insert", $sql);
295
		Logger::log("Key and values", json_encode($keyAndValues));
296
		$statement=self::$db->prepareStatement($sql);
297
		foreach ($keyAndValues as $key=>$value){
298
				self::$db->bindValueFromStatement($statement,$key,$value);
299
		}
300
		$result=$statement->execute();
301
		if($result){
302
			$accesseurId="set".ucfirst(OrmUtils::getFirstKey(get_class($instance)));
303
			$instance->$accesseurId(self::$db->lastInserId());
304
			if($insertMany){
305
				self::insertOrUpdateAllManyToMany($instance);
306
			}
307
		}
308
		return $result;
309
	}
310
311
	/**
312
	 * Met à jour les membres de $instance annotés par un ManyToMany
313
	 * @param object $instance
314
	 */
315
	public static function insertOrUpdateAllManyToMany($instance){
316
		$members=OrmUtils::getAnnotationInfo(get_class($instance), "#manyToMany");
317
		if($members!==false){
318
			$members=\array_keys($members);
319
			foreach ($members as $member){
320
				self::insertOrUpdateManyToMany($instance, $member);
321
			}
322
		}
323
	}
324
325
	/**
326
	 * Met à jour le membre $member de $instance annoté par un ManyToMany
327
	 * @param Object $instance
328
	 * @param String $member
329
	 */
330
	public static function insertOrUpdateManyToMany($instance,$member){
331
		$parser=new ManyToManyParser($instance, $member);
332
		if($parser->init()){
333
			$myField=$parser->getMyFkField();
334
			$field=$parser->getFkField();
335
			$sql="INSERT INTO `".$parser->getJoinTable()."`(`".$myField."`,`".$field."`) VALUES (:".$myField.",:".$field.");";
336
			$memberAccessor="get".ucfirst($member);
337
			$memberValues=$instance->$memberAccessor();
338
			$myKey=$parser->getMyPk();
339
			$myAccessorId="get".ucfirst($myKey);
340
			$accessorId="get".ucfirst($parser->getPk());
341
			$id=$instance->$myAccessorId();
342
			if(!is_null($memberValues)){
343
				self::$db->execute("DELETE FROM `".$parser->getJoinTable()."` WHERE `".$myField."`='".$id."'");
344
				$statement=self::$db->prepareStatement($sql);
345
				foreach ($memberValues as $k=>$targetInstance){
346
					$foreignId=$targetInstance->$accessorId();
347
					$foreignInstances=self::getAll($parser->getTargetEntity(), "`".$parser->getPk()."`"."='".$foreignId."'");
348
					if(!OrmUtils::exists($targetInstance, $parser->getPk(), $foreignInstances)){
349
						self::insert($targetInstance,false);
350
						$foreignId=$targetInstance->$accessorId();
351
						Logger::log("InsertMany", "Insertion d'une instance de ".get_class($instance));
352
					}
353
					self::$db->bindValueFromStatement($statement,$myField,$id);
354
					self::$db->bindValueFromStatement($statement,$field,$foreignId);
355
					$statement->execute();
356
					Logger::log("InsertMany", "Insertion des valeurs dans la table association '".$parser->getJoinTable()."'");
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 $dbName
388
	 * @param string $serverName
389
	 * @param string $port
390
	 * @param string $user
391
	 * @param string $password
392
	 */
393
	public static function connect($dbName,$serverName="127.0.0.1",$port="3306",$user="root",$password=""){
394
		self::$db=new Database($dbName,$serverName,$port,$user,$password);
395
		self::$db->connect();
396
	}
397
}
398