Passed
Push — master ( c4282d...8835f1 )
by Jean-Christophe
10:25
created

DAO::getOneToMany()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

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