Passed
Push — master ( caa32e...4f267a )
by Jean-Christophe
09:15
created

DAO::connect()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.5

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 6
c 2
b 0
f 0
dl 0
loc 7
ccs 3
cts 6
cp 0.5
rs 10
cc 2
nc 2
nop 10
crap 2.5

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\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
	private static $pool;
42
	protected static $modelsDatabase = [ ];
43
44 67
	protected static function getDb($model) {
45 67
		return self::getDatabase ( self::$modelsDatabase [$model] ?? 'default');
46
	}
47
48
	/**
49
	 * Initialize pooling (To invoke during Swoole startup)
50
	 *
51
	 * @param array $config
52
	 * @param ?string $offset
53
	 */
54
	public static function initPooling(&$config, $offset = null) {
55
		$dbConfig = self::getDbOffset ( $config, $offset );
56
		$wrapperClass = $dbConfig ['wrapper'] ?? \Ubiquity\db\providers\pdo\PDOWrapper::class;
57
		if (\method_exists ( $wrapperClass, 'getPoolClass' )) {
58
			$poolClass = \call_user_func ( $wrapperClass . '::getPoolClass' );
1 ignored issue
show
Bug introduced by
Are you sure $wrapperClass of type object can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

58
			$poolClass = \call_user_func ( /** @scrutinizer ignore-type */ $wrapperClass . '::getPoolClass' );
Loading history...
59
			if (\class_exists ( $poolClass, true )) {
60
				self::$pool = new $poolClass ( $config, $offset );
61
			} else {
62
				throw new DAOException ( $poolClass . ' class does not exists!' );
63
			}
64
		} else {
65
			throw new DAOException ( $wrapperClass . ' does not support connection pooling!' );
66
		}
67
		self::$db [$offset] = self::startDatabase ( $config, $offset );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to self::db[$offset] is correct as self::startDatabase($config, $offset) targeting Ubiquity\orm\DAO::startDatabase() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
68
	}
69
70
	/**
71
	 * Loads member associated with $instance by a ManyToOne relationship
72
	 *
73
	 * @param object|array $instance The instance object or an array with [classname,id]
74
	 * @param string $member The member to load
75
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
76
	 * @param boolean|null $useCache
77
	 */
78 4
	public static function getManyToOne($instance, $member, $included = false, $useCache = NULL) {
79 4
		$classname = self::getClass_ ( $instance );
80 4
		if (is_array ( $instance )) {
81 1
			$instance = self::getById ( $classname, $instance [1], false, $useCache );
82
		}
83 4
		$fieldAnnot = OrmUtils::getMemberJoinColumns ( $classname, $member );
84 4
		if ($fieldAnnot !== null) {
85 4
			$annotationArray = $fieldAnnot [1];
86 4
			$member = $annotationArray ["member"];
87 4
			$value = Reflexion::getMemberValue ( $instance, $member );
88 4
			$key = OrmUtils::getFirstKey ( $annotationArray ["className"] );
89 4
			$kv = array ($key => $value );
90 4
			$obj = self::getById ( $annotationArray ["className"], $kv, $included, $useCache );
91 4
			if ($obj !== null) {
92 4
				Logger::info ( "DAO", "Loading the member " . $member . " for the object " . $classname, "getManyToOne" );
93 4
				$accesseur = "set" . ucfirst ( $member );
94 4
				if (is_object ( $instance ) && method_exists ( $instance, $accesseur )) {
95 4
					$instance->$accesseur ( $obj );
96 4
					$instance->_rest [$member] = $obj->_rest;
97
				}
98 4
				return $obj;
99
			}
100
		}
101
	}
102
103
	/**
104
	 * Assign / load the child records in the $member member of $instance.
105
	 *
106
	 * @param object|array $instance The instance object or an array with [classname,id]
107
	 * @param string $member Member on which a oneToMany annotation must be present
108
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
109
	 * @param boolean $useCache
110
	 * @param array $annot used internally
111
	 */
112 7
	public static function getOneToMany($instance, $member, $included = true, $useCache = NULL, $annot = null) {
113 7
		$ret = array ();
114 7
		$class = self::getClass_ ( $instance );
115 7
		if (! isset ( $annot )) {
116 7
			$annot = OrmUtils::getAnnotationInfoMember ( $class, "#oneToMany", $member );
117
		}
118 7
		if ($annot !== false) {
119 7
			$fkAnnot = OrmUtils::getAnnotationInfoMember ( $annot ["className"], "#joinColumn", $annot ["mappedBy"] );
120 7
			if ($fkAnnot !== false) {
121 7
				$fkv = self::getFirstKeyValue_ ( $instance );
122 7
				$db = self::getDb ( $annot ["className"] );
123 7
				$ret = self::_getAll ( $db, $annot ["className"], ConditionParser::simple ( $db->quote . $fkAnnot ["name"] . $db->quote . "= ?", $fkv ), $included, $useCache );
124 7
				if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getOneToMany' )) {
125 6
					self::setToMember ( $member, $instance, $ret, $modifier );
126
				}
127
			}
128
		}
