| Total Complexity | 97 |
| Total Lines | 607 |
| Duplicated Lines | 0 % |
| Changes | 11 | ||
| 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 declare(strict_types=1); |
||
| 28 | class TagHandler extends \XoopsPersistableObjectHandler |
||
| 29 | { |
||
| 30 | public $table_link; |
||
| 31 | public $table_stats; |
||
| 32 | |||
| 33 | /** |
||
| 34 | * Constructor |
||
| 35 | * |
||
| 36 | * @param \XoopsMySQLDatabase|null $db reference to the object {@link XoopsMySQLDatabase} |
||
| 37 | */ |
||
| 38 | public function __construct(?\XoopsMySQLDatabase $db = null) |
||
| 43 | } |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Get tags linked to an item |
||
| 47 | * |
||
| 48 | * @param int $itemid item ID |
||
| 49 | * @param int $modid module ID, optional |
||
| 50 | * @param int $catid id of corresponding category, optional |
||
| 51 | * @return array associative array of tags (id, term) |
||
| 52 | */ |
||
| 53 | public function getByItem(int $itemid, int $modid = 0, int $catid = 0): array |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Update tags linked to an item |
||
| 83 | * |
||
| 84 | * @param array|string $tags array of $tags or a single tag |
||
| 85 | * @param int $itemid item ID |
||
| 86 | * @param int|string $modid module ID or module dirname, optional |
||
| 87 | * @param int $catid id of corresponding category, optional |
||
| 88 | */ |
||
| 89 | public function updateByItem($tags, int $itemid, $modid = '', int $catid = 0): bool |
||
| 180 | } |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Update count stats or tag |
||
| 184 | * |
||
| 185 | */ |
||
| 186 | public function update_stats(int $tag_id, int $modid = 0, int $catid = 0): bool |
||
| 290 | } |
||
| 291 | |||
| 292 | /** |
||
| 293 | * Get tags with item count |
||
| 294 | * |
||
| 295 | * @param int $limit |
||
| 296 | * @param int $start |
||
| 297 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria} |
||
| 298 | * @param null|array $fields |
||
| 299 | * @param bool $fromStats fetch from tag-stats table |
||
| 300 | * @return array associative array of tags (id, term, status, count) |
||
| 301 | */ |
||
| 302 | public function &getByLimit($limit = Constants::UNLIMITED, $start = Constants::BEGINNING, \CriteriaElement $criteria = null, $fields = null, $fromStats = true): ?array |
||
| 303 | {//&getByLimit($criteria = null, $fromStats = true) |
||
| 304 | $ret = []; |
||
| 305 | if ($fromStats) { |
||
| 306 | $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, SUM(l.tag_count) AS count , l.tag_modid" . " FROM {$this->table} AS o LEFT JOIN {$this->table_stats} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 307 | } else { |
||
| 308 | $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, COUNT(l.tl_id) AS count , l.tag_modid" . " FROM {$this->table} AS o LEFT JOIN {$this->table_link} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 309 | } |
||
| 310 | |||
| 311 | $limit = \is_int($limit) && ($limit >= 0) ? $limit : Constants::UNLIMITED; |
||
| 312 | $start = \is_int($start) && ($start >= 0) ? $start : Constants::BEGINNING; |
||
| 313 | $sort = ''; |
||
| 314 | $order = ''; |
||
| 315 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 316 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 317 | $sort = $criteria->getSort(); |
||
| 318 | $order = $criteria->getOrder(); |
||
| 319 | $limit = $limit >= 0 ? $limit : $criteria->getLimit(); // non-zero arg passed to method overrides $criteria setting |
||
| 320 | $start = $start >= 0 ? $start : $criteria->getStart(); // non-zero arg passed to method overrides $criteria setting |
||
| 321 | } |
||
| 322 | $sql .= " GROUP BY o.{$this->keyName}, o.tag_term, o.tag_status, l.tag_modid"; |
||
| 323 | |||
| 324 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 325 | $sort = \mb_strtolower($sort); |
||
| 326 | switch ($sort) { |
||
| 327 | case 'a': |
||
| 328 | case 'alphabet': |
||
| 329 | $sql .= " ORDER BY o.tag_term {$order}"; |
||
| 330 | break; |
||
| 331 | case 'id': |
||
| 332 | case 'time': |
||
| 333 | $sql .= " ORDER BY o.{$this->keyName} {$order}"; |
||
| 334 | break; |
||
| 335 | case 'c': |
||
| 336 | case 'count': |
||
| 337 | default: |
||
| 338 | $sql .= " ORDER BY count {$order}"; |
||
| 339 | break; |
||
| 340 | } |
||
| 341 | |||
| 342 | $result = $this->db->query($sql, $limit, $start); |
||
| 343 | if ($result instanceof \mysqli_result) { |
||
| 344 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 345 | $ret[$myrow[$this->keyName]] = [ |
||
| 346 | 'id' => $myrow[$this->keyName], |
||
| 347 | 'term' => \htmlspecialchars($myrow['tag_term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 348 | 'status' => $myrow['tag_status'], |
||
| 349 | 'modid' => $myrow['tag_modid'], |
||
| 350 | 'count' => (int)$myrow['count'], |
||
| 351 | ]; |
||
| 352 | } |
||
| 353 | } else { |
||
| 354 | \trigger_error($this->db->error()); |
||
| 355 | $ret = null; |
||
| 356 | } |
||
| 357 | |||
| 358 | return $ret; |
||
| 359 | } |
||
| 360 | |||
| 361 | /** |
||
| 362 | * Get count of tags |
||
| 363 | * |
||
| 364 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria) |
||
| 365 | */ |
||
| 366 | public function getCount(\CriteriaElement $criteria = null): ?int |
||
| 367 | { |
||
| 368 | /* |
||
| 369 | $catid = (int)($catid); |
||
| 370 | $modid = (int)($modid); |
||
| 371 | */ |
||
| 372 | $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}"; |
||
| 373 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 374 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 375 | } |
||
| 376 | /* |
||
| 377 | $sql_where = " WHERE 1 = 1"; |
||
| 378 | if (!empty($modid)) { |
||
| 379 | $sql_where .= " AND l.tag_modid = {$modid}"; |
||
| 380 | } |
||
| 381 | if (empty($catid) || $catid > 0) { |
||
| 382 | $sql_where .= " AND l.tag_catid = {$catid}"; |
||
| 383 | } |
||
| 384 | |||
| 385 | $sql = $sql_select . " " . $sql_from . " " . $sql_where; |
||
| 386 | */ |
||
| 387 | $result = $this->db->query($sql); |
||
| 388 | if ($result instanceof \mysqli_result) { |
||
| 389 | [$ret] = (int)$this->db->fetchRow($result); |
||
| 390 | } else { |
||
| 391 | \trigger_error($this->db->error()); |
||
| 392 | $ret = 0; |
||
| 393 | } |
||
| 394 | |||
| 395 | return $ret; |
||
| 396 | } |
||
| 397 | |||
| 398 | /** |
||
| 399 | * Get items linked with a tag |
||
| 400 | * |
||
| 401 | * @param \CriteriaElement|null $criteria {@link Criteria} |
||
| 402 | * @return array associative array of items[] => (id, modid, catid, time) |
||
| 403 | */ |
||
| 404 | public function getItems(\CriteriaElement $criteria = null): array |
||
| 405 | { |
||
| 406 | $ret = []; |
||
| 407 | $sql = ' SELECT o.tl_id, o.tag_itemid, o.tag_modid, o.tag_catid, o.tag_time'; |
||
| 408 | $sql .= " FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 409 | |||
| 410 | $limit = Constants::UNLIMITED; |
||
| 411 | $start = Constants::BEGINNING; |
||
| 412 | $sort = ''; |
||
| 413 | $order = ''; |
||
| 414 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 415 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 416 | $sort = $criteria->getSort(); |
||
| 417 | $order = $criteria->getOrder(); |
||
| 418 | $limit = $criteria->getLimit(); |
||
| 419 | $start = $criteria->getStart(); |
||
| 420 | } |
||
| 421 | |||
| 422 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 423 | $sort = \mb_strtolower($sort); |
||
| 424 | switch ($sort) { |
||
| 425 | case 'i': |
||
| 426 | case 'item': |
||
| 427 | $sql .= " ORDER BY o.tag_itemid {$order}, o.tl_id DESC"; |
||
| 428 | break; |
||
| 429 | case 'm': |
||
| 430 | case 'module': |
||
| 431 | $sql .= " ORDER BY o.tag_modid {$order}, o.tl_id DESC"; |
||
| 432 | break; |
||
| 433 | case 't': |
||
| 434 | case 'time': |
||
| 435 | default: |
||
| 436 | $sql .= " ORDER BY o.tl_id {$order}"; |
||
| 437 | break; |
||
| 438 | } |
||
| 439 | |||
| 440 | $result = $this->db->query($sql, $limit, $start); |
||
| 441 | if ($result instanceof \mysqli_result) { |
||
| 442 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 443 | $ret[$myrow['tl_id']] = [ |
||
| 444 | 'itemid' => $myrow['tag_itemid'], |
||
| 445 | 'modid' => $myrow['tag_modid'], |
||
| 446 | 'catid' => $myrow['tag_catid'], |
||
| 447 | 'time' => $myrow['tag_time'], |
||
| 448 | ]; |
||
| 449 | } |
||
| 450 | } else { |
||
| 451 | \trigger_error($this->db->error()); |
||
| 452 | } |
||
| 453 | |||
| 454 | return $ret; |
||
| 455 | } |
||
| 456 | |||
| 457 | /** |
||
| 458 | * Get count of items linked with a tag |
||
| 459 | * |
||
| 460 | * @param int $modid id of corresponding module, optional: 0 for all; >1 for a specific module |
||
| 461 | * @param int $catid id of corresponding category, optional |
||
| 462 | * @return int count |
||
| 463 | */ |
||
| 464 | public function getItemCount(int $tag_id, int $modid = 0, int $catid = 0): int |
||
| 493 | } |
||
| 494 | |||
| 495 | /** |
||
| 496 | * Get detailed data (and font) for a tag |
||
| 497 | * |
||
| 498 | * @param array $tags_array associative array of tags (id, term, status, count) |
||
| 499 | * @return array tag data values for display |
||
| 500 | */ |
||
| 501 | public function getTagData(array $tags_array, int $font_max = 0, int $font_min = 0): array |
||
| 502 | { |
||
| 503 | // $tags_data_array = []; |
||
| 504 | // if (\is_array($tags_array) && !empty($tags_array)) { |
||
| 505 | // // set min and max tag count |
||
| 506 | // $count_array = \array_column($tags_array, 'count', 'id'); |
||
| 507 | // $count_min = \count($count_array) > 0 ? \min($count_array) : 0; |
||
| 508 | // $count_min = max($count_min, 0); |
||
| 509 | // $count_max = \count($count_array) > 0 ? \max($count_array) : 0; |
||
| 510 | // $count_max = max($count_max, 0); |
||
| 511 | // if ($count_max > 0) { |
||
| 512 | // $term_array = \array_column($tags_array, 'term', 'id'); |
||
| 513 | // $tags_term_array = \array_map('\mb_strtolower', $term_array); |
||
| 514 | // \array_multisort($tags_term_array, \SORT_ASC, $tags_array); |
||
| 515 | // $count_interval = $count_max - $count_min; |
||
| 516 | // $level_limit = 5; |
||
| 517 | // |
||
| 518 | // $font_ratio = $count_interval ? ($font_max - $font_min) / $count_interval : 1; |
||
| 519 | // |
||
| 520 | // foreach ($tags_array as $tag) { |
||
| 521 | // /* |
||
| 522 | // * Font-size = ((tag.count - count.min) * (font.max - font.min) / (count.max - count.min) ) * 100% |
||
| 523 | // */ |
||
| 524 | // $font_sz = \floor(($tag['count'] - $count_min) * $font_ratio) + $font_min; |
||
| 525 | // $level_sz = \floor(($tag['count'] - $count_min) * $level_limit / $count_max); |
||
| 526 | // $tags_data_array[] = [ |
||
| 527 | // 'id' => $tag['id'], |
||
| 528 | // 'font' => empty($count_interval) ? 100 : (int)$font_sz, |
||
| 529 | // 'level' => empty($count_max) ? 0 : (int)$level_sz, |
||
| 530 | // 'term' => \urlencode($tag['term']), |
||
| 531 | // 'title' => \htmlspecialchars($tag['term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 532 | // 'count' => $tag['count'], |
||
| 533 | // ]; |
||
| 534 | // } |
||
| 535 | // } |
||
| 536 | // } |
||
| 537 | |||
| 538 | $count_max = 0; |
||
| 539 | $count_min = 0; |
||
| 540 | $tags_term = []; |
||
| 541 | foreach ($tags_array as $tag) { |
||
| 542 | $count_max = \max($count_max, $tag['count']); // set counter to the max tag count |
||
| 543 | $count_min = \min(0, $count_min, $tag['count']); //set counter to the minimum for tag count |
||
| 544 | $tags_term[] = \mb_strtolower($tag['term']); |
||
| 545 | } |
||
| 546 | |||
| 547 | if (!empty($tags_term)) { |
||
| 548 | \array_multisort($tags_term, \SORT_ASC, $tags_array); |
||
| 549 | } |
||
| 550 | $count_interval = $count_max - $count_min; |
||
| 551 | $level_limit = 5; |
||
| 552 | |||
| 553 | // $font_max = $options[2]; |
||
| 554 | // $font_min = $options[3]; |
||
| 555 | $font_ratio = $count_interval ? ($font_max - $font_min) / $count_interval : 1; |
||
| 556 | |||
| 557 | $tags_data_array = []; |
||
| 558 | foreach ($tags_array as $tag) { |
||
| 559 | $tags_data_array[] = [ |
||
| 560 | 'id' => $tag['id'], |
||
| 561 | 'font' => $count_interval ? \floor(($tag['count'] - $count_min) * $font_ratio + $font_min) : 100, |
||
| 562 | 'level' => empty($count_max) ? 0 : \floor(($tag['count'] - $count_min) * $level_limit / $count_max), |
||
| 563 | 'term' => \urlencode($tag['term']), |
||
| 564 | 'title' => \htmlspecialchars($tag['term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 565 | 'count' => $tag['count'], |
||
| 566 | ]; |
||
| 567 | } |
||
| 568 | // unset($tags_array, $tag, $tags_term, $tag_count_array); |
||
| 569 | |||
| 570 | return $tags_data_array; |
||
| 571 | } |
||
| 572 | |||
| 573 | /** |
||
| 574 | * Delete an object as well as links relying on it |
||
| 575 | * |
||
| 576 | * @param \XoopsObject $object $object {@link Tag} |
||
| 577 | * @param bool $force flag to force the query execution despite security settings |
||
| 578 | */ |
||
| 579 | public function delete(\XoopsObject $object, $force = true): bool |
||
| 619 | } |
||
| 620 | |||
| 621 | /** |
||
| 622 | * clean orphan links from database |
||
| 623 | * |
||
| 624 | * @param string $table_link |
||
| 625 | * @param string $field_link |
||
| 626 | * @param string $field_object |
||
| 627 | * @return bool true on success |
||
| 628 | */ |
||
| 629 | public function cleanOrphan($table_link = '', $field_link = '', $field_object = ''): bool |
||
| 635 | } |
||
| 636 | } |
||
| 637 |