Passed
Push — master ( 64da0c...c6d718 )
by Jean-Christophe
11:31
created

DAO   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 334
Duplicated Lines 0 %

Test Coverage

Coverage 79.56%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 55
eloc 119
c 6
b 0
f 0
dl 0
loc 334
ccs 109
cts 137
cp 0.7956
rs 6

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getAll() 0 2 1
A paginate() 0 5 2
A getRownum() 0 11 2
A affectsManyToManys() 0 6 3
A getManyToMany() 0 17 5
A getConditionParser() 0 9 2
A startDatabase() 0 4 3
A getById() 0 2 1
A isConnected() 0 3 3
A getDbOffset() 0 2 2
A closeDb() 0 4 2
A getManyToOne() 0 21 6
A start() 0 2 1
A setModelDatabase() 0 2 1
A setTransformerOp() 0 2 1
A getDatabase() 0 5 2
A connect() 0 7 2
A getOne() 0 11 3
A count() 0 6 2
A getDatabases() 0 10 3
A getDb() 0 2 1
A setModelsDatabases() 0 2 1
A getOneToMany() 0 17 6

How to fix   Complexity   

Complex Class

Complex classes like DAO often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DAO, and based on these observations, apply Extract Interface, too.

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\traits\DAOUpdatesTrait;
10
use Ubiquity\orm\traits\DAORelationsTrait;
11
use Ubiquity\orm\parser\ConditionParser;
12
use Ubiquity\orm\traits\DAOUQueries;
13
use Ubiquity\orm\traits\DAOCoreTrait;
14
use Ubiquity\orm\traits\DAORelationsPrepareTrait;
15
use Ubiquity\exceptions\DAOException;
16
use Ubiquity\orm\traits\DAORelationsAssignmentsTrait;
17
use Ubiquity\orm\parser\Reflexion;
18
use Ubiquity\orm\traits\DAOTransactionsTrait;
19
use Ubiquity\controllers\Startup;
20
use Ubiquity\cache\CacheManager;
21
22
/**
23
 * Gateway class between database and object model.
24
 * This class is part of Ubiquity
25
 *
26
 * @author jcheron <[email protected]>
27
 * @version 1.2.1
28
 *
29
 */
30
class DAO {
31
	use DAOCoreTrait,DAOUpdatesTrait,DAORelationsTrait,DAORelationsPrepareTrait,DAORelationsAssignmentsTrait,DAOUQueries,DAOTransactionsTrait;
32
33
	/**
34
	 *
35
	 * @var Database
36
	 */
37
	public static $db;
38
	public static $useTransformers = false;
39
	public static $transformerOp = 'transform';
40
	private static $conditionParsers = [ ];
41
	protected static $modelsDatabase = [ ];
42
43 67
	protected static function getDb($model) {
44 67
		return self::getDatabase ( self::$modelsDatabase [$model] ?? 'default');
45
	}
46
47
	/**
48
	 * Loads member associated with $instance by a ManyToOne relationship
49
	 *
50
	 * @param object|array $instance The instance object or an array with [classname,id]
51
	 * @param string $member The member to load
52
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
53
	 * @param boolean|null $useCache
54
	 */
55 4
	public static function getManyToOne($instance, $member, $included = false, $useCache = NULL) {
56 4
		$classname = self::getClass_ ( $instance );
57 4
		if (is_array ( $instance )) {
58 1
			$instance = self::getById ( $classname, $instance [1], false, $useCache );
59
		}
60 4
		$fieldAnnot = OrmUtils::getMemberJoinColumns ( $classname, $member );
61 4
		if ($fieldAnnot !== null) {
62 4
			$annotationArray = $fieldAnnot [1];
63 4
			$member = $annotationArray ["member"];
64 4
			$value = Reflexion::getMemberValue ( $instance, $member );
65 4
			$key = OrmUtils::getFirstKey ( $annotationArray ["className"] );
66 4
			$kv = array ($key => $value );
67 4
			$obj = self::getById ( $annotationArray ["className"], $kv, $included, $useCache );
68 4
			if ($obj !== null) {
69 4
				Logger::info ( "DAO", "Loading the member " . $member . " for the object " . $classname, "getManyToOne" );
70 4
				$accesseur = "set" . ucfirst ( $member );
71 4
				if (is_object ( $instance ) && method_exists ( $instance, $accesseur )) {
72 4
					$instance->$accesseur ( $obj );
73 4
					$instance->_rest [$member] = $obj->_rest;
74
				}
75 4
				return $obj;
76
			}
77
		}
78
	}
79
80
	/**
81
	 * Assign / load the child records in the $member member of $instance.
82
	 *
83
	 * @param object|array $instance The instance object or an array with [classname,id]
84
	 * @param string $member Member on which a oneToMany annotation must be present
85
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
86
	 * @param boolean $useCache
87
	 * @param array $annot used internally
88
	 */
89 7
	public static function getOneToMany($instance, $member, $included = true, $useCache = NULL, $annot = null) {
90 7
		$ret = array ();
91 7
		$class = self::getClass_ ( $instance );
92 7
		if (! isset ( $annot )) {
93 7
			$annot = OrmUtils::getAnnotationInfoMember ( $class, "#oneToMany", $member );
94
		}
95 7
		if ($annot !== false) {
96 7
			$fkAnnot = OrmUtils::getAnnotationInfoMember ( $annot ["className"], "#joinColumn", $annot ["mappedBy"] );
97 7
			if ($fkAnnot !== false) {
98 7
				$fkv = self::getFirstKeyValue_ ( $instance );
99 7
				$ret = self::_getAll ( $annot ["className"], ConditionParser::simple ( $fkAnnot ["name"] . "= ?", $fkv ), $included, $useCache );
100 7
				if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getOneToMany' )) {
101 6
					self::setToMember ( $member, $instance, $ret, $modifier );
102
				}
103
			}
104
		}
105 7
		return $ret;
106
	}