129 7
		return $ret;
130
	}
131
132
	/**
133
	 * Assigns / loads the child records in the $member member of $instance.
134
	 * If $array is null, the records are loaded from the database
135
	 *
136
	 * @param object|array $instance The instance object or an array with [classname,id]
137
	 * @param string $member Member on which a ManyToMany annotation must be present
138
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
139
	 * @param array $array optional parameter containing the list of possible child records
140
	 * @param boolean $useCache
141
	 */
142 4
	public static function getManyToMany($instance, $member, $included = false, $array = null, $useCache = NULL) {
143 4
		$ret = [ ];
144 4
		$class = self::getClass_ ( $instance );
145 4
		$parser = new ManyToManyParser ( $class, $member );
146 4
		if ($parser->init ()) {
147 4
			if (is_null ( $array )) {
148 4
				$pk = self::getFirstKeyValue_ ( $instance );
149 4
				$quote = SqlUtils::$quote;
150 4
				$condition = " INNER JOIN " . $quote . $parser->getJoinTable () . $quote . " on " . $quote . $parser->getJoinTable () . $quote . "." . $quote . $parser->getFkField () . $quote . "=" . $quote . $parser->getTargetEntityTable () . $quote . "." . $quote . $parser->getPk () . $quote . " WHERE " . $quote . $parser->getJoinTable () . $quote . "." . $quote . $parser->getMyFkField () . $quote . "= ?";
151 4
				$targetEntityClass = $parser->getTargetEntityClass ();
152 4
				$ret = self::_getAll ( self::getDb ( $targetEntityClass ), $targetEntityClass, ConditionParser::simple ( $condition, $pk ), $included, $useCache );
153
			} else {
154
				$ret = self::getManyToManyFromArray ( $instance, $array, $class, $parser );
155
			}
156 4
			if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getManyToMany' )) {
157 3
				self::setToMember ( $member, $instance, $ret, $modifier );
158
			}
159
		}
160 4
		return $ret;
161
	}
162
163
	/**
164
	 *
165
	 * @param object $instance
166
	 * @param array $array
167
	 * @param boolean $useCache
168
	 */
169
	public static function affectsManyToManys($instance, $array = NULL, $useCache = NULL) {
170
		$metaDatas = OrmUtils::getModelMetadata ( \get_class ( $instance ) );
171
		$manyToManyFields = $metaDatas ["#manyToMany"];
172
		if (\sizeof ( $manyToManyFields ) > 0) {
173
			foreach ( $manyToManyFields as $member ) {
174
				self::getManyToMany ( $instance, $member, false, $array, $useCache );
175
			}
176
		}
177
	}
178
179
	/**
180
	 * Returns an array of $className objects from the database
181
	 *
182
	 * @param string $className class name of the model to load
183
	 * @param string $condition Part following the WHERE of an SQL statement
184
	 * @param boolean|array $included if true, loads associate members with associations, if array, example : ["client.*","commands"]
185
	 * @param array|null $parameters
186
	 * @param boolean $useCache use the active cache if true
187
	 * @return array
188
	 */
189 23
	public static function getAll($className, $condition = '', $included = true, $parameters = null, $useCache = NULL) {
190 23
		return self::_getAll ( self::getDb ( $className ), $className, new ConditionParser ( $condition, null, $parameters ), $included, $useCache );
191
	}
192
193 3
	public static function paginate($className, $page = 1, $rowsPerPage = 20, $condition = null, $included = true) {
194 3
		if (! isset ( $condition )) {
195 1
			$condition = "1=1";
196
		}
197 3
		return self::getAll ( $className, $condition . " LIMIT " . $rowsPerPage . " OFFSET " . (($page - 1) * $rowsPerPage), $included );
198
	}
199
200 3
	public static function getRownum($className, $ids) {
201 3
		$tableName = OrmUtils::getTableName ( $className );
202 3
		$db = self::getDb ( $className );
203 3
		$quote = $db->quote;
204 3
		self::parseKey ( $ids, $className, $quote );
205 3
		$condition = SqlUtils::getCondition ( $ids, $className );
206 3
		$keyFields = OrmUtils::getKeyFields ( $className );
207 3
		if (is_array ( $keyFields )) {
208 3
			$keys = implode ( ",", $keyFields );
209
		} else {
210
			$keys = "1";
211
		}
212
213 3
		return $db->queryColumn ( "SELECT num FROM (SELECT *, @rownum:=@rownum + 1 AS num FROM {$quote}{$tableName}{$quote}, (SELECT @rownum:=0) r ORDER BY {$keys}) d WHERE " . $condition );
214
	}
