| Total Complexity | 97 |
| Total Lines | 600 |
| Duplicated Lines | 0 % |
| Changes | 14 | ||
| Bugs | 2 | 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) |
||
| 39 | { |
||
| 40 | parent::__construct($db, 'tag_tag', Tag::class, 'tag_id', 'tag_term'); |
||
| 41 | $this->table_link = $this->db->prefix('tag_link'); |
||
| 42 | $this->table_stats = $this->db->prefix('tag_stats'); |
||
| 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 |
||
| 54 | { |
||
| 55 | $ret = []; |
||
| 56 | |||
| 57 | $modid = (empty($modid) && \is_object($GLOBALS['xoopsModule']) |
||
| 58 | && 'tag' !== $GLOBALS['xoopsModule']->getVar('dirname')) ? $GLOBALS['xoopsModule']->getVar('mid') : $modid; |
||
| 59 | if (empty($itemid) || empty($modid)) { |
||
| 60 | return $ret; |
||
| 61 | } |
||
| 62 | |||
| 63 | $sql = 'SELECT o.tag_id, o.tag_term' |
||
| 64 | . " FROM {$this->table_link} AS l " |
||
| 65 | . " LEFT JOIN {$this->table} AS o ON o.{$this->keyName} = l.{$this->keyName} " |
||
| 66 | . " WHERE l.tag_itemid = {$itemid} AND l.tag_modid = {$modid}" |
||
| 67 | . (empty($catid) ? '' : (' AND l.tag_catid=' . $catid)) |
||
| 68 | . ' ORDER BY o.tag_count DESC'; |
||
| 69 | |||
| 70 | $result = $this->db->query($sql); |
||
| 71 | if ($result instanceof \mysqli_result) { |
||
| 72 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 73 | $ret[$myrow[$this->keyName]] = $myrow['tag_term']; |
||
| 74 | } |
||
| 75 | } |
||
| 76 | |||
| 77 | return $ret; |
||
| 78 | } |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Update tags linked to an item |
||
| 82 | * |
||
| 83 | * @param array|string $tags array of $tags or a single tag |
||
| 84 | * @param int $itemid item ID |
||
| 85 | * @param int|string $modid module ID or module dirname, optional |
||
| 86 | * @param int $catid id of corresponding category, optional |
||
| 87 | */ |
||
| 88 | public function updateByItem($tags, int $itemid, $modid = '', int $catid = 0): bool |
||
| 89 | { |
||
| 90 | if (!empty($modid) && !\is_numeric($modid)) { |
||
| 91 | if (($GLOBALS['xoopsModule'] instanceof \XoopsModule) |
||
| 92 | && ($modid == $GLOBALS['xoopsModule']->getVar('dirname'))) { |
||
| 93 | $modid = $GLOBALS['xoopsModule']->getVar('mid'); |
||
| 94 | } else { |
||
| 95 | /** @var \XoopsModuleHandler $moduleHandler */ |
||
| 96 | $moduleHandler = \xoops_getHandler('module'); |
||
| 97 | $modid = ($moduleObj = $moduleHandler->getByDirname($modid)) ? $moduleObj->getVar('mid') : 0; |
||
| 98 | } |
||
| 99 | } elseif ($GLOBALS['xoopsModule'] instanceof \XoopsModule) { |
||
| 100 | $modid = $GLOBALS['xoopsModule']->getVar('mid'); |
||
| 101 | } |
||
| 102 | |||
| 103 | if (empty($itemid) || empty($modid)) { |
||
| 104 | return false; |
||
| 105 | } |
||
| 106 | |||
| 107 | if (empty($tags)) { |
||
| 108 | $tags = []; |
||
| 109 | } elseif (!\is_array($tags)) { |
||
| 110 | $tags = Utility::tag_parse_tag(\addslashes(\stripslashes($tags))); |
||
| 111 | } |
||
| 112 | |||
| 113 | $tags_existing = $this->getByItem($itemid, $modid, $catid); |
||
| 114 | $tags_delete = \array_diff(\array_values($tags_existing), $tags); |
||
| 115 | $tags_add = \array_diff($tags, \array_values($tags_existing)); |
||
| 116 | $tags_update = []; |
||
| 117 | |||
| 118 | if (0 < \count($tags_delete)) { |
||
| 119 | $tags_delete = \array_map([$this->db, 'quoteString'], $tags_delete); |
||
| 120 | $tags_id = &$this->getIds(new \Criteria('tag_term', '(' . \implode(', ', $tags_delete) . ')', 'IN')); |
||
| 121 | if (!empty($tags_id)) { |
||
| 122 | $sql = "DELETE FROM {$this->table_link}" . ' WHERE ' . " {$this->keyName} IN (" . \implode(', ', $tags_id) . ')' . " AND tag_modid = {$modid} AND tag_catid = {$catid} AND tag_itemid = {$itemid}"; |
||
| 123 | if (false === ($result = $this->db->queryF($sql))) { |
||
|
|
|||
| 124 | //@todo: decide if we should do something here on failure |
||
| 125 | \trigger_error($this->db->error()); |
||
| 126 | } |
||
| 127 | $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . ' tag_count < 2 AND ' . " {$this->keyName} IN (" . \implode(', ', $tags_id) . ')'; |
||
| 128 | if (false === ($result = $this->db->queryF($sql))) { |
||
| 129 | \trigger_error($this->db->error()); |
||
| 130 | } |
||
| 131 | |||
| 132 | $sql = 'UPDATE ' . $this->table . ' SET tag_count = tag_count - 1' . ' WHERE ' . " {$this->keyName} IN (" . \implode(', ', $tags_id) . ')'; |
||
| 133 | if (false === ($result = $this->db->queryF($sql))) { |
||
| 134 | \trigger_error($this->db->error()); |
||
| 135 | } |
||
| 136 | $tags_update = $tags_id; |
||
| 137 | } |
||
| 138 | } |
||
| 139 | |||
| 140 | if (!empty($tags_add)) { |
||
| 141 | $tag_link = []; |
||
| 142 | $tag_count = []; |
||
| 143 | foreach ($tags_add as $tag) { |
||
| 144 | $tags_id = &$this->getIds(new \Criteria('tag_term', $tag)); |
||
| 145 | if (!empty($tags_id)) { |
||
| 146 | $tag_id = $tags_id[0]; |
||
| 147 | $tag_count[] = $tag_id; |
||
| 148 | } else { |
||
| 149 | $tagObj = $this->create(); |
||
| 150 | $tagObj->setVars(['tag_term' => $tag, 'tag_count' => 1]); |
||
| 151 | $this->insert($tagObj); |
||
| 152 | $tag_id = $tagObj->getVar('tag_id'); |
||
| 153 | unset($tagObj); |
||
| 154 | } |
||
| 155 | $tag_link[] = "({$tag_id}, {$itemid}, {$catid}, {$modid}, " . \time() . ')'; |
||
| 156 | $tags_update[] = $tag_id; |
||
| 157 | } |
||
| 158 | $sql = "INSERT INTO {$this->table_link}" . ' (tag_id, tag_itemid, tag_catid, tag_modid, tag_time) ' . ' VALUES ' . \implode(', ', $tag_link); |
||
| 159 | if (false === ($result = $this->db->queryF($sql))) { |
||
| 160 | \trigger_error($this->db->error()); |
||
| 161 | } |
||
| 162 | if (!empty($tag_count)) { |
||
| 163 | $sql = 'UPDATE ' . $this->table . ' SET tag_count = tag_count+1' . ' WHERE ' . " {$this->keyName} IN (" . \implode(', ', $tag_count) . ')'; |
||
| 164 | if (false === ($result = $this->db->queryF($sql))) { |
||
| 165 | \trigger_error($this->db->error()); |
||
| 166 | } |
||
| 167 | } |
||
| 168 | } |
||
| 169 | if (\is_array($tags_update)) { |
||
| 170 | foreach ($tags_update as $tag_id) { |
||
| 171 | $this->update_stats((int)$tag_id, $modid, $catid); |
||
| 172 | } |
||
| 173 | } |
||
| 174 | |||
| 175 | return true; |
||
| 176 | } |
||
| 177 | |||
| 178 | /** |
||
| 179 | * Update count stats or tag |
||
| 180 | * |
||
| 181 | */ |
||
| 182 | public function update_stats(int $tag_id, int $modid = 0, int $catid = 0): bool |
||
| 183 | { |
||
| 184 | if (0 === $tag_id) { |
||
| 185 | return true; |
||
| 186 | } |
||
| 187 | |||
| 188 | $tag_count = []; |
||
| 189 | $catid = (0 === $modid) ? -1 : $catid; |
||
| 190 | |||
| 191 | /** @var \XoopsModules\Tag\LinkHandler $linkHandler */ |
||
| 192 | $linkHandler = \XoopsModules\Tag\Helper::getInstance()->getHandler('Link'); |
||
| 193 | $criteria = new \CriteriaCompo(new \Criteria('tag_id', (string)$tag_id)); |
||
| 194 | if (0 !== $modid) { |
||
| 195 | $criteria->add(new \Criteria('tag_modid', (string)$modid), 'AND'); |
||
| 196 | } |
||
| 197 | if (0 < $catid) { |
||
| 198 | $criteria->add(new \Criteria('tag_catid', (string)$catid), 'AND'); |
||
| 199 | } |
||
| 200 | $count = $linkHandler->getCount($criteria); |
||
| 201 | /* |
||
| 202 | $sql = 'SELECT COUNT(*) ' . " FROM {$this->table_link}" . " WHERE tag_id = {$tag_id}" . (empty($modid) ? '' : " AND tag_modid = {$modid}") . (($catid < 0) ? '' : " AND tag_catid = {$catid}"); |
||
| 203 | |||
| 204 | $result = $this->db->query($sql); |
||
| 205 | if ($result) { |
||
| 206 | list($count) = $this->db->fetchRow($result); |
||
| 207 | } |
||
| 208 | */ |
||
| 209 | if (0 === $modid) { |
||
| 210 | $tagObj = $this->get($tag_id); |
||
| 211 | if ($tagObj instanceof \XoopsModules\Tag\Tag) { |
||
| 212 | if (0 === $count) { |
||
| 213 | $this->delete($tagObj); |
||
| 214 | } else { |
||
| 215 | $tagObj->setVar('tag_count', $count); |
||
| 216 | $this->insert($tagObj, true); |
||
| 217 | } |
||
| 218 | } |
||
| 219 | } else { |
||
| 220 | $statsHandler = Helper::getInstance()->getHandler('Stats'); |
||
| 221 | if (empty($count)) { |
||
| 222 | $criteria = new \CriteriaCompo(new \Criteria($this->keyName, (string)$tag_id)); |
||
| 223 | $criteria->add(new \Criteria('tag_modid, $modid'), 'AND'); |
||
| 224 | $criteria->add(new \Criteria('tag_catid', $catid), 'AND'); |
||
| 225 | $status = $statsHandler->deleteAll($criteria); |
||
| 226 | if (!$status) { |
||
| 227 | //@todo determine what should happen here on failure. |
||
| 228 | } |
||
| 229 | /* |
||
| 230 | $sql = "DELETE FROM {$this->table_stats}" . ' WHERE ' . " {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}"; |
||
| 231 | |||
| 232 | if (false === $result = $this->db->queryF($sql)) { |
||
| 233 | \trigger_error($this->db->error()); |
||
| 234 | } |
||
| 235 | */ |
||
| 236 | } else { |
||
| 237 | $ts_id = null; |
||
| 238 | $criteria = new \CriteriaCompo(new \Criteria($this->keyName, (string)$tag_id)); |
||
| 239 | $criteria->add(new \Criteria('tag_modid', (string)$modid), 'AND'); |
||
| 240 | $criteria->add(new \Criteria('tag_catid', (string)$catid), 'AND'); |
||
| 241 | $criteria->setLimit(1); |
||
| 242 | $tsCountObjs = $statsHandler->getAll($criteria); |
||
| 243 | if (\count($tsCountObjs) > 0) { |
||
| 244 | $tsCountObj = \array_pop($tsCountObjs); // get 1st (only) item |
||
| 245 | $ts_id = $tsCountObj->getVar('ts_id'); |
||
| 246 | $tag_count = $tsCountObj->getVar('tag_count'); |
||
| 247 | } |
||
| 248 | /* |
||
| 249 | $sql = 'SELECT ts_id, tag_count ' . " FROM {$this->table_stats}" . " WHERE {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}"; |
||
| 250 | $result = $this->db->query($sql); |
||
| 251 | if ($result) { |
||
| 252 | list($ts_id, $tag_count) = $this->db->fetchRow($result); |
||
| 253 | } |
||
| 254 | */ |
||
| 255 | $sql = ''; |
||
| 256 | if ($ts_id) { |
||
| 257 | if ($tag_count != $count) { |
||
| 258 | $tsCountObj->setVar('tag_count', $count); |
||
| 259 | $statsHandler->insert($tsCountObj); |
||
| 260 | //$sql = "UPDATE {$this->table_stats}" . " SET tag_count = {$count}" . ' WHERE ' . " ts_id = {$ts_id}"; |
||
| 261 | } |
||
| 262 | } else { |
||
| 263 | $newTsObj = $statsHandler->create(); |
||
| 264 | $newTsObj->setVars( |
||
| 265 | [ |
||
| 266 | 'tag_id' => $tag_id, |
||
| 267 | 'tag_modid' => $modid, |
||
| 268 | 'tag_catid' => $catid, |
||
| 269 | 'tag_count' => $count, |
||
| 270 | ] |
||
| 271 | ); |
||
| 272 | $statsHandler->insert($newTsObj); |
||
| 273 | //$sql = "INSERT INTO {$this->table_stats}" . ' (tag_id, tag_modid, tag_catid, tag_count)' . " VALUES ({$tag_id}, {$modid}, {$catid}, {$count})"; |
||
| 274 | } |
||
| 275 | /* |
||
| 276 | if (!empty($sql) && false === ($result = $this->db->queryF($sql))) { |
||
| 277 | \trigger_error($this->db->error()); |
||
| 278 | } |
||
| 279 | */ |
||
| 280 | } |
||
| 281 | } |
||
| 282 | |||
| 283 | return true; |
||
| 284 | } |
||
| 285 | |||
| 286 | /** |
||
| 287 | * Get tags with item count |
||
| 288 | * |
||
| 289 | * @param int $limit |
||
| 290 | * @param int $start |
||
| 291 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria} |
||
| 292 | * @param null|array $fields |
||
| 293 | * @param bool $fromStats fetch from tag-stats table |
||
| 294 | * @return array associative array of tags (id, term, status, count) |
||
| 295 | */ |
||
| 296 | public function &getByLimit($limit = Constants::UNLIMITED, $start = Constants::BEGINNING, \CriteriaElement $criteria = null, $fields = null, $fromStats = true): ?array |
||
| 297 | {//&getByLimit($criteria = null, $fromStats = true) |
||
| 298 | $ret = []; |
||
| 299 | if ($fromStats) { |
||
| 300 | $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}"; |
||
| 301 | } else { |
||
| 302 | $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}"; |
||
| 303 | } |
||
| 304 | |||
| 305 | $limit = \is_int($limit) && ($limit >= 0) ? $limit : Constants::UNLIMITED; |
||
| 306 | $start = \is_int($start) && ($start >= 0) ? $start : Constants::BEGINNING; |
||
| 307 | $sort = ''; |
||
| 308 | $order = ''; |
||
| 309 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 310 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 311 | $sort = $criteria->getSort(); |
||
| 312 | $order = $criteria->getOrder(); |
||
| 313 | $limit = $limit >= 0 ? $limit : $criteria->getLimit(); // non-zero arg passed to method overrides $criteria setting |
||
| 314 | $start = $start >= 0 ? $start : $criteria->getStart(); // non-zero arg passed to method overrides $criteria setting |
||
| 315 | } |
||
| 316 | $sql .= " GROUP BY o.{$this->keyName}, o.tag_term, o.tag_status"; |
||
| 317 | |||
| 318 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 319 | $sort = \mb_strtolower($sort); |
||
| 320 | switch ($sort) { |
||
| 321 | case 'a': |
||
| 322 | case 'alphabet': |
||
| 323 | $order = 'ASC'; |
||
| 324 | $sql .= " ORDER BY o.tag_term {$order}"; |
||
| 325 | break; |
||
| 326 | case 'id': |
||
| 327 | case 'time': |
||
| 328 | $sql .= " ORDER BY o.{$this->keyName} {$order}"; |
||
| 329 | break; |
||
| 330 | case 'c': |
||
| 331 | case 'count': |
||
| 332 | default: |
||
| 333 | $order = 'DESC'; |
||
| 334 | $sql .= " ORDER BY count {$order}"; |
||
| 335 | break; |
||
| 336 | } |
||
| 337 | |||
| 338 | $result = $this->db->query($sql, $limit, $start); |
||
| 339 | if ($result instanceof \mysqli_result) { |
||
| 340 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 341 | $ret[$myrow[$this->keyName]] = [ |
||
| 342 | 'id' => $myrow[$this->keyName], |
||
| 343 | 'term' => \htmlspecialchars($myrow['tag_term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 344 | 'status' => $myrow['tag_status'], |
||
| 345 | 'modid' => $myrow['tag_modid'], |
||
| 346 | 'count' => (int)$myrow['count'], |
||
| 347 | ]; |
||
| 348 | } |
||
| 349 | } else { |
||
| 350 | \trigger_error($this->db->error()); |
||
| 351 | $ret = null; |
||
| 352 | } |
||
| 353 | |||
| 354 | return $ret; |
||
| 355 | } |
||
| 356 | |||
| 357 | /** |
||
| 358 | * Get count of tags |
||
| 359 | * |
||
| 360 | * @param null|\CriteriaElement|\CriteriaCompo $criteria {@link Criteria) |
||
| 361 | */ |
||
| 362 | public function getCount(\CriteriaElement $criteria = null): ?int |
||
| 363 | { |
||
| 364 | /* |
||
| 365 | $catid = (int)($catid); |
||
| 366 | $modid = (int)($modid); |
||
| 367 | */ |
||
| 368 | $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}"; |
||
| 369 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 370 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 371 | } |
||
| 372 | /* |
||
| 373 | $sql_where = " WHERE 1 = 1"; |
||
| 374 | if (!empty($modid)) { |
||
| 375 | $sql_where .= " AND l.tag_modid = {$modid}"; |
||
| 376 | } |
||
| 377 | if (empty($catid) || $catid > 0) { |
||
| 378 | $sql_where .= " AND l.tag_catid = {$catid}"; |
||
| 379 | } |
||
| 380 | |||
| 381 | $sql = $sql_select . " " . $sql_from . " " . $sql_where; |
||
| 382 | */ |
||
| 383 | $result = $this->db->query($sql); |
||
| 384 | if ($result instanceof \mysqli_result) { |
||
| 385 | [$ret] = (int)$this->db->fetchRow($result); |
||
| 386 | } else { |
||
| 387 | \trigger_error($this->db->error()); |
||
| 388 | $ret = 0; |
||
| 389 | } |
||
| 390 | |||
| 391 | return $ret; |
||
| 392 | } |
||
| 393 | |||
| 394 | /** |
||
| 395 | * Get items linked with a tag |
||
| 396 | * |
||
| 397 | * @param \CriteriaElement|null $criteria {@link Criteria} |
||
| 398 | * @return array associative array of items[] => (id, modid, catid, time) |
||
| 399 | */ |
||
| 400 | public function getItems(\CriteriaElement $criteria = null): array |
||
| 401 | { |
||
| 402 | $ret = []; |
||
| 403 | $sql = ' SELECT o.tl_id, o.tag_itemid, o.tag_modid, o.tag_catid, o.tag_time'; |
||
| 404 | $sql .= " FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 405 | |||
| 406 | $limit = Constants::UNLIMITED; |
||
| 407 | $start = Constants::BEGINNING; |
||
| 408 | $sort = ''; |
||
| 409 | $order = ''; |
||
| 410 | if (($criteria instanceof \CriteriaCompo) || ($criteria instanceof \Criteria)) { |
||
| 411 | $sql .= ' ' . $criteria->renderWhere(); |
||
| 412 | $sort = $criteria->getSort(); |
||
| 413 | $order = $criteria->getOrder(); |
||
| 414 | $limit = $criteria->getLimit(); |
||
| 415 | $start = $criteria->getStart(); |
||
| 416 | } |
||
| 417 | |||
| 418 | $order = ('ASC' !== \mb_strtoupper($order)) ? 'DESC' : 'ASC'; |
||
| 419 | $sort = \mb_strtolower($sort); |
||
| 420 | switch ($sort) { |
||
| 421 | case 'i': |
||
| 422 | case 'item': |
||
| 423 | $sql .= " ORDER BY o.tag_itemid {$order}, o.tl_id DESC"; |
||
| 424 | break; |
||
| 425 | case 'm': |
||
| 426 | case 'module': |
||
| 427 | $sql .= " ORDER BY o.tag_modid {$order}, o.tl_id DESC"; |
||
| 428 | break; |
||
| 429 | case 't': |
||
| 430 | case 'time': |
||
| 431 | default: |
||
| 432 | $sql .= " ORDER BY o.tl_id {$order}"; |
||
| 433 | break; |
||
| 434 | } |
||
| 435 | |||
| 436 | $result = $this->db->query($sql, $limit, $start); |
||
| 437 | if ($result instanceof \mysqli_result) { |
||
| 438 | while (false !== ($myrow = $this->db->fetchArray($result))) { |
||
| 439 | $ret[$myrow['tl_id']] = [ |
||
| 440 | 'itemid' => $myrow['tag_itemid'], |
||
| 441 | 'modid' => $myrow['tag_modid'], |
||
| 442 | 'catid' => $myrow['tag_catid'], |
||
| 443 | 'time' => $myrow['tag_time'], |
||
| 444 | ]; |
||
| 445 | } |
||
| 446 | } else { |
||
| 447 | \trigger_error($this->db->error()); |
||
| 448 | } |
||
| 449 | |||
| 450 | return $ret; |
||
| 451 | } |
||
| 452 | |||
| 453 | /** |
||
| 454 | * Get count of items linked with a tag |
||
| 455 | * |
||
| 456 | * @param int $modid id of corresponding module, optional: 0 for all; >1 for a specific module |
||
| 457 | * @param int $catid id of corresponding category, optional |
||
| 458 | * @return int count |
||
| 459 | */ |
||
| 460 | public function getItemCount(int $tag_id, int $modid = 0, int $catid = 0): int |
||
| 461 | { |
||
| 462 | $ret = 0; |
||
| 463 | if ($tag_id = $tag_id) { |
||
| 464 | $sql_select = ' SELECT COUNT(DISTINCT o.tl_id)'; |
||
| 465 | $sql_from = " FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}"; |
||
| 466 | $sql_where = " WHERE o.tag_id = {$tag_id}"; |
||
| 467 | if (!empty($modid)) { |
||
| 468 | $sql_where .= " AND o.tag_modid = {$modid}"; |
||
| 469 | } |
||
| 470 | if (empty($catid) || $catid > 0) { |
||
| 471 | $sql_where .= " AND o.tag_catid = {$catid}"; |
||
| 472 | } |
||
| 473 | |||
| 474 | $sql = $sql_select . ' ' . $sql_from . ' ' . $sql_where; |
||
| 475 | $result = $this->db->query($sql); |
||
| 476 | if ($result instanceof \mysqli_result) { |
||
| 477 | [$temp] = $this->db->fetchRow($result); |
||
| 478 | $ret = (int)$temp[0]; |
||
| 479 | } else { |
||
| 480 | \trigger_error($this->db->error()); |
||
| 481 | $ret = 0; |
||
| 482 | } |
||
| 483 | } |
||
| 484 | |||
| 485 | return $ret; |
||
| 486 | } |
||
| 487 | |||
| 488 | /** |
||
| 489 | * Get detailed data (and font) for a tag |
||
| 490 | * |
||
| 491 | * @param array $tags_array associative array of tags (id, term, status, count) |
||
| 492 | * @return array tag data values for display |
||
| 493 | */ |
||
| 494 | public function getTagData(array $tags_array, int $font_max = 0, int $font_min = 0): array |
||
| 495 | { |
||
| 496 | // $tags_data_array = []; |
||
| 497 | // if (\is_array($tags_array) && !empty($tags_array)) { |
||
| 498 | // // set min and max tag count |
||
| 499 | // $count_array = \array_column($tags_array, 'count', 'id'); |
||
| 500 | // $count_min = \count($count_array) > 0 ? \min($count_array) : 0; |
||
| 501 | // $count_min = max($count_min, 0); |
||
| 502 | // $count_max = \count($count_array) > 0 ? \max($count_array) : 0; |
||
| 503 | // $count_max = max($count_max, 0); |
||
| 504 | // if ($count_max > 0) { |
||
| 505 | // $term_array = \array_column($tags_array, 'term', 'id'); |
||
| 506 | // $tags_term_array = \array_map('\mb_strtolower', $term_array); |
||
| 507 | // \array_multisort($tags_term_array, \SORT_ASC, $tags_array); |
||
| 508 | // $count_interval = $count_max - $count_min; |
||
| 509 | // $level_limit = 5; |
||
| 510 | // |
||
| 511 | // $font_ratio = $count_interval ? ($font_max - $font_min) / $count_interval : 1; |
||
| 512 | // |
||
| 513 | // foreach ($tags_array as $tag) { |
||
| 514 | // /* |
||
| 515 | // * Font-size = ((tag.count - count.min) * (font.max - font.min) / (count.max - count.min) ) * 100% |
||
| 516 | // */ |
||
| 517 | // $font_sz = \floor(($tag['count'] - $count_min) * $font_ratio) + $font_min; |
||
| 518 | // $level_sz = \floor(($tag['count'] - $count_min) * $level_limit / $count_max); |
||
| 519 | // $tags_data_array[] = [ |
||
| 520 | // 'id' => $tag['id'], |
||
| 521 | // 'font' => empty($count_interval) ? 100 : (int)$font_sz, |
||
| 522 | // 'level' => empty($count_max) ? 0 : (int)$level_sz, |
||
| 523 | // 'term' => \urlencode($tag['term']), |
||
| 524 | // 'title' => \htmlspecialchars($tag['term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 525 | // 'count' => $tag['count'], |
||
| 526 | // ]; |
||
| 527 | // } |
||
| 528 | // } |
||
| 529 | // } |
||
| 530 | |||
| 531 | $count_max = 0; |
||
| 532 | $count_min = 0; |
||
| 533 | $tags_term = []; |
||
| 534 | foreach ($tags_array as $tag) { |
||
| 535 | $count_max = \max($count_max, $tag['count']); // set counter to the max tag count |
||
| 536 | $count_min = \min(0, $count_min, $tag['count']); //set counter to the minimum for tag count |
||
| 537 | $tags_term[] = \mb_strtolower($tag['term']); |
||
| 538 | } |
||
| 539 | |||
| 540 | if (!empty($tags_term)) { |
||
| 541 | \array_multisort($tags_term, \SORT_ASC, $tags_array); |
||
| 542 | } |
||
| 543 | $count_interval = $count_max - $count_min; |
||
| 544 | $level_limit = 5; |
||
| 545 | |||
| 546 | // $font_max = $options[2]; |
||
| 547 | // $font_min = $options[3]; |
||
| 548 | $font_ratio = $count_interval ? ($font_max - $font_min) / $count_interval : 1; |
||
| 549 | |||
| 550 | $tags_data_array = []; |
||
| 551 | foreach ($tags_array as $tag) { |
||
| 552 | $tags_data_array[] = [ |
||
| 553 | 'id' => $tag['id'], |
||
| 554 | 'font' => $count_interval ? \floor(($tag['count'] - $count_min) * $font_ratio + $font_min) : 100, |
||
| 555 | 'level' => empty($count_max) ? 0 : \floor(($tag['count'] - $count_min) * $level_limit / $count_max), |
||
| 556 | 'term' => \urlencode($tag['term']), |
||
| 557 | 'title' => \htmlspecialchars($tag['term'], \ENT_QUOTES | \ENT_HTML5), |
||
| 558 | 'count' => $tag['count'], |
||
| 559 | ]; |
||
| 560 | } |
||
| 561 | // unset($tags_array, $tag, $tags_term, $tag_count_array); |
||
| 562 | |||
| 563 | return $tags_data_array; |
||
| 564 | } |
||
| 565 | |||
| 566 | /** |
||
| 567 | * Delete an object as well as links relying on it |
||
| 568 | * |
||
| 569 | * @param \XoopsObject $object $object {@link Tag} |
||
| 570 | * @param bool $force flag to force the query execution despite security settings |
||
| 571 | */ |
||
| 572 | public function delete(\XoopsObject $object, $force = true): bool |
||
| 573 | { |
||
| 574 | /* {@internal - this isn't needed if we type hint Tag object }} |
||
| 575 | if (!is_object($object) || !$object->getVar($this->keyName)) { |
||
| 576 | return false; |
||
| 577 | } |
||
| 578 | */ |
||
| 579 | //$queryFunc = empty($force) ? 'query' : 'queryF'; |
||
| 580 | |||
| 581 | /* |
||
| 582 | * Remove item-tag links |
||
| 583 | */ |
||
| 584 | $helper = \XoopsModules\Tag\Helper::getInstance(); |
||
| 585 | |||
| 586 | /** @var \XoopsModules\Tag\LinkHandler $linkHandler */ |
||
| 587 | $linkHandler = $helper->getHandler('Link'); |
||
| 588 | $criteria = new \Criteria($this->keyName, $object->getVar($this->keyName)); |
||
| 589 | $linkHandler->deleteAll($criteria, $force); |
||
| 590 | //$sql = 'DELETE' . " FROM {$this->table_link}" . " WHERE {$this->keyName} = " . $object->getVar($this->keyName); |
||
| 591 | /* |
||
| 592 | if (false === ($result = $this->db->{$queryFunc}($sql))) { |
||
| 593 | // xoops_error($this->db->error()); |
||
| 594 | } |
||
| 595 | */ |
||
| 596 | /* |
||
| 597 | * Remove stats-tag links |
||
| 598 | */ |
||
| 599 | /** @var \XoopsModules\Tag\StatsHandler $statsHandler */ |
||
| 600 | $statsHandler = $helper->getHandler('Stats'); |
||
| 601 | $criteria = new \Criteria($this->keyName, $object->getVar($this->keyName)); |
||
| 602 | $statsHandler->deleteAll($criteria, $force); |
||
| 603 | //$sql = 'DELETE' . " FROM {$this->table_stats}" . " WHERE {$this->keyName} = " . $object->getVar($this->keyName); |
||
| 604 | |||
| 605 | /* |
||
| 606 | if (false === ($result = $this->db->{$queryFunc}($sql))) { |
||
| 607 | // xoops_error($this->db->error()); |
||
| 608 | } |
||
| 609 | */ |
||
| 610 | |||
| 611 | return parent::delete($object, $force); |
||
| 612 | } |
||
| 613 | |||
| 614 | /** |
||
| 615 | * clean orphan links from database |
||
| 616 | * |
||
| 617 | * @param string $table_link |
||
| 618 | * @param string $field_link |
||
| 619 | * @param string $field_object |
||
| 620 | * @return bool true on success |
||
| 621 | */ |
||
| 622 | public function cleanOrphan($table_link = '', $field_link = '', $field_object = ''): bool |
||
| 628 | } |
||
| 629 | } |
||
| 630 |