Completed
Push — master ( f97bb0...2ac44b )
by Jean-Christophe
01:48
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\Database;
6
use Ubiquity\log\Logger;
7
use Ubiquity\orm\parser\ManyToManyParser;
8
use Ubiquity\db\SqlUtils;
9
use Ubiquity\orm\parser\Reflexion;
10
use Ubiquity\orm\traits\DAOUpdatesTrait;
11
12
/**
13
 * Gateway class between database and object model
14
 * @author jc
15
 * @version 1.0.0.6
16
 * @package orm
17
 */
18
class DAO {
19
	use DAOUpdatesTrait;
20
	public static $db;
21
22
	/**
23
	 * Loads member associated with $instance by a ManyToOne type relationship
24
	 * @param object $instance
25
	 * @param string $member
26
	 * @param boolean $useCache
27
	 */
28
	public static function getManyToOne($instance, $member, $useCache=NULL) {
29
		$fieldAnnot=OrmUtils::getMemberJoinColumns($instance, $member);
30
		if($fieldAnnot!==null){
31
			$field=$fieldAnnot[0];
32
			$value=Reflexion::getMemberValue($instance, $field);
33
			$annotationArray=$fieldAnnot[1];
34
			$member=$annotationArray["member"];
35
			$key=OrmUtils::getFirstKey($annotationArray["className"]);
36
			$kv=array ($key => $value );
37
			$obj=self::getOne($annotationArray["className"], $kv, false, false, $useCache);
38
			if ($obj !== null) {
39
				Logger::log("getManyToOne", "Chargement de " . $member . " pour l'objet " . \get_class($instance));
40
				$accesseur="set" . ucfirst($member);
41
				if (method_exists($instance, $accesseur)) {
42
					$instance->$accesseur($obj);
43
					$instance->_rest[$member]=$obj->_rest;
44
					return;
45
				}
46
			}
47
		}
48
	}
49
50
	private static function _getOneToManyFromArray(&$ret, $array, $fkv, $mappedBy) {
51
		$elementAccessor="get" . ucfirst($mappedBy);
52
		foreach ( $array as $element ) {
53
			$elementRef=$element->$elementAccessor();
54
			if (!is_null($elementRef)) {
55
				$idElementRef=OrmUtils::getFirstKeyValue($elementRef);
56
				if ($idElementRef == $fkv)
57
					$ret[]=$element;
58
			}
59
		}
60
	}
61
62
	/**
63
	 * Assign / load the child records in the $member member of $instance.
64
	 * @param object $instance
65
	 * @param string $member Member on which a oneToMany annotation must be present
66
	 * @param boolean $useCache
67
	 * @param array $annot used internally
68
	 */
69
	public static function getOneToMany($instance, $member, $useCache=NULL, $annot=null) {
70
		$ret=array ();
71
		$class=get_class($instance);
72
		if (!isset($annot))
73
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
74
			if ($annot !== false) {
75
				$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn", $annot["mappedBy"]);
76
				if ($fkAnnot !== false) {
77
					$fkv=OrmUtils::getFirstKeyValue($instance);
78
					$ret=self::getAll($annot["className"], $fkAnnot["name"] . "='" . $fkv . "'", true, false, $useCache);
79
					self::setToMember($member, $instance, $ret, $class, "getOneToMany");
80
				}
81
			}
82
			return $ret;
83
	}
84
85
	/**
86
	 * @param object $instance
87
	 * @param string $member
88
	 * @param array $array
89
	 * @param string $mappedBy
90
	 */
91
	public static function affectsOneToManyFromArray($instance, $member, $array=null, $mappedBy=null) {
92
		$ret=array ();
93
		$class=get_class($instance);
94
		if (!isset($mappedBy)){
95
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
96
			$mappedBy=$annot["mappedBy"];
97
		}
98
		if ($mappedBy !== false) {
99
				$fkv=OrmUtils::getFirstKeyValue($instance);
100
				self::_getOneToManyFromArray($ret, $array, $fkv, $mappedBy);
101
				self::setToMember($member, $instance, $ret, $class, "getOneToMany");
102
		}
103
		return $ret;
104
	}
105
106
	private static function setToMember($member, $instance, $value, $class, $part) {
107
		$accessor="set" . ucfirst($member);
108
		if (method_exists($instance, $accessor)) {
109
			Logger::log($part, "Affectation de " . $member . " pour l'objet " . $class);
110
			$instance->$accessor($value);
111
			$instance->_rest[$member]=$value;
112
		} else {
113
			Logger::warn($part, "L'accesseur " . $accessor . " est manquant pour " . $class);
114
		}
115
	}
116
117
	/**
118
	 * Assigns / loads the child records in the $member member of $instance.
119
	 * If $ array is null, the records are loaded from the database
120
	 * @param object $instance
121
	 * @param string $member Member on which a ManyToMany annotation must be present
122
	 * @param array $array optional parameter containing the list of possible child records
123
	 * @param boolean $useCache
124
	 */
125
	public static function getManyToMany($instance, $member,$array=null,$useCache=NULL){
126
		$ret=array ();
127
		$class=get_class($instance);
128
		$parser=new ManyToManyParser($instance, $member);
129
		if ($parser->init()) {
130
			if (is_null($array)) {
131
				$accessor="get" . ucfirst($parser->getMyPk());
132
				$condition=" INNER JOIN `" . $parser->getJoinTable() . "` on `".$parser->getJoinTable()."`.`".$parser->getFkField()."`=`".$parser->getTargetEntityTable()."`.`".$parser->getPk()."` WHERE `" . $parser->getMyFkField() . "`='" . $instance->$accessor() . "'";
133
				$ret=self::getAll($parser->getTargetEntityClass(),$condition,true,false,$useCache);
134
			}else{
135
				self::getManyToManyFromArray($ret, $instance, $array, $class, $parser);
136
			}
137
			self::setToMember($member, $instance, $ret, $class, "getManyToMany");
138
		}
139
		return $ret;
140
	}
141
142
	/**
143
	 * @param object $instance
144
	 * @param array $array
145
	 * @param boolean $useCache
146
	 */
147
	public static function affectsManyToManys($instance,$array=NULL,$useCache=NULL){
148
		$metaDatas=OrmUtils::getModelMetadata(\get_class($instance));
149
		$manyToManyFields=$metaDatas["#manyToMany"];
150
		if(\sizeof($manyToManyFields)>0){
151
			foreach ($manyToManyFields as $member){
152
				self::getManyToMany($instance, $member,$array,$useCache);
153
			}
154
		}
155
	}
156
157
	private static function getManyToManyFromArray(&$ret, $instance, $array, $class, $parser) {
158
		$continue=true;
159
		$accessorToMember="get" . ucfirst($parser->getInversedBy());
160
		$myPkAccessor="get" . ucfirst($parser->getMyPk());
161
162
		if (!method_exists($instance, $myPkAccessor)) {
163
			Logger::warn("ManyToMany", "L'accesseur au membre clé primaire " . $myPkAccessor . " est manquant pour " . $class);
164
		}
165
		if (count($array) > 0)
166
			$continue=method_exists($array[0], $accessorToMember);
167
		if ($continue) {
168
			foreach ( $array as $targetEntityInstance ) {
169
				$instances=$targetEntityInstance->$accessorToMember();
170
				if (is_array($instances)) {
171
					foreach ( $instances as $inst ) {
172
						if ($inst->$myPkAccessor() == $instance->$myPkAccessor())
173
							array_push($ret, $targetEntityInstance);
174
					}
175
				}
176
			}
177
		} else {
178
			Logger::warn("ManyToMany", "L'accesseur au membre " . $parser->getInversedBy() . " est manquant pour " . $parser->getTargetEntity());
179
		}
180
	}
181
182
	/**
183
	 * Returns an array of $className objects from the database
184
	 * @param string $className class name of the model to load
185
	 * @param string $condition Part following the WHERE of an SQL statement
186
	 * @param boolean $loadManyToOne if true, charges associate members with manyToOne association
187
	 * @param boolean $loadOneToMany if true, charges associate members with oneToMany association
188
	 * @param boolean $useCache use the active cache if true
189
	 * @return array
190
	 */
191
	public static function getAll($className, $condition='', $loadManyToOne=true, $loadOneToMany=false,$useCache=NULL) {
192
		$objects=array ();
193
		$invertedJoinColumns=null;
194
		$oneToManyFields=null;
195
		$metaDatas=OrmUtils::getModelMetadata($className);
196
		$tableName=$metaDatas["#tableName"];
197
		if ($loadManyToOne && isset($metaDatas["#invertedJoinColumn"]))
198
			$invertedJoinColumns=$metaDatas["#invertedJoinColumn"];
199
		if ($loadOneToMany && isset($metaDatas["#oneToMany"])) {
200
			$oneToManyFields=$metaDatas["#oneToMany"];
201
		}
202
		$condition=SqlUtils::checkWhere($condition);
203
		$members=\array_diff($metaDatas["#fieldNames"],$metaDatas["#notSerializable"]);
204
		$query=self::$db->prepareAndExecute($tableName, $condition,$members,$useCache);
205
		Logger::log("getAll", "SELECT * FROM " . $tableName . $condition);
206
		$oneToManyQueries=[];
207
		$manyToOneQueries=[];
208
209
		foreach ( $query as $row ) {
210
			$object=self::loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields,$members, $oneToManyQueries,$manyToOneQueries);
211
			$key=OrmUtils::getFirstKeyValue($object);
212
			$objects[$key]=$object;
213
		}
214
215
		if($loadManyToOne && \sizeof($manyToOneQueries)>0){
216
			self::_affectsObjectsFromArray($manyToOneQueries, $objects, function($object,$member,$manyToOneObjects,$fkField){
217
				self::affectsManyToOneFromArray($object,$member,$manyToOneObjects,$fkField);
218
			});
219
		}
220
221
		if($loadOneToMany && \sizeof($oneToManyQueries)>0){
222
			self::_affectsObjectsFromArray($oneToManyQueries, $objects, function($object,$member,$relationObjects,$fkField){
223
				self::affectsOneToManyFromArray($object,$member,$relationObjects,$fkField);
224
			});
225
		}
226
		return $objects;
227
	}