215
216
	/**
217
	 * Returns the number of objects of $className from the database respecting the condition possibly passed as parameter
218
	 *
219
	 * @param string $className complete classname of the model to load
220
	 * @param string $condition Part following the WHERE of an SQL statement
221
	 * @param array|null $parameters The query parameters
222
	 * @return int|false count of objects
223
	 */
224 21
	public static function count($className, $condition = '', $parameters = null) {
225 21
		$tableName = OrmUtils::getTableName ( $className );
226 21
		if ($condition != '') {
227 9
			$condition = " WHERE " . $condition;
228
		}
229 21
		$db = self::getDb ( $className );
230 21
		$quote = $db->quote;
231 21
		return $db->prepareAndFetchColumn ( "SELECT COUNT(*) FROM " . $quote . $tableName . $quote . $condition, $parameters );
232
	}
233
234
	/**
235
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key or with a condition
236
	 *
237
	 * @param String $className complete classname of the model to load
238
	 * @param Array|string $condition condition or primary key values
239
	 * @param boolean|array $included if true, charges associate members with association
240
	 * @param array|null $parameters the request parameters
241
	 * @param boolean|null $useCache use cache if true
242
	 * @return object the instance loaded or null if not found
243
	 */
244 16
	public static function getOne($className, $condition, $included = true, $parameters = null, $useCache = NULL) {
245 16
		$conditionParser = new ConditionParser ();
246 16
		if (! isset ( $parameters )) {
247 16
			$conditionParser->addKeyValues ( $condition, $className );
248
		} elseif (! is_array ( $condition )) {
249
			$conditionParser->setCondition ( $condition );
250
			$conditionParser->setParams ( $parameters );
251
		} else {
252
			throw new DAOException ( "The \$keyValues parameter should not be an array if \$parameters is not null" );
253
		}
254 16
		return self::_getOne ( self::getDb ( $className ), $className, $conditionParser, $included, $useCache );
255
	}
256
257
	/**
258
	 * Returns an instance of $className from the database, from $keyvalues values of the primary key
259
	 *
260
	 * @param String $className complete classname of the model to load
261
	 * @param Array|string $keyValues primary key values or condition
262
	 * @param boolean|array $included if true, charges associate members with association
263
	 * @param array|null $parameters the request parameters
264
	 * @param boolean|null $useCache use cache if true
265
	 * @return object the instance loaded or null if not found
266
	 */
267 21
	public static function getById($className, $keyValues, $included = true, $useCache = NULL) {
268 21
		return self::_getOne ( self::getDb ( $className ), $className, self::getConditionParser ( $className, $keyValues ), $included, $useCache );
269
	}
270
271 21
	protected static function getConditionParser($className, $keyValues) {
272 21
		if (! isset ( self::$conditionParsers [$className] )) {
273 14
			$conditionParser = new ConditionParser ();
274 14
			$conditionParser->addKeyValues ( $keyValues, $className );
275 14
			self::$conditionParsers [$className] = $conditionParser;
276
		} else {
277 9
			self::$conditionParsers [$className]->setKeyValues ( $keyValues );
278
		}
279 21
		return self::$conditionParsers [$className];
280
	}
281
282
	/**
283
	 * Establishes the connection to the database using the past parameters
284
	 *
285
	 * @param string $offset
286
	 * @param string $wrapper
287
	 * @param string $dbType
288
	 * @param string $dbName
289
	 * @param string $serverName
290
	 * @param string $port
291
	 * @param string $user
292
	 * @param string $password
293
	 * @param array $options
294
	 * @param boolean $cache
295
	 */
296 65
	public static function connect($offset, $wrapper, $dbType, $dbName, $serverName = '127.0.0.1', $port = '3306', $user = 'root', $password = '', $options = [], $cache = false) {
297 65
		self::$db [$offset] = new Database ( $wrapper, $dbType, $dbName, $serverName, $port, $user, $password, $options, $cache, self::$pool );
298
		try {
299 65
			self::$db [$offset]->connect ();
300
		} catch ( \Exception $e ) {
301
			Logger::error ( "DAO", $e->getMessage () );
302
			throw new DAOException ( $e->getMessage (), $e->getCode (), $e->getPrevious () );
303
		}
304 65
	}
305
306
	/**
307
	 * Establishes the connection to the database using the $config array
308
	 *
309
	 * @param array $config the config array (Startup::getConfig())
310
	 */
