Passed
Push — master ( 9d6429...7d913c )
by Jean-Christophe
08:48
created

DAO::setModelsDatabases()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
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 76
	protected static function getDb($model) {
45 76
		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 5
	public static function getManyToOne($instance, $member, $included = false, $useCache = NULL) {
79 5
		$classname = self::getClass_ ( $instance );
80 5
		if (is_array ( $instance )) {
81 1
			$instance = self::getById ( $classname, $instance [1], false, $useCache );
82
		}
83 5
		$fieldAnnot = OrmUtils::getMemberJoinColumns ( $classname, $member );
84 5
		if ($fieldAnnot !== null) {
85 5
			$annotationArray = $fieldAnnot [1];
86 5
			$member = $annotationArray ["member"];
87 5
			$value = Reflexion::getMemberValue ( $instance, $member );
88 5
			$key = OrmUtils::getFirstKey ( $annotationArray ["className"] );
89 5
			$kv = array ($key => $value );
90 5
			$obj = self::getById ( $annotationArray ["className"], $kv, $included, $useCache );
91 5
			if ($obj !== null) {
92 5
				Logger::info ( "DAO", "Loading the member " . $member . " for the object " . $classname, "getManyToOne" );
93 5
				$accesseur = "set" . ucfirst ( $member );
94 5
				if (is_object ( $instance ) && method_exists ( $instance, $accesseur )) {
95 5
					$instance->$accesseur ( $obj );
96 5
					$instance->_rest [$member] = $obj->_rest;
97
				}
98 5
				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 8
	public static function getOneToMany($instance, $member, $included = true, $useCache = NULL, $annot = null) {
113 8
		$ret = array ();
114 8
		$class = self::getClass_ ( $instance );
115 8
		if (! isset ( $annot )) {
116 8
			$annot = OrmUtils::getAnnotationInfoMember ( $class, "#oneToMany", $member );
117
		}
118 8
		if ($annot !== false) {
119 8
			$fkAnnot = OrmUtils::getAnnotationInfoMember ( $annot ["className"], "#joinColumn", $annot ["mappedBy"] );
120 8
			if ($fkAnnot !== false) {
121 8
				$fkv = self::getFirstKeyValue_ ( $instance );
122 8
				$db = self::getDb ( $annot ["className"] );
123 8
				$ret = self::_getAll ( $db, $annot ["className"], ConditionParser::simple ( $db->quote . $fkAnnot ["name"] . $db->quote . "= ?", $fkv ), $included, $useCache );
124 8
				if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getOneToMany' )) {
125 7
					self::setToMember ( $member, $instance, $ret, $modifier );
126
				}
127
			}
128
		}
129 8
		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 5
	public static function getManyToMany($instance, $member, $included = false, $array = null, $useCache = NULL) {
143 5
		$ret = [ ];
144 5
		$class = self::getClass_ ( $instance );
145 5
		$parser = new ManyToManyParser ( $class, $member );
146 5
		if ($parser->init ()) {
147 5
			if (is_null ( $array )) {
148 5
				$pk = self::getFirstKeyValue_ ( $instance );
149 5
				$quote = SqlUtils::$quote;
150 5
				$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 5
				$targetEntityClass = $parser->getTargetEntityClass ();
152 5
				$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 5
			if (is_object ( $instance ) && $modifier = self::getAccessor ( $member, $instance, 'getManyToMany' )) {
157 4
				self::setToMember ( $member, $instance, $ret, $modifier );
158
			}
159
		}
160 5
		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 25
	public static function getAll($className, $condition = '', $included = true, $parameters = null, $useCache = NULL) {
190 25
		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 4
	public static function getRownum($className, $ids) {
201 4
		$tableName = OrmUtils::getTableName ( $className );
202 4
		$db = self::getDb ( $className );
203 4
		$quote = $db->quote;
204 4
		self::parseKey ( $ids, $className, $quote );
205 4
		$condition = SqlUtils::getCondition ( $ids, $className );
206 4
		$keyFields = OrmUtils::getKeyFields ( $className );
207 4
		if (is_array ( $keyFields )) {
208 4
			$keys = implode ( ",", $keyFields );
209
		} else {
210
			$keys = "1";
211
		}
212
213 4
		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 20
	public static function getOne($className, $condition, $included = true, $parameters = null, $useCache = NULL) {
245 20
		$conditionParser = new ConditionParser ();
246 20
		if (! isset ( $parameters )) {
247 20
			$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 20
		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 23
	public static function getById($className, $keyValues, $included = true, $useCache = NULL) {
268 23
		return self::_getOne ( self::getDb ( $className ), $className, self::getConditionParser ( $className, $keyValues ), $included, $useCache );
269
	}
270
271 23
	protected static function getConditionParser($className, $keyValues) {
272 23
		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 11
			self::$conditionParsers [$className]->setKeyValues ( $keyValues );
278
		}
279 23
		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 74
	public static function connect($offset, $wrapper, $dbType, $dbName, $serverName = '127.0.0.1', $port = '3306', $user = 'root', $password = '', $options = [], $cache = false) {
297 74
		self::$db [$offset] = new Database ( $wrapper, $dbType, $dbName, $serverName, $port, $user, $password, $options, $cache, self::$pool );
298
		try {
299 74
			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 74
	}
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 119
	public static function getDbOffset(&$config, $offset = null) {
319 119
		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 32
	public static function closeDb($offset = 'default') {
345 32
		$db = self::$db [$offset] ?? false;
346 32
		if ($db !== false) {
347 32
			$db->close ();
348
		}
349 32
	}
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 9
	public static function setModelsDatabases($modelsDatabase) {
367 9
		self::$modelsDatabase = $modelsDatabase;
368 9
	}
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 76
	public static function getDatabase($offset = 'default') {
377 76
		if (! isset ( self::$db [$offset] )) {
378 20
			self::startDatabase ( Startup::$config, $offset );
379
		}
380 76
		SqlUtils::$quote = self::$db [$offset]->quote;
381 76
		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