| 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 |