Completed
Push — master ( 4f04d3...489696 )
by Jean-Christophe
01:34
created

DAO::isConnected()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 3
eloc 2
nc 3
nop 0
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 mixed $value
0 ignored issues
show
Bug introduced by
There is no parameter named $value. 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...
26
	 * @param array $annotationArray
0 ignored issues
show
Bug introduced by
There is no parameter named $annotationArray. 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...
27
	 * @param boolean $useCache
28
	 */
29
	public static function getManyToOne($instance, $member, $useCache=NULL) {
30
		$fieldAnnot=OrmUtils::getMemberJoinColumns($instance, $member);
31
		if($fieldAnnot!==null){
32
			$field=$fieldAnnot[0];
33
			$value=Reflexion::getMemberValue($instance, $field);
34
			$annotationArray=$fieldAnnot[1];
35
			$member=$annotationArray["member"];
36
			$key=OrmUtils::getFirstKey($annotationArray["className"]);
37
			$kv=array ($key => $value );
38
			$obj=self::getOne($annotationArray["className"], $kv, false, false, $useCache);
39
			if ($obj !== null) {
40
				Logger::log("getManyToOne", "Chargement de " . $member . " pour l'objet " . \get_class($instance));
41
				$accesseur="set" . ucfirst($member);
42
				if (method_exists($instance, $accesseur)) {
43
					$instance->$accesseur($obj);
44
					$instance->_rest[$member]=$obj->_rest;
45
					return;
46
				}
47
			}
48
		}
49
	}
50
51
	private static function _getOneToManyFromArray(&$ret, $array, $fkv, $mappedBy) {
52
		$elementAccessor="get" . ucfirst($mappedBy);
53
		foreach ( $array as $element ) {
54
			$elementRef=$element->$elementAccessor();
55
			if (!is_null($elementRef)) {
56
				$idElementRef=OrmUtils::getFirstKeyValue($elementRef);
57
				if ($idElementRef == $fkv)
58
					$ret[]=$element;
59
			}
60
		}
61
	}
62
63
	/**
64
	 * Assign / load the child records in the $member member of $instance.
65
	 * @param object $instance
66
	 * @param string $member Member on which a oneToMany annotation must be present
67
	 * @param boolean $useCache
68
	 * @param array $annot used internally
69
	 */
70
	public static function getOneToMany($instance, $member, $useCache=NULL, $annot=null) {
71
		$ret=array ();
72
		$class=get_class($instance);
73
		if (!isset($annot))
74
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
75
			if ($annot !== false) {
76
				$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn", $annot["mappedBy"]);
77
				if ($fkAnnot !== false) {
78
					$fkv=OrmUtils::getFirstKeyValue($instance);
79
					$ret=self::getAll($annot["className"], $fkAnnot["name"] . "='" . $fkv . "'", true, false, $useCache);
80
					self::setToMember($member, $instance, $ret, $class, "getOneToMany");
81
				}
82
			}
83
			return $ret;
84
	}
85
86
	/**
87
	 * @param object $instance
88
	 * @param string $member
89
	 * @param array $array
90
	 * @param string $mappedBy
91
	 */
92
	public static function affectsOneToManyFromArray($instance, $member, $array=null, $mappedBy=null) {
93
		$ret=array ();
94
		$class=get_class($instance);
95
		if (!isset($mappedBy)){
96
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
97
			$mappedBy=$annot["mappedBy"];
98
		}
99
		if ($mappedBy !== false) {
100
				$fkv=OrmUtils::getFirstKeyValue($instance);
101
				self::_getOneToManyFromArray($ret, $array, $fkv, $mappedBy);
102
				self::setToMember($member, $instance, $ret, $class, "getOneToMany");
103
		}
104
		return $ret;
105
	}
106
107
	private static function setToMember($member, $instance, $value, $class, $part) {
108
		$accessor="set" . ucfirst($member);
109
		if (method_exists($instance, $accessor)) {
110
			Logger::log($part, "Affectation de " . $member . " pour l'objet " . $class);
111
			$instance->$accessor($value);
112
			$instance->_rest[$member]=$value;
113
		} else {
114
			Logger::warn($part, "L'accesseur " . $accessor . " est manquant pour " . $class);
115
		}
116
	}
117
118
	/**
119
	 * Assigns / loads the child records in the $member member of $instance.
120
	 * If $ array is null, the records are loaded from the database
121
	 * @param object $instance
122
	 * @param string $member Member on which a ManyToMany annotation must be present
123
	 * @param array $array optional parameter containing the list of possible child records
124
	 * @param boolean $useCache
125
	 */
126
	public static function getManyToMany($instance, $member,$array=null,$useCache=NULL){
127
		$ret=array ();
128
		$class=get_class($instance);
129
		$parser=new ManyToManyParser($instance, $member);
130
		if ($parser->init()) {
131
			if (is_null($array)) {
132
				$accessor="get" . ucfirst($parser->getMyPk());
133
				$condition=" INNER JOIN `" . $parser->getJoinTable() . "` on `".$parser->getJoinTable()."`.`".$parser->getFkField()."`=`".$parser->getTargetEntityTable()."`.`".$parser->getPk()."` WHERE `" . $parser->getMyFkField() . "`='" . $instance->$accessor() . "'";
134
				$ret=self::getAll($parser->getTargetEntityClass(),$condition,true,false,$useCache);
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
	public static function affectsManyToManys($instance,$array=NULL,$useCache=NULL){
0 ignored issues
show
Unused Code introduced by
The parameter $array is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
144
		$metaDatas=OrmUtils::getModelMetadata(\get_class($instance));
145
		$manyToManyFields=$metaDatas["#manyToMany"];
146
		if(\sizeof($manyToManyFields)>0){
147
			foreach ($manyToManyFields as $member){
148
				self::getManyToMany($instance, $member,null,$useCache);
149
			}
150
		}
151
	}
152
153
	private static function getManyToManyFromArray(&$ret, $instance, $array, $class, $parser) {
154
		$continue=true;
155
		$accessorToMember="get" . ucfirst($parser->getInversedBy());
156
		$myPkAccessor="get" . ucfirst($parser->getMyPk());
157
158
		if (!method_exists($instance, $myPkAccessor)) {
159
			Logger::warn("ManyToMany", "L'accesseur au membre clé primaire " . $myPkAccessor . " est manquant pour " . $class);
160
		}
161
		if (count($array) > 0)
162
			$continue=method_exists($array[0], $accessorToMember);
163
		if ($continue) {
164
			foreach ( $array as $targetEntityInstance ) {
165
				$instances=$targetEntityInstance->$accessorToMember();
166
				if (is_array($instances)) {
167
					foreach ( $instances as $inst ) {
168
						if ($inst->$myPkAccessor() == $instance->$myPkAccessor())
169
							array_push($ret, $targetEntityInstance);
170
					}
171
				}
172
			}
173
		} else {
174
			Logger::warn("ManyToMany", "L'accesseur au membre " . $parser->getInversedBy() . " est manquant pour " . $parser->getTargetEntity());
175
		}
176
	}
177
178
	/**
179
	 * Returns an array of $className objects from the database
180
	 * @param string $className class name of the model to load
181
	 * @param string $condition Part following the WHERE of an SQL statement
182
	 * @param boolean $loadManyToOne if true, charges associate members with manyToOne association
183
	 * @param boolean $loadOneToMany if true, charges associate members with oneToMany association
184
	 * @param boolean $useCache use the active cache if true
185
	 * @return array
186
	 */
187
	public static function getAll($className, $condition='', $loadManyToOne=true, $loadOneToMany=false,$useCache=NULL) {
188
		$objects=array ();
189
		$invertedJoinColumns=null;
190
		$oneToManyFields=null;
191
		$metaDatas=OrmUtils::getModelMetadata($className);
192
		$tableName=$metaDatas["#tableName"];
193
		if ($loadManyToOne && isset($metaDatas["#invertedJoinColumn"]))
194
			$invertedJoinColumns=$metaDatas["#invertedJoinColumn"];
195
		if ($loadOneToMany && isset($metaDatas["#oneToMany"])) {
196
			$oneToManyFields=$metaDatas["#oneToMany"];
197
		}
198
		$condition=SqlUtils::checkWhere($condition);
199
		$members=\array_diff($metaDatas["#fieldNames"],$metaDatas["#notSerializable"]);
200
		$query=self::$db->prepareAndExecute($tableName, $condition,$members,$useCache);
201
		Logger::log("getAll", "SELECT * FROM " . $tableName . $condition);
202
		$oneToManyQueries=[];
203
		$manyToOneQueries=[];
204
205
		foreach ( $query as $row ) {
206
			$object=self::loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields,$members, $oneToManyQueries,$manyToOneQueries);
207
			$key=OrmUtils::getFirstKeyValue($object);
208
			$objects[$key]=$object;
209
		}
210
211
		if($loadManyToOne && \sizeof($manyToOneQueries)>0){
212
			self::_affectsObjectsFromArray($manyToOneQueries, $objects, function($object,$member,$manyToOneObjects,$fkField){
213
				self::affectsManyToOneFromArray($object,$member,$manyToOneObjects,$fkField);
214
			});
215
		}
216
217
		if($loadOneToMany && \sizeof($oneToManyQueries)>0){
218
			self::_affectsObjectsFromArray($oneToManyQueries, $objects, function($object,$member,$relationObjects,$fkField){
219
				self::affectsOneToManyFromArray($object,$member,$relationObjects,$fkField);
220
			});
221
		}
222
		return $objects;
223
	}
224
225
	private static function _affectsObjectsFromArray($queries,$objects,$affectsCallback,$useCache=NULL){
226
		foreach ($queries as $key=>$conditions){
227
			list($class,$member,$fkField)=\explode("|", $key);
228
			$condition=\implode(" OR ", $conditions);
229
			$relationObjects=self::getAll($class,$condition,true,false,$useCache);
230
			foreach ($objects as $object){
231
				$affectsCallback($object, $member,$relationObjects,$fkField);
232
			}
233
		}
234
	}
235
236
	private static function affectsManyToOneFromArray($object,$member,$manyToOneObjects,$fkField){
237
		$class=\get_class($object);
238
		if(isset($object->$fkField)){
239
			$value=$manyToOneObjects[$object->$fkField];
240
			self::setToMember($member, $object, $value, $class, "getManyToOne");
241
		}
242
	}
243
244
	/**
245
	 * @param array $row
246
	 * @param string $className
247
	 * @param array $invertedJoinColumns
248
	 * @param array $oneToManyFields
249
	 * @param array $members
250
	 * @param array $oneToManyQueries
251
	 * @param array $manyToOneQueries
252
	 * @param boolean $useCache
0 ignored issues
show
Bug introduced by
There is no parameter named $useCache. 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...
253
	 * @return object
254
	 */
255
	private static function loadObjectFromRow($row, $className, $invertedJoinColumns, $oneToManyFields, $members,&$oneToManyQueries,&$manyToOneQueries) {
256
		$o=new $className();
257
		foreach ( $row as $k => $v ) {
258
			if(($field=\array_search($k, $members))!==false){
259
				$accesseur="set" . ucfirst($field);
260
				if (method_exists($o, $accesseur)) {
261
					$o->$accesseur($v);
262
					$o->_rest[$field]=$v;
263
				}
264
			}
265
			if (isset($invertedJoinColumns) && isset($invertedJoinColumns[$k])) {
266
				$fk="_".$k;
267
				$o->$fk=$v;
268
				self::prepareManyToOne($manyToOneQueries,$v, $fk,$invertedJoinColumns[$k]);
269
			}
270
		}
271
		if (isset($oneToManyFields)) {
272
			foreach ( $oneToManyFields as $k => $annot ) {
273
				self::prepareOneToMany($oneToManyQueries,$o, $k, $annot);
274
			}
275
		}
276
		return $o;
277
	}
278
279
280
	/**
281
	 * Prepares members associated with $instance with a oneToMany type relationship
282
	 * @param $ret array of sql conditions
283
	 * @param object $instance
284
	 * @param string $member Member on which a OneToMany annotation must be present
285
	 * @param array $annot used internally
286
	 */
287
	private static function prepareOneToMany(&$ret,$instance, $member, $annot=null) {
288
		$class=get_class($instance);
289
		if (!isset($annot))
290
			$annot=OrmUtils::getAnnotationInfoMember($class, "#oneToMany", $member);
291
			if ($annot !== false) {
292
				$fkAnnot=OrmUtils::getAnnotationInfoMember($annot["className"], "#joinColumn", $annot["mappedBy"]);
293
				if ($fkAnnot !== false) {
294
					$fkv=OrmUtils::getFirstKeyValue($instance);
295
					$key=$annot["className"]."|".$member."|".$annot["mappedBy"];
296
					if(!isset($ret[$key])){
297
						$ret[$key]=[];
298
					}
299
					$ret[$key][$fkv]=$fkAnnot["name"] . "='" . $fkv . "'";
300
				}
301
			}
302
	}
303
304
	/**
305
	 * Prepares members associated with $instance with a manyToOne type relationship
306
	 * @param $ret array of sql conditions
307
	 * @param mixed $value
308
	 * @param string $fkField
309
	 * @param array $annotationArray
310
	 */
311
	private static function prepareManyToOne(&$ret, $value, $fkField,$annotationArray) {
312
		$member=$annotationArray["member"];
313
		$fk=OrmUtils::getFirstKey($annotationArray["className"]);
314
		$key=$annotationArray["className"]."|".$member."|".$fkField;
315
		if(!isset($ret[$key])){
316
			$ret[$key]=[];
317
		}
318
		$ret[$key][$value]=$fk . "='" . $value . "'";
319
	}
320
321
	/**
322
	 * Returns the number of objects of $className from the database respecting the condition possibly passed as parameter
323
	 * @param string $className complete classname of the model to load
324
	 * @param string $condition Part following the WHERE of an SQL statement
325
	 * @return int count of objects
326
	 */
327
	public static function count($className, $condition='') {
328
		$tableName=OrmUtils::getTableName($className);
329
		if ($condition != '')
330
			$condition=" WHERE " . $condition;
331
		return self::$db->query("SELECT COUNT(*) FROM " . $tableName . $condition)->fetchColumn();
332
	}
333
334
	/**
335
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key
336
	 * @param String $className complete classname of the model to load
337
	 * @param Array|string $keyValues primary key values or condition
338
	 * @param $loadManyToOne if true, charges associate members with manyToOne association
339
	 * @param $loadOneToMany if true, charges associate members with oneToMany association
340
	 * @param boolean $useCache use cache if true
341
	 * @return object the instance loaded or null if not found
342
	 */
343
	public static function getOne($className, $keyValues, $loadManyToOne=true, $loadOneToMany=false, $useCache=NULL) {
344
		if (!is_array($keyValues)) {
345
			if (strrpos($keyValues, "=") === false) {
346
				$keyValues="`" . OrmUtils::getFirstKey($className) . "`='" . $keyValues . "'";
347
			}
348
		}
349
		$condition=SqlUtils::getCondition($keyValues,$className);
350
		$retour=self::getAll($className, $condition." limit 1", $loadManyToOne, $loadOneToMany,$useCache);
351
		if (sizeof($retour) < 1){
352
			return null;
353
		}
354
		return \reset($retour);
355
	}
356
357
	/**
358
	 * Establishes the connection to the database using the past parameters
359
	 * @param string $dbType
360
	 * @param string $dbName
361
	 * @param string $serverName
362
	 * @param string $port
363
	 * @param string $user
364
	 * @param string $password
365
	 * @param array $options
366
	 * @param boolean $cache
367
	 */
368
	public static function connect($dbType,$dbName, $serverName="127.0.0.1", $port="3306", $user="root", $password="", $options=[],$cache=false) {
369
		self::$db=new Database($dbType,$dbName, $serverName, $port, $user, $password, $options,$cache);
370
		try {
371
			self::$db->connect();
372
		} catch (\Exception $e) {
373
			Logger::error("DAO", $e->getMessage());
374
			throw $e;
375
		}
376
	}
377
378
	/**
379
	 * Returns true if the connection to the database is estabished
380
	 * @return boolean
381
	 */
382
	public static function isConnected(){
383
		return self::$db!==null && (self::$db instanceof Database) && self::$db->isConnected();
384
	}
385
}
386