Total Complexity | 69 |
Total Lines | 413 |
Duplicated Lines | 0 % |
Coverage | 67.22% |
Changes | 20 | ||
Bugs | 1 | Features | 2 |
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 |
||
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
|
|||
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 ); |
||
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) { |
|
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') { |
||
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
|
|||
440 | $db = self::pool ( $offset ); |
||
441 | \call_user_func_array ( $asyncCallable, $vars ); |
||
442 | self::freePool ( $db ); |
||
443 | } ); |
||
444 | } |
||
445 | } |
||
446 |