| Total Complexity | 101 |
| Total Lines | 594 |
| Duplicated Lines | 0 % |
| Changes | 6 | ||
| Bugs | 0 | Features | 0 |
Complex classes like TagHandler 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 TagHandler, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 31 | class TagHandler extends \XoopsPersistableObjectHandler |
||
| 32 | { |
||
| 33 | public $table_link; |
||
| 34 | public $table_stats; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Constructor |
||
| 38 | * |
||
| 39 | * @param \XoopsDatabase|null $db reference to the object {@link XoopsDatabase} |
||
| 40 | */ |
||
| 41 | public function __construct(\XoopsDatabase $db = null) |
||
| 46 | } |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Get tags linked to an item |
||
| 50 | * |
||
| 51 | * @access public |
||
| 52 | * @param int $itemid item ID |
||
| 53 | * @param int $modid module ID, optional |
||
| 54 | * @param int $catid id of corresponding category, optional |
||
| 55 | * @return array associative array of tags (id, term) |
||
| 56 | */ |
||
| 57 | public function getByItem($itemid, $modid = 0, $catid = 0) |
||
| 58 | { |
||
| 59 | $ret = []; |
||
| 60 | |||
| 61 | $itemid = (int)$itemid; |
||
| 62 | $modid = (empty($modid) && \is_object($GLOBALS['xoopsModule']) |
||
| 63 | && 'tag' !== $GLOBALS['xoopsModule']->getVar('dirname')) ? $GLOBALS['xoopsModule']->getVar('mid') : (int)$modid; |
||
| 64 | if (empty($itemid) || empty($modid)) { |
||
| 65 | return $ret; |
||
| 66 | } |
||
| 67 | |||
| 68 | $sql = 'SELECT o.tag_id, o.tag_term' |
||
| 69 | . " FROM {$this->table_link} AS l " |
||
| 70 | . " LEFT JOIN {$this->table} AS o ON o.{$this->keyName} = l.{$this->keyName} " |
||
| 71 | . " WHERE l.tag_itemid = {$itemid} AND l.tag_modid = {$modid}" |
||
| 72 | . (empty($catid) ? '' : (' AND l.tag_catid=' . (int)$catid)) |
||
| 73 | . ' ORDER BY o.tag_count DESC'; |
||
| 74 | |||
| 75 | $result = $this->db->query($sql); |
||
| 76 | if ($result instanceof \mysqli_result) { |
||
| 77 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 78 | $ret[$myrow[$this->keyName]] = $myrow['tag_term']; |
||
| 79 | } |
||
| 80 | } |
||
| 81 | return $ret; |
||
| 82 | } |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Update tags linked to an item |
||
| 86 | * |
||
| 87 | * @access public |
||
| 88 | * @param array|string $tags array of $tags or a single tag |
||
| 89 | * @param int $itemid item ID |
||
| 90 | * @param int|string $modid module ID or module dirname, optional |
||
| 91 | * @param int $catid id of corresponding category, optional |
||
| 92 | * @return bool |
||
| 93 | */ |
||
| 94 | public function updateByItem($tags, $itemid, $modid = '', $catid = 0) |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Update count stats or tag |
||
| 189 | * |
||
| 190 | * @access public |
||
| 191 | * @param int $tag_id |
||
| 192 | * @param int $modid |
||
| 193 | * @param int $catid |
||
| 194 | * @return bool |
||
| 195 | */ |
||
| 196 | public function update_stats($tag_id, $modid = 0, $catid = 0) |
||
| 197 | { |
||
| 198 | $tag_id = (int)$tag_id; |
||
| 199 | if (0 === $tag_id) { |
||
| 200 | return true; |
||
| 201 | } |
||
| 202 | |||
| 203 | $tag_count = []; |
||
| 204 | $modid = (int)$modid; |
||
| 205 | $catid = (0 === $modid) ? -1 : (int)$catid; |
||
| 206 | |||
| 207 | /** @var \XoopsModules\Tag\LinkHandler $linkHandler */ |
||
| 208 | $linkHandler = \XoopsModules\Tag\Helper::getInstance()->getHandler('Link'); |
||
| 209 | $criteria = new \CriteriaCompo(new \Criteria('tag_id', $tag_id)); |
||
| 210 | if (0 !== $modid) { |
||
| 211 | $criteria->add(new \Criteria('tag_modid', $modid), 'ADD'); |
||
| 212 | } |
||
| 213 | if (0 < $catid) { |
||
| 214 | $criteria->add(new \Criteria('tag_catid', $catid), 'ADD'); |
||
| 215 | } |
||
| 216 | $count = $linkHandler->getCount($criteria); |
||
| 217 | /* |
||
| 218 | $sql = 'SELECT COUNT(*) ' . " FROM {$this->table_link}" . " WHERE tag_id = {$tag_id}" . (empty($modid) ? '' : " AND tag_modid = {$modid}") . (($catid < 0) ? '' : " AND tag_catid = {$catid}"); |
||
| 219 | |||
| 220 | $result = $this->db->query($sql); |
||
| 221 | if ($result) { |
||
| 222 | list($count) = $this->db->fetchRow($result); |
||
| 223 | } |
||
| 224 | */ |
||
| 225 | if (0 === $modid) { |
||
| 226 | $tag_obj = $this->get($tag_id); |
||
| 227 | if ($tag_obj instanceof \XoopsModules\Tag\Tag) { |
||
| 228 | if (0 === $count) { |
||
| 229 | $this->delete($tag_obj); |
||
| 230 | } else { |
||
| 231 | $tag_obj->setVar('tag_count', $count); |
||
| 232 | $this->insert($tag_obj, true); |
||
| 233 | } |
||
| 234 | } |
||
| 235 | } else { |
||
| 236 | $statsHandler = \XoopsModules\Tag\Helper::getInstance()->getHandler('Stats'); |
||
| 237 | if (empty($count)) { |
||
| 238 | $criteria = new \CriteriaCompo(new \Criteria($this->keyName, $tag_id)); |
||
| 239 | $criteria->add(new \Criteria('tag_modid, $modid'), 'AND'); |
||
| 240 | $criteria->add(new \Criteria('tag_catid', $catid), 'AND'); |
||
| 241 | $status = $statsHandler->deleteAll($criteria); |
||
| 242 | if (!$status) { |
||
| 243 | //@todo determine what should happen here on failure. |
||
| 244 | } |
||
| 245 | /* |
||
| 246 | $sql = "DELETE FROM {$this->table_stats}" . ' WHERE ' . " {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}"; |
||
| 247 | |||
| 248 | if (false === $result = $this->db->queryF($sql)) { |
||
| 249 | //xoops_error($this->db->error()); |
||
| 250 | } |
||
| 251 | */ |
||
| 252 | } else { |
||
| 253 | $ts_id = null; |
||
| 254 | $criteria = new \CriteriaCompo(new \Criteria($this->keyName, $tag_id)); |
||
| 255 | $criteria->add(new \Criteria('tag_modid', $modid), 'AND'); |
||
| 256 | $criteria->add(new \Criteria('tag_catid', $catid), 'AND'); |
||
| 257 | $criteria->setLimit(1); |
||
| 258 | $tsCountObjs = $statsHandler->getAll($criteria); |
||
| 259 | if (\count($tsCountObjs) > 0) { |
||
| 260 | $tsCountObj = \array_pop($tsCountObjs); // get 1st (only) item |
||
| 261 | $ts_id = $tsCountObj->getVar('ts_id'); |
||
| 262 | $tag_count = $tsCountObj->getVar('tag_count'); |
||
| 263 | } |
||
| 264 | /* |
||
| 265 | $sql = 'SELECT ts_id, tag_count ' . " FROM {$this->table_stats}" . " WHERE {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}"; |
||
| 266 | $result = $this->db->query($sql); |
||
| 267 | if ($result) { |
||
| 268 | list($ts_id, $tag_count) = $this->db->fetchRow($result); |
||
| 269 | } |
||
| 270 | */ |
||
| 271 | $sql = ''; |
||
| 272 | if ($ts_id) { |
||
| 273 | if ($tag_count != $count) { |
||
| 274 | $tsCountObj->setVar('tag_count', $count); |
||
| 275 | $statsHandler->insert($tsCountObj); |
||
| 276 | //$sql = "UPDATE {$this->table_stats}" . " SET tag_count = {$count}" . ' WHERE ' . " ts_id = {$ts_id}"; |
||
| 277 | } |
||
| 278 | } else { |
||
| 279 | $newTsObj = $statsHandler->create(); |
||
| 280 | $newTsObj->setVars( |
||
| 281 | [ |
||
| 282 | 'tag_id' => $tag_id, |
||
| 283 | 'tag_modid' => $modid, |
||
| 284 | 'tag_catid' => $catid, |
||
| 285 | 'tag_count' => $count, |
||
| 286 | ] |
||
| 287 | ); |
||
| 288 | $statsHandler->insert($newTsObj); |
||
| 289 | //$sql = "INSERT INTO {$this->table_stats}" . ' (tag_id, tag_modid, tag_catid, tag_count)' . " VALUES ({$tag_id}, {$modid}, {$catid}, {$count})"; |
||
| 290 | } |
||
| 291 | /* |
||
| 292 | if (!empty($sql) && false === ($result = $this->db->queryF($sql))) { |
||
| 293 | //xoops_error($this->db->error()); |
||
| 294 | } |
||
| 295 | */ |
||
| 296 | } |
||
| 297 | } |
||
| 298 | |||
| 299 | return true; |
||
| 300 | } |
||
| 301 | |||
| 302 | /** |
||
| 303 | * Get tags with item count |
||
| 304 | * |
||
| 305 | * @access public |
||
| 306 | * @param int $limit |
||
| 307 | * @param int $start |
||
| 308 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria} |
||
| 309 | * @param null $fields |
||
| 310 | * @param bool $fromStats fetch from tag-stats table |
||
| 311 | * @return array associative array of tags (id, term, status, count) |
||
| 312 | */ |
||
| 313 | public function &getByLimit( |
||
| 314 | $limit = Constants::UNLIMITED, |
||
| 315 | $start = Constants::BEGINNING, |
||
| 316 | \CriteriaElement $criteria = null, |
||
| 317 | $fields = null, |
||
| 318 | $fromStats = true |
||
| 319 | )//&getByLimit($criteria = null, $fromStats = true) |
||
| 320 | { |
||
| 321 | $ret = []; |
||
| 322 | if ($fromStats) { |
||
| 323 | $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, SUM(l.tag_count) AS count" . " FROM {$this->table} AS o LEFT JOIN {$this->table_stats} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 324 | } else { |
||
| 325 | $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, COUNT(l.tl_id) AS count" . " FROM {$this->table} AS o LEFT JOIN {$this->table_link} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 326 | } |
||
| 327 | |||
| 328 | $limit = \is_int($limit) && ($limit >= 0) ? $limit : Constants::UNLIMITED; |
||
| 329 | $start = \is_int($start) && ($start >= 0) ? $start : Constants::BEGINNING; |
||
| 330 | $sort = ''; |
||
| 331 | $order = ''; |
||
| 332 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 333 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 334 | $sort = $criteria->getSort(); |
||
| 335 | $order = $criteria->getOrder(); |
||
| 336 | $limit = $limit >= 0 ? $limit : $criteria->getLimit(); // non-zero arg passed to method overrides $criteria setting |
||
| 337 | $start = $start >= 0 ? $start : $criteria->getStart(); // non-zero arg passed to method overrides $criteria setting |
||
| 338 | } |
||
| 339 | $sql .= " GROUP BY o.{$this->keyName}, o.tag_term, o.tag_status, l.tag_modid"; |
||
| 340 | |||
| 341 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 342 | $sort = \mb_strtolower($sort); |
||
| 343 | switch ($sort) { |
||
| 344 | case 'a': |
||
| 345 | case 'alphabet': |
||
| 346 | $sql .= " ORDER BY o.tag_term {$order}"; |
||
| 347 | break; |
||
| 348 | case 'id': |
||
| 349 | case 'time': |
||
| 350 | $sql .= " ORDER BY o.{$this->keyName} {$order}"; |
||
| 351 | break; |
||
| 352 | case 'c': |
||
| 353 | case 'count': |
||
| 354 | default: |
||
| 355 | $sql .= " ORDER BY count {$order}"; |
||
| 356 | break; |
||
| 357 | } |
||
| 358 | |||
| 359 | if (false === ($result = $this->db->query($sql, $limit, $start))) { |
||
| 360 | //xoops_error($this->db->error()); |
||
| 361 | $ret = null; |
||
| 362 | } else { |
||
| 363 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 364 | $ret[$myrow[$this->keyName]] = [ |
||
| 365 | 'id' => $myrow[$this->keyName], |
||
| 366 | 'term' => \htmlspecialchars($myrow['tag_term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 367 | 'status' => $myrow['tag_status'], |
||
| 368 | 'count' => (int)$myrow['count'], |
||
| 369 | ]; |
||
| 370 | } |
||
| 371 | } |
||
| 372 | |||
| 373 | return $ret; |
||
| 374 | } |
||
| 375 | |||
| 376 | /** |
||
| 377 | * Get count of tags |
||
| 378 | * |
||
| 379 | * @access public |
||
| 380 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria) |
||
| 381 | * @return int count |
||
| 382 | */ |
||
| 383 | public function getCount(\CriteriaElement $criteria = null) |
||
| 384 | { |
||
| 385 | /* |
||
| 386 | $catid = (int)($catid); |
||
| 387 | $modid = (int)($modid); |
||
| 388 | */ |
||
| 389 | $sql = "SELECT COUNT(DISTINCT o.{$this->keyName})" . " FROM {$this->table} AS o LEFT JOIN {$this->table_link} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 390 | if ((null !== $criteria) && $criteria instanceof \CriteriaElement) { |
||
| 391 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 392 | } |
||
| 393 | /* |
||
| 394 | $sql_where = " WHERE 1 = 1"; |
||
| 395 | if (!empty($modid)) { |
||
| 396 | $sql_where .= " AND l.tag_modid = {$modid}"; |
||
| 397 | } |
||
| 398 | if (empty($catid) || $catid > 0) { |
||
| 399 | $sql_where .= " AND l.tag_catid = {$catid}"; |
||
| 400 | } |
||
| 401 | |||
| 402 | $sql = $sql_select . " " . $sql_from . " " . $sql_where; |
||
| 403 | */ |
||
| 404 | if (false === ($result = $this->db->query($sql))) { |
||
| 405 | //xoops_error($this->db->error()); |
||
| 406 | $ret = 0; |
||
| 407 | } else { |
||
| 408 | [$ret] = $this->db->fetchRow($result); |
||
| 409 | } |
||
| 410 | |||
| 411 | return $ret; |
||
| 412 | } |
||
| 413 | |||
| 414 | /** |
||
| 415 | * Get items linked with a tag |
||
| 416 | * |
||
| 417 | * @access public |
||
| 418 | * @param \CriteriaElement|null $criteria {@link Criteria} |
||
| 419 | * @return array associative array of items[] => (id, modid, catid, time) |
||
| 420 | */ |
||
| 421 | public function getItems(\CriteriaElement $criteria = null) |
||
| 422 | { |
||
| 423 | $ret = []; |
||
| 424 | $sql = ' SELECT o.tl_id, o.tag_itemid, o.tag_modid, o.tag_catid, o.tag_time'; |
||
| 425 | $sql .= " FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 426 | |||
| 427 | $limit = Constants::UNLIMITED; |
||
| 428 | $start = Constants::BEGINNING; |
||
| 429 | $sort = ''; |
||
| 430 | $order = ''; |
||
| 431 | if ((null !== $criteria) && $criteria instanceof \CriteriaElement) { |
||
| 432 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 433 | $sort = $criteria->getSort(); |
||
| 434 | $order = $criteria->getOrder(); |
||
| 435 | $limit = $criteria->getLimit(); |
||
| 436 | $start = $criteria->getStart(); |
||
| 437 | } |
||
| 438 | |||
| 439 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 440 | $sort = \mb_strtolower($sort); |
||
| 441 | switch ($sort) { |
||
| 442 | case 'i': |
||
| 443 | case 'item': |
||
| 444 | $sql .= " ORDER BY o.tag_itemid {$order}, o.tl_id DESC"; |
||
| 445 | break; |
||
| 446 | case 'm': |
||
| 447 | case 'module': |
||
| 448 | $sql .= " ORDER BY o.tag_modid {$order}, o.tl_id DESC"; |
||
| 449 | break; |
||
| 450 | case 't': |
||
| 451 | case 'time': |
||
| 452 | default: |
||
| 453 | $sql .= " ORDER BY o.tl_id {$order}"; |
||
| 454 | break; |
||
| 455 | } |
||
| 456 | |||
| 457 | if (false === ($result = $this->db->query($sql, $limit, $start))) { |
||
| 458 | //xoops_error($this->db->error()); |
||
| 459 | $ret = []; |
||
| 460 | } else { |
||
| 461 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 462 | $ret[$myrow['tl_id']] = [ |
||
| 463 | 'itemid' => $myrow['tag_itemid'], |
||
| 464 | 'modid' => $myrow['tag_modid'], |
||
| 465 | 'catid' => $myrow['tag_catid'], |
||
| 466 | 'time' => $myrow['tag_time'], |
||
| 467 | ]; |
||
| 468 | } |
||
| 469 | } |
||
| 470 | |||
| 471 | return $ret; |
||
| 472 | } |
||
| 473 | |||
| 474 | /** |
||
| 475 | * Get count of items linked with a tag |
||
| 476 | * |
||
| 477 | * @access public |
||
| 478 | * @param int $tag_id |
||
| 479 | * @param int $modid id of corresponding module, optional: 0 for all; >1 for a specific module |
||
| 480 | * @param int $catid id of corresponding category, optional |
||
| 481 | * @return int count |
||
| 482 | */ |
||
| 483 | public function getItemCount($tag_id, $modid = 0, $catid = 0) |
||
| 511 | } |
||
| 512 | |||
| 513 | /** |
||
| 514 | * Get detailed data (and font) for a tag |
||
| 515 | * |
||
| 516 | * @access public |
||
| 517 | * @param array $tags_array associative array of tags (id, term, status, count) |
||
| 518 | * @param int $font_max |
||
| 519 | * @param int $font_min |
||
| 520 | * @return array tag data values for display |
||
| 521 | */ |
||
| 522 | public function getTagData($tags_array, $font_max = 0, $font_min = 0) |
||
| 523 | { |
||
| 524 | $tags_data_array = []; |
||
| 525 | if (\is_array($tags_array) && !empty($tags_array)) { |
||
| 526 | // set min and max tag count |
||
| 527 | $count_array = \array_column($tags_array, 'count', 'id'); |
||
| 528 | $count_min = \count($count_array) > 0 ? \min($count_array) : 0; |
||
| 529 | $count_min = $count_min > 0 ? $count_min : 0; |
||
| 530 | $count_max = \count($count_array) > 0 ? \max($count_array) : 0; |
||
| 531 | $count_max = $count_max > 0 ? $count_max : 0; |
||
| 532 | |||
| 533 | $term_array = \array_column($tags_array, 'term', 'id'); |
||
| 534 | $tags_term_array = \array_map('\mb_strtolower', $term_array); |
||
| 535 | \array_multisort($tags_term_array, \SORT_ASC, $tags_array); |
||
| 536 | $count_interval = $count_max - $count_min; |
||
| 537 | $level_limit = 5; |
||
| 538 | |||
| 539 | $font_ratio = $count_interval ? ($font_max - $font_min) / $count_interval : 1; |
||
| 540 | |||
| 541 | foreach ($tags_array as $tag) { |
||
| 542 | /* |
||
| 543 | * Font-size = ((tag.count - count.min) * (font.max - font.min) / (count.max - count.min) ) * 100% |
||
| 544 | */ |
||
| 545 | $font_sz = \floor(($tag['count'] - $count_min) * $font_ratio) + $font_min; |
||
| 546 | $level_sz = \floor(($tag['count'] - $count_min) * $level_limit / $count_max); |
||
| 547 | $tags_data_array[] = [ |
||
| 548 | 'id' => $tag['id'], |
||
| 549 | 'font' => empty($count_interval) ? 100 : (int)$font_sz, |
||
| 550 | 'level' => empty($count_max) ? 0 : (int)$level_sz, |
||
| 551 | 'term' => \urlencode($tag['term']), |
||
| 552 | 'title' => \htmlspecialchars($tag['term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 553 | 'count' => $tag['count'], |
||
| 554 | ]; |
||
| 555 | } |
||
| 556 | } |
||
| 557 | return $tags_data_array; |
||
| 558 | } |
||
| 559 | |||
| 560 | /** |
||
| 561 | * Delete an object as well as links relying on it |
||
| 562 | * |
||
| 563 | * @access public |
||
| 564 | * @param \XoopsObject $object $object {@link Tag} |
||
| 565 | * @param bool $force flag to force the query execution despite security settings |
||
| 566 | * @return bool |
||
| 567 | */ |
||
| 568 | public function delete(\XoopsObject $object, $force = true) |
||
| 608 | } |
||
| 609 | |||
| 610 | /** |
||
| 611 | * clean orphan links from database |
||
| 612 | * |
||
| 613 | * @access public |
||
| 614 | * @param string $table_link |
||
| 615 | * @param string $field_link |
||
| 616 | * @param string $field_object |
||
| 617 | * @return bool true on success |
||
| 618 | */ |
||
| 619 | public function cleanOrphan($table_link = '', $field_link = '', $field_object = '') |
||
| 625 | } |
||
| 626 | } |
||
| 627 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.