107
108
	/**
109
	 * Assigns / loads the child records in the $member member of $instance.
110
	 * If $array is null, the records are loaded from the database
111
	 *
112
	 * @param object|array $instance The instance object or an array with [classname,id]
113
	 * @param string $member Member on which a ManyToMany annotation must be present
114
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
115
	 * @param array $array optional parameter containing the list of possible child records
116
	 * @param boolean $useCache
117
	 */
118 4
	public static function getManyToMany($instance, $member, $included = false, $array = null, $useCache = NULL) {
119 4
		$ret = [ ];
120 4
		$class = self::getClass_ ( $instance );
121 4
		$parser = new ManyToManyParser ( $class, $member );
122 4
		if ($parser->init ()) {
123 4
			if (is_null ( $array )) {
124 4
				$pk = self::getFirstKeyValue_ ( $instance );
125 4
				$condition = " INNER JOIN `" . $parser->getJoinTable () . "` on `" . $parser->getJoinTable () . "`.`" . $parser->getFkField () . "`=`" . $parser->getTargetEntityTable () . "`.`" . $parser->getPk () . "` WHERE `" . $parser->getJoinTable () . "`.`" . $parser->getMyFkField () . "`= ?";
126 4
				$ret = self::_getAll ( $parser->getTargetEntityClass (), ConditionParser::simple ( $condition, $pk ), $included, $useCache );
127
			} else {
128
				$ret = self::getManyToManyFromArray ( $instance, $array, $class, $parser );
129
			}
130 4
			if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getManyToMany' )) {
131 3
				self::setToMember ( $member, $instance, $ret, $modifier );
132
			}
133
		}
134 4
		return $ret;
135
	}
136
137
	/**
138
	 *
139
	 * @param object $instance
140
	 * @param array $array
141
	 * @param boolean $useCache
142
	 */
143
	public static function affectsManyToManys($instance, $array = NULL, $useCache = NULL) {
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, false, $array, $useCache );
149
			}
150
		}
151
	}
152
153
	/**
154
	 * Returns an array of $className objects from the database
155
	 *
156
	 * @param string $className class name of the model to load
157
	 * @param string $condition Part following the WHERE of an SQL statement
158
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
159
	 * @param array|null $parameters
160
	 * @param boolean $useCache use the active cache if true
161
	 * @return array
162
	 */
163 24
	public static function getAll($className, $condition = '', $included = true, $parameters = null, $useCache = NULL) {
164 24
		return self::_getAll ( $className, new ConditionParser ( $condition, null, $parameters ), $included, $useCache );
165
	}