311 21
	public static function startDatabase(&$config, $offset = null) {
312 21
		$db = $offset ? ($config ['database'] [$offset] ?? ($config ['database'] ?? [ ])) : ($config ['database'] ['default'] ?? $config ['database']);
313 21
		if ($db ['dbName'] !== '') {
314 21
			self::connect ( $offset ?? 'default', $db ['wrapper'] ?? \Ubiquity\db\providers\pdo\PDOWrapper::class, $db ['type'], $db ['dbName'], $db ['serverName'] ?? '127.0.0.1', $db ['port'] ?? 3306, $db ['user'] ?? 'root', $db ['password'] ?? '', $db ['options'] ?? [ ], $db ['cache'] ?? false);
315
		}
316 21
	}
317
318 110
	public static function getDbOffset(&$config, $offset = null) {
319 110
		return $offset ? ($config ['database'] [$offset] ?? ($config ['database'] ?? [ ])) : ($config ['database'] ['default'] ?? $config ['database']);
320
	}
321
322
	/**
323
	 * Returns true if the connection to the database is established
324
	 *
325
	 * @return boolean
326
	 */
327 5
	public static function isConnected($offset = 'default') {
328 5
		$db = self::$db [$offset] ?? false;
329 5
		return $db && ($db instanceof Database) && $db->isConnected ();
330
	}
331
332
	/**
333
	 * Sets the transformer operation
334
	 *
335
	 * @param string $op
336
	 */
337
	public static function setTransformerOp($op) {
338
		self::$transformerOp = $op;
339
	}
340
341
	/**
342
	 * Closes the active pdo connection to the database
343
	 */
344 23
	public static function closeDb($offset = 'default') {
345 23
		$db = self::$db [$offset] ?? false;
346 23
		if ($db !== false) {
347 23
			$db->close ();
348
		}
349 23
	}
350
351
	/**
352
	 * Defines the database connection to use for $model class
353
	 *
354
	 * @param string $model a model class
355
	 * @param string $database a database connection defined in config.php
356
	 */
357
	public static function setModelDatabase($model, $database = 'default') {
358
		self::$modelsDatabase [$model] = $database;
359
	}
360
361
	/**
362
	 * Defines the database connections to use for models classes
363
	 *
364
	 * @param array $modelsDatabase
365
	 */
366
	public static function setModelsDatabases($modelsDatabase) {
367
		self::$modelsDatabase = $modelsDatabase;
368
	}
369
370
	/**
371
	 * Returns the database instance defined at $offset key in config
372
	 *
373
	 * @param string $offset
374
	 * @return \Ubiquity\db\Database
375
	 */
376 67
	public static function getDatabase($offset = 'default') {
377 67
		if (! isset ( self::$db [$offset] )) {
378 20
			self::startDatabase ( Startup::$config, $offset );
379
		}
380 67
		SqlUtils::$quote = self::$db [$offset]->quote;
381 67
		return self::$db [$offset];
382
	}
383
384 4
	public static function getDatabases() {
385 4
		$config = Startup::getConfig ();
386 4
		if (isset ( $config ['database'] )) {
387 4
			if (isset ( $config ['database'] ['dbName'] )) {
388 4
				return [ 'default' ];
389
			} else {
390
				return \array_keys ( $config ['database'] );
391
			}
392
		}
393
		return [ ];
394
	}
395
396
	public static function updateDatabaseParams(array &$config, array $parameters, $offset = 'default') {
397
		if ($offset === 'default') {
398
			if (isset ( $config ['database'] [$offset] )) {
399
				foreach ( $parameters as $k => $param ) {
400
					$config ['database'] [$offset] [$k] = $param;
401
				}
402
			} else {
403
				foreach ( $parameters as $k => $param ) {
404
					$config ['database'] [$k] = $param;
405
				}
406
			}
407
		} else {
408
			if (isset ( $config ['database'] [$offset] )) {
409
				foreach ( $parameters as $k => $param ) {
410
					$config ['database'] [$offset] [$k] = $param;
411
				}
412
			}
413
		}
414
	}
415
416 39
	public static function start() {
417 39
		self::$modelsDatabase = CacheManager::getModelsDatabases ();
418 39
	}
419
420
	/**
421
	 * gets a new DbConnection from pool
422
	 *
423
	 * @param string $offset
424
	 * @return mixed
425
	 */
426
	public static function pool($offset = 'default') {
427
		if (! isset ( self::$db [$offset] )) {
428
			self::startDatabase ( Startup::$config, $offset );
429
		}
430
		return self::$db [$offset]->pool ();
431
	}
432
433
	public static function freePool($db) {
434
		self::$pool->put ( $db );
435
	}
436
437
	public static function go($asyncCallable, $offset = 'default') {
438
		$vars = \get_defined_vars ();
439
		\Swoole\Coroutine::create ( function () use ($vars, $asyncCallable, $offset) {
1 ignored issue
show
Bug introduced by
The type Swoole\Coroutine was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
440
			$db = self::pool ( $offset );
441
			\call_user_func_array ( $asyncCallable, $vars );
442
			self::freePool ( $db );
443
		} );
444
	}
445
}
446