228
229
	private static function _affectsObjectsFromArray($queries,$objects,$affectsCallback,$useCache=NULL){
230
		foreach ($queries as $key=>$conditions){
231
			list($class,$member,$fkField)=\explode("|", $key);
232
			$condition=\implode(" OR ", $conditions);
233
			$relationObjects=self::getAll($class,$condition,true,false,$useCache);
234
			foreach ($objects as $object){
235
				$affectsCallback($object, $member,$relationObjects,$fkField);
236
			}
237
		}
238
	}
239
240
	private static function affectsManyToOneFromArray($object,$member,$manyToOneObjects,$fkField){
241
		$class=\get_class($object);
242
		if(isset($object->$fkField)){
243
			$value=$manyToOneObjects[$object->$fkField];
244
			self::setToMember($member, $object, $value, $class, "getManyToOne");
245
		}
246
	}
247
248
	/**
249
	 * @param array $row
250
	 * @param string $className
251
	 * @param array $invertedJoinColumns
252
	 * @param array $oneToManyFields
253
	 * @param array $members
254
	 * @param array $oneToManyQueries
255
	 * @param array $manyToOneQueries
256
	 * @return object
257
	 */
258
	private static function loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields, $members,&$oneToManyQueries,&$manyToOneQueries) {
259
		$o=new $className();
260
		foreach ( $row as $k => $v ) {
261
			if(($field=\array_search($k, $members))!==false){
262
				$accesseur="set" . ucfirst($field);
263
				if (method_exists($o, $accesseur)) {
264
					$o->$accesseur($v);
265
				}
266
			}
267
			$o->_rest[$k]=$v;
268
			if (isset($invertedJoinColumns) && isset($invertedJoinColumns[$k])) {
269
				$fk="_".$k;
270
				$o->$fk=$v;
271
				self::prepareManyToOne($manyToOneQueries,$v, $fk,$invertedJoinColumns[$k]);
272
			}
273
		}
274
		if (isset($oneToManyFields)) {
275
			foreach ( $oneToManyFields as $k => $annot ) {
276
				self::prepareOneToMany($oneToManyQueries,$o, $k, $annot);
277
			}
278
		}
279
		return $o;
280
	}
281
282
283
	/**
284
	 * Prepares members associated with $instance with a oneToMany type relationship
285
	 * @param $ret array of sql conditions
286
	 * @param object $instance
287
	 * @param string $member Member on which a OneToMany annotation must be present
288
	 * @param array $annot used internally
289
	 */
290
	private static function prepareOneToMany(&$ret,$instance, $member, $annot=null) {
291
		$class=get_class($instance);
292
		if (!isset($annot))
293
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
294
			if ($annot !== false) {
295
				$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn", $annot["mappedBy"]);
296
				if ($fkAnnot !== false) {
297
					$fkv=OrmUtils::getFirstKeyValue($instance);
298
					$key=$annot["className"]."|".$member."|".$annot["mappedBy"];
299
					if(!isset($ret[$key])){
300
						$ret[$key]=[];
301
					}
302
					$ret[$key][$fkv]=$fkAnnot["name"] . "='" . $fkv . "'";
303
				}
304
			}
305
	}
306
307
	/**
308
	 * Prepares members associated with $instance with a manyToOne type relationship
309
	 * @param $ret array of sql conditions
310
	 * @param mixed $value
311
	 * @param string $fkField
312
	 * @param array $annotationArray
313
	 */
314
	private static function prepareManyToOne(&$ret, $value, $fkField,$annotationArray) {
315
		$member=$annotationArray["member"];
316
		$fk=OrmUtils::getFirstKey($annotationArray["className"]);
317
		$key=$annotationArray["className"]."|".$member."|".$fkField;
318
		if(!isset($ret[$key])){
319
			$ret[$key]=[];
320
		}
321
		$ret[$key][$value]=$fk . "='" . $value . "'";
322
	}
323
324
	/**
325
	 * Returns the number of objects of $className from the database respecting the condition possibly passed as parameter
326
	 * @param string $className complete classname of the model to load
327
	 * @param string $condition Part following the WHERE of an SQL statement
328
	 * @return int count of objects
329
	 */
330
	public static function count($className, $condition='') {
331
		$tableName=OrmUtils::getTableName($className);
332
		if ($condition != '')
333
			$condition=" WHERE " . $condition;
334
		return self::$db->query("SELECT COUNT(*) FROM " . $tableName . $condition)->fetchColumn();
335
	}
336
337
	/**
338
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key
339
	 * @param String $className complete classname of the model to load
340
	 * @param Array|string $keyValues primary key values or condition
341
	 * @param $loadManyToOne if true, charges associate members with manyToOne association
342
	 * @param $loadOneToMany if true, charges associate members with oneToMany association
343
	 * @param boolean $useCache use cache if true
344
	 * @return object the instance loaded or null if not found
345
	 */
346
	public static function getOne($className, $keyValues, $loadManyToOne=true, $loadOneToMany=false, $useCache=NULL) {
347
		if (!is_array($keyValues)) {
348
			if (strrpos($keyValues, "=") === false && strrpos($keyValues, ">") === false && strrpos($keyValues, "<") === false) {
349
				$keyValues="`" . OrmUtils::getFirstKey($className) . "`='" . $keyValues . "'";
350
			}
351
		}
352
		$condition=SqlUtils::getCondition($keyValues,$className);
353
		$limit="";
354
		if(\stripos($condition, " limit ")===false)
355
			$limit=" limit 1";
356
		$retour=self::getAll($className, $condition.$limit, $loadManyToOne, $loadOneToMany,$useCache);
357
		if (sizeof($retour) < 1){
358
			return null;
359
		}
360
		return \reset($retour);
361
	}
362
363
	/**
364
	 * Establishes the connection to the database using the past parameters
365
	 * @param string $dbType
366
	 * @param string $dbName
367
	 * @param string $serverName
368
	 * @param string $port
369
	 * @param string $user
370
	 * @param string $password
371
	 * @param array $options
372
	 * @param boolean $cache
373
	 */
374
	public static function connect($dbType,$dbName, $serverName="127.0.0.1", $port="3306", $user="root", $password="", $options=[],$cache=false) {
375
		self::$db=new Database($dbType,$dbName, $serverName, $port, $user, $password, $options,$cache);
376
		try {
377
			self::$db->connect();
378
		} catch (\Exception $e) {
379
			Logger::error("DAO", $e->getMessage());
380
			throw $e;
381
		}
382
	}
383
384
	/**
385
	 * Returns true if the connection to the database is estabished
386
	 * @return boolean
387
	 */
388
	public static function isConnected(){
389
		return self::$db!==null && (self::$db instanceof Database) && self::$db->isConnected();
390
	}
391
}
392