166
167 3
	public static function paginate($className, $page = 1, $rowsPerPage = 20, $condition = null, $included = true) {
168 3
		if (! isset ( $condition )) {
169 1
			$condition = "1=1";
170
		}
171 3
		return self::getAll ( $className, $condition . " LIMIT " . $rowsPerPage . " OFFSET " . (($page - 1) * $rowsPerPage), $included );
172
	}
173
174 3
	public static function getRownum($className, $ids) {
175 3
		$tableName = OrmUtils::getTableName ( $className );
176 3
		self::parseKey ( $ids, $className );
177 3
		$condition = SqlUtils::getCondition ( $ids, $className );
178 3
		$keyFields = OrmUtils::getKeyFields ( $className );
179 3
		if (is_array ( $keyFields )) {
180 3
			$keys = implode ( ",", $keyFields );
181
		} else {
182
			$keys = "1";
183
		}
184 3
		return self::getDb ( $className )->queryColumn ( "SELECT num FROM (SELECT *, @rownum:=@rownum + 1 AS num FROM `{$tableName}`, (SELECT @rownum:=0) r ORDER BY {$keys}) d WHERE " . $condition );
185
	}
186
187
	/**
188
	 * Returns the number of objects of $className from the database respecting the condition possibly passed as parameter
189
	 *
190
	 * @param string $className complete classname of the model to load
191
	 * @param string $condition Part following the WHERE of an SQL statement
192
	 * @param array|null $parameters The query parameters
193
	 * @return int|false count of objects
194
	 */
195 21
	public static function count($className, $condition = '', $parameters = null) {
196 21
		$tableName = OrmUtils::getTableName ( $className );
197 21
		if ($condition != '') {
198 10
			$condition = " WHERE " . $condition;
199
		}
200 21
		return self::getDb ( $className )->prepareAndFetchColumn ( "SELECT COUNT(*) FROM `" . $tableName . "`" . $condition, $parameters );
201
	}
202
203
	/**
204
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key or with a condition
205
	 *
206
	 * @param String $className complete classname of the model to load
207
	 * @param Array|string $condition condition or primary key values
208
	 * @param boolean|array $included if true, charges associate members with association
209
	 * @param array|null $parameters the request parameters
210
	 * @param boolean|null $useCache use cache if true
211
	 * @return object the instance loaded or null if not found
212
	 */
213 16
	public static function getOne($className, $condition, $included = true, $parameters = null, $useCache = NULL) {
214 16
		$conditionParser = new ConditionParser ();
215 16
		if (! isset ( $parameters )) {
216 16
			$conditionParser->addKeyValues ( $condition, $className );
217
		} elseif (! is_array ( $condition )) {
218
			$conditionParser->setCondition ( $condition );
219
			$conditionParser->setParams ( $parameters );
220
		} else {
221
			throw new DAOException ( "The \$keyValues parameter should not be an array if \$parameters is not null" );
222
		}
223 16
		return self::_getOne ( $className, $conditionParser, $included, $useCache );
224
	}
225
226
	/**
227
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key
228
	 *
229
	 * @param String $className complete classname of the model to load
230
	 * @param Array|string $keyValues primary key values or condition
231
	 * @param boolean|array $included if true, charges associate members with association
232
	 * @param array|null $parameters the request parameters
233
	 * @param boolean|null $useCache use cache if true
234
	 * @return object the instance loaded or null if not found
235
	 */
236 21
	public static function getById($className, $keyValues, $included = true, $useCache = NULL) {
237 21
		return self::_getOne ( $className, self::getConditionParser ( $className, $keyValues ), $included, $useCache );
238
	}
239
240 21
	protected static function getConditionParser($className, $keyValues) {
241 21
		if (! isset ( self::$conditionParsers [$className] )) {
242 14
			$conditionParser = new ConditionParser ();
243 14
			$conditionParser->addKeyValues ( $keyValues, $className );
244 14
			self::$conditionParsers [$className] = $conditionParser;
245
		} else {
246 9
			self::$conditionParsers [$className]->setKeyValues ( $keyValues );
247
		}
248 21
		return self::$conditionParsers [$className];
249
	}
250
251
	/**
252
	 * Establishes the connection to the database using the past parameters
253
	 *
254
	 * @param string $dbType
255
	 * @param string $dbName
256
	 * @param string $serverName
257
	 * @param string $port
258
	 * @param string $user
259
	 * @param string $password
260
	 * @param array $options
261
	 * @param boolean $cache
262
	 */
263 65
	public static function connect($offset, $dbType, $dbName, $serverName = '127.0.0.1', $port = '3306', $user = 'root', $password = '', $options = [], $cache = false) {
264 65
		self::$db [$offset] = new Database ( $dbType, $dbName, $serverName, $port, $user, $password, $options, $cache );
265
		try {
266 65
			self::$db [$offset]->connect ();
267
		} catch ( \Exception $e ) {
268
			Logger::error ( "DAO", $e->getMessage () );
269
			throw new DAOException ( $e->getMessage (), $e->getCode (), $e->getPrevious () );
270
		}
271 65
	}
272
273
	/**
274
	 * Establishes the connection to the database using the $config array
275
	 *
276
	 * @param array $config the config array (Startup::getConfig())
277
	 */
278 21
	public static function startDatabase(&$config, $offset = null) {
279 21
		$db = $offset ? ($config ['database'] [$offset] ?? ($config ['database'] ?? [ ])) : ($config ['database'] ['default'] ?? $config ['database']);
280 21
		if ($db ['dbName'] !== '') {
281 21
			self::connect ( $offset ?? 'default', $db ['type'], $db ['dbName'], $db ['serverName'] ?? '127.0.0.1', $db ['port'] ?? 3306, $db ['user'] ?? 'root', $db ['password'] ?? '', $db ['options'] ?? [ ], $db ['cache'] ?? false);
282
		}
283 21
	}
284
285 45
	public static function getDbOffset(&$config, $offset = null) {
286 45
		return $offset ? ($config ['database'] [$offset] ?? ($config ['database'] ?? [ ])) : ($config ['database'] ['default'] ?? $config ['database']);
287
	}
288
289
	/**
290
	 * Returns true if the connection to the database is established
291
	 *
292
	 * @return boolean
293
	 */
294 4
	public static function isConnected($offset = 'default') {
295 4
		$db = self::$db [$offset] ?? false;
296 4
		return $db && ($db instanceof Database) && $db->isConnected ();
297
	}
298
299
	/**
300
	 * Sets the transformer operation
301
	 *
302
	 * @param string $op
303
	 */
304
	public static function setTransformerOp($op) {
305
		self::$transformerOp = $op;
306
	}
307
308
	/**
309
	 * Closes the active pdo connection to the database
310
	 */
311 23
	public static function closeDb($offset = 'default') {
312 23
		$db = self::$db [$offset] ?? false;
313 23
		if ($db !== false) {
314 23
			$db->close ();
315
		}
316 23
	}
317
318
	/**
319
	 * Defines the database connection to use for $model class
320
	 *
321
	 * @param string $model a model class
322
	 * @param string $database a database connection defined in config.php
323
	 */
324
	public static function setModelDatabase($model, $database = 'default') {
325
		self::$modelsDatabase [$model] = $database;
326
	}
327
328
	/**
329
	 * Defines the database connections to use for models classes
330
	 *
331
	 * @param array $modelsDatabase
332
	 */
333
	public static function setModelsDatabases($modelsDatabase) {
334
		self::$modelsDatabase = $modelsDatabase;
335
	}
336
337
	/**
338
	 * Returns the database instance defined at $offset key in config
339
	 *
340
	 * @param string $offset
341
	 * @return \Ubiquity\db\Database
342
	 */
343 67
	public static function getDatabase($offset = 'default') {
344 67
		if (! isset ( self::$db [$offset] )) {
345 20
			self::startDatabase ( Startup::$config, $offset );
346
		}
347 67
		return self::$db [$offset];
348
	}
349
350 3
	public static function getDatabases() {
351 3
		$config = Startup::getConfig ();
352 3
		if (isset ( $config ['database'] )) {
353 3
			if (isset ( $config ['database'] ['dbName'] )) {
354 3
				return [ 'default' ];
355
			} else {
356
				return \array_keys ( $config ['database'] );
357
			}
358
		}
359
		return [ ];
360
	}
361
362 38
	public static function start() {
363 38
		self::$modelsDatabase = CacheManager::getModelsDatabases ();
364 38
	}
365
}
366