Completed
Push — master ( 61f3b2...32110c )
by Jean-Christophe
02:56
created

DAO::loadObjectFromRow()   C

Complexity

Conditions 11
Paths 20

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 30
rs 5.2653
c 2
b 0
f 0
cc 11
eloc 20
nc 20
nop 9

How to fix   Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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