PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libraries/kunena/forum/topic/user/helper.php

https://github.com/xillibit/Kunena-forum
PHP | 526 lines | 341 code | 73 blank | 112 comment | 21 complexity | cb4f5d720b3e13507f081393685a9c78 MD5 | raw file
  1. <?php
  2. /**
  3. * Kunena Component
  4. *
  5. * @package Kunena.Framework
  6. * @subpackage Forum.Topic.User
  7. *
  8. * @copyright Copyright (C) 2008 - 2020 Kunena Team. All rights reserved.
  9. * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL
  10. * @link https://www.kunena.org
  11. **/
  12. defined('_JEXEC') or die();
  13. use Joomla\CMS\Factory;
  14. use Joomla\Database\Exception\ExecutionFailureException;
  15. /**
  16. * Kunena Forum Topic User Helper Class
  17. *
  18. * @since Kunena
  19. */
  20. abstract class KunenaForumTopicUserHelper
  21. {
  22. /**
  23. * @var array|KunenaForumTopicUser[]
  24. * @since Kunena
  25. */
  26. protected static $_instances = array();
  27. /**
  28. * @var array|KunenaForumTopicUser[]
  29. * @since Kunena
  30. */
  31. protected static $_topics = array();
  32. /**
  33. * Returns KunenaForumTopicUser object.
  34. *
  35. * @param KunenaForumTopic|int|null $topic topic
  36. * @param mixed $user user
  37. * @param bool $reload reload
  38. *
  39. * @return KunenaForumTopicUser
  40. * @since Kunena
  41. * @throws Exception
  42. */
  43. public static function get($topic = null, $user = null, $reload = false)
  44. {
  45. if ($topic instanceof KunenaForumTopic)
  46. {
  47. $topic = $topic->id;
  48. }
  49. $topic = intval($topic);
  50. $user = KunenaUserHelper::get($user);
  51. if ($topic < 1)
  52. {
  53. return new KunenaForumTopicUser(null, $user);
  54. }
  55. if ($reload || empty(self::$_instances [$user->userid][$topic]))
  56. {
  57. $topics = self::getTopics($topic, $user);
  58. self::$_instances [$user->userid][$topic] = self::$_topics [$topic][$user->userid] = array_pop($topics);
  59. }
  60. return self::$_instances [$user->userid][$topic];
  61. }
  62. /**
  63. * @param bool|array $ids ids
  64. * @param mixed $user user
  65. *
  66. * @return KunenaForumTopicUser[]
  67. * @since Kunena
  68. * @throws Exception
  69. */
  70. public static function getTopics($ids = false, $user = null)
  71. {
  72. $user = KunenaUserHelper::get($user);
  73. if ($ids === false)
  74. {
  75. return isset(self::$_instances[$user->userid]) ? self::$_instances[$user->userid] : array();
  76. }
  77. elseif (!is_array($ids))
  78. {
  79. $ids = array($ids);
  80. }
  81. // Convert topic objects into ids
  82. foreach ($ids as $i => $id)
  83. {
  84. if ($id instanceof KunenaForumTopic)
  85. {
  86. $ids[$i] = $id->id;
  87. }
  88. }
  89. $ids = array_unique($ids);
  90. self::loadTopics($ids, $user);
  91. $list = array();
  92. foreach ($ids as $id)
  93. {
  94. if (!empty(self::$_instances [$user->userid][$id]))
  95. {
  96. $list [$id] = self::$_instances [$user->userid][$id];
  97. }
  98. }
  99. return $list;
  100. }
  101. /**
  102. * @param array $ids ids
  103. * @param KunenaUser $user user
  104. *
  105. * @return void
  106. * @since Kunena
  107. * @throws Exception
  108. */
  109. protected static function loadTopics(array $ids, KunenaUser $user)
  110. {
  111. foreach ($ids as $i => $id)
  112. {
  113. $id = intval($id);
  114. if (!$id || isset(self::$_instances [$user->userid][$id]))
  115. {
  116. unset($ids[$i]);
  117. }
  118. }
  119. if (empty($ids))
  120. {
  121. return;
  122. }
  123. $idlist = implode(',', $ids);
  124. $db = Factory::getDBO();
  125. $query = $db->getQuery(true);
  126. $query->select('*')
  127. ->from($db->quoteName('#__kunena_user_topics'))
  128. ->where($db->quoteName('user_id') . ' = ' . $db->quote($user->userid))
  129. ->andWhere($db->quoteName('topic_id') . ' IN (' . $idlist . ')');
  130. $db->setQuery($query);
  131. try
  132. {
  133. $results = (array) $db->loadAssocList('topic_id');
  134. }
  135. catch (ExecutionFailureException $e)
  136. {
  137. KunenaError::displayDatabaseError($e);
  138. }
  139. foreach ($ids as $id)
  140. {
  141. if (isset($results[$id]))
  142. {
  143. $instance = new KunenaForumTopicUser;
  144. if (!empty($results))
  145. {
  146. $instance->bind($results[$id]);
  147. }
  148. $instance->exists(true);
  149. self::$_instances [$user->userid][$id] = self::$_topics [$id][$user->userid] = $instance;
  150. }
  151. else
  152. {
  153. self::$_instances [$user->userid][$id] = self::$_topics [$id][$user->userid] = new KunenaForumTopicUser($id, $user->userid);
  154. }
  155. }
  156. unset($results);
  157. }
  158. /**
  159. * Get all user ids who have participated to the given topics.
  160. *
  161. * @param array|KunenaForumTopic[] $topics topics
  162. * @param string $value Row to pick up as value.
  163. *
  164. * @return array List of [topic][userid] = value.
  165. * @since Kunena
  166. * @throws Exception
  167. */
  168. public static function getUserIds(array $topics, $value = 'user_id')
  169. {
  170. // Convert topic objects into ids
  171. $ids = array();
  172. foreach ($topics as $id)
  173. {
  174. if ($id instanceof KunenaForumTopic)
  175. {
  176. $ids[(int) $id->id] = (int) $id->id;
  177. }
  178. else
  179. {
  180. $ids[(int) $id] = (int) $id;
  181. }
  182. }
  183. $idlist = implode(',', $ids);
  184. $db = Factory::getDbo();
  185. $query = $db->getQuery(true);
  186. $query->select('topic_id, user_id')
  187. ->from($db->quoteName('#__kunena_user_topics'))
  188. ->where($db->quoteName('topic_id') . ' IN (' . $idlist . ')')
  189. ->where($db->quoteName('posts') . ' > 0');
  190. $query->select($db->quoteName($value));
  191. $db->setQuery($query);
  192. try
  193. {
  194. $results = (array) $db->loadRowList();
  195. }
  196. catch (ExecutionFailureException $e)
  197. {
  198. KunenaError::displayDatabaseError($e);
  199. }
  200. $list = array();
  201. if (!empty($results))
  202. {
  203. foreach ($results as $result)
  204. {
  205. $list[$result->topic_id][$result->user_id] = $result->{$value};
  206. }
  207. }
  208. return $list;
  209. }
  210. /**
  211. * @param KunenaForumTopic $old old
  212. * @param KunenaForumTopic $new new
  213. *
  214. * @return boolean
  215. * @since Kunena
  216. * @throws Exception
  217. */
  218. public static function move($old, $new)
  219. {
  220. // Update database
  221. $db = Factory::getDBO();
  222. $query = $db->getQuery(true);
  223. $query->update($db->quoteName('#__kunena_user_topics'))
  224. ->set($db->quoteName('topic_id') . ' = ' . $db->quote($new->id))
  225. ->set($db->quoteName('category_id') . ' = ' . $db->quote($new->category_id))
  226. ->where($db->quoteName('topic_id') . ' = ' . $db->quote($old->id));
  227. $db->setQuery($query);
  228. try
  229. {
  230. $db->execute();
  231. }
  232. catch (ExecutionFailureException $e)
  233. {
  234. KunenaError::displayDatabaseError($e);
  235. return false;
  236. }
  237. // Update internal state
  238. if (isset(self::$_topics [$old->id]))
  239. {
  240. if ($new->id != $old->id)
  241. {
  242. self::$_topics [$new->id] = self::$_topics [$old->id];
  243. unset(self::$_topics [$old->id]);
  244. }
  245. foreach (self::$_topics [$new->id] as &$instance)
  246. {
  247. $instance->topic_id = $new->id;
  248. $instance->category_id = $new->category_id;
  249. }
  250. }
  251. return true;
  252. }
  253. /**
  254. * @param KunenaForumTopic $old old
  255. * @param KunenaForumTopic $new new
  256. *
  257. * @return boolean
  258. * @since Kunena
  259. * @throws Exception
  260. */
  261. public static function merge($old, $new)
  262. {
  263. $db = Factory::getDBO();
  264. // Move all user topics which do not exist in new topic
  265. $queries[] = "UPDATE #__kunena_user_topics AS ut
  266. INNER JOIN #__kunena_user_topics AS o ON o.user_id = ut.user_id
  267. SET ut.topic_id={$db->quote($new->id)}, ut.category_id={$db->quote($new->category_id)}
  268. WHERE o.topic_id={$db->quote($old->id)} AND ut.topic_id IS NULL";
  269. // Merge user topics information that exists in both topics
  270. $queries[] = "UPDATE #__kunena_user_topics AS ut
  271. INNER JOIN #__kunena_user_topics AS o ON o.user_id = ut.user_id
  272. SET ut.posts = o.posts + ut.posts,
  273. ut.last_post_id = GREATEST( o.last_post_id, ut.last_post_id ),
  274. ut.owner = GREATEST( o.owner, ut.owner ),
  275. ut.favorite = GREATEST( o.favorite, ut.favorite ),
  276. ut.subscribed = GREATEST( o.subscribed, ut.subscribed )
  277. WHERE ut.topic_id = {$db->quote($new->id)}
  278. AND o.topic_id = {$db->quote($old->id)}";
  279. // Delete all user topics from the shadow topic
  280. $queries[] = "DELETE FROM #__kunena_user_topics WHERE topic_id={$db->quote($old->id)}";
  281. foreach ($queries as $query)
  282. {
  283. $db->setQuery($query);
  284. try
  285. {
  286. $db->execute();
  287. }
  288. catch (ExecutionFailureException $e)
  289. {
  290. KunenaError::displayDatabaseError($e);
  291. return false;
  292. }
  293. }
  294. // Update internal state
  295. self::reloadTopic($old->id);
  296. self::reloadTopic($new->id);
  297. return true;
  298. }
  299. /**
  300. * @param int $id id
  301. *
  302. * @return void
  303. * @since Kunena
  304. * @throws Exception
  305. */
  306. protected static function reloadTopic($id)
  307. {
  308. if (empty(self::$_topics [$id]))
  309. {
  310. return;
  311. }
  312. $idlist = implode(',', array_keys(self::$_topics [$id]));
  313. $db = Factory::getDBO();
  314. $query = $db->getQuery(true);
  315. $query->select('*')
  316. ->from($db->quoteName('#__kunena_user_topics'))
  317. ->where($db->quoteName('user_id') . ' IN (' . $idlist . ')')
  318. ->where($db->quoteName('topic_id') . ' = ' . $db->quote($id));
  319. $db->setQuery($query);
  320. try
  321. {
  322. $results = (array) $db->loadAssocList('user_id');
  323. }
  324. catch (ExecutionFailureException $e)
  325. {
  326. KunenaError::displayDatabaseError($e);
  327. }
  328. // TODO: Is there a bug?
  329. foreach (self::$_topics[$id] as $instance)
  330. {
  331. if (isset($results[$instance->user_id]))
  332. {
  333. $instance->bind($results[$instance->user_id]);
  334. $instance->exists(true);
  335. }
  336. else
  337. {
  338. $instance->reset();
  339. }
  340. }
  341. unset($results);
  342. }
  343. /**
  344. * Free up memory by cleaning up all cached items.
  345. *
  346. * @return void
  347. * @since Kunena
  348. */
  349. public static function cleanup()
  350. {
  351. self::$_instances = array();
  352. self::$_topics = array();
  353. }
  354. /**
  355. * @param bool|array|int $topicids topicids
  356. * @param int $start start
  357. * @param int $end end
  358. *
  359. * @return boolean|integer
  360. * @since Kunena
  361. * @throws Exception
  362. */
  363. public static function recount($topicids = false, $start = 0, $end = 0)
  364. {
  365. $db = Factory::getDBO();
  366. if (is_array($topicids))
  367. {
  368. $where = 'AND m.thread IN (' . implode(',', $topicids) . ')';
  369. $where2 = 'AND ut.topic_id IN (' . implode(',', $topicids) . ')';
  370. $where3 = 'topic_id IN (' . implode(',', $topicids) . ')';
  371. }
  372. elseif ((int) $topicids)
  373. {
  374. $where = 'AND m.thread=' . (int) $topicids;
  375. $where2 = 'AND ut.topic_id=' . (int) $topicids;
  376. $where3 = 'topic_id=' . (int) $topicids;
  377. }
  378. else
  379. {
  380. $where = '';
  381. $where2 = '';
  382. $where3 = '';
  383. }
  384. if ($end)
  385. {
  386. $where .= " AND (m.thread BETWEEN {$start} AND {$end})";
  387. $where2 .= " AND (ut.topic_id BETWEEN {$start} AND {$end})";
  388. $where3 = "(topic_id BETWEEN {$start} AND {$end})";
  389. }
  390. // Create missing user topics and update post count and last post if there are posts by that user
  391. $subQuery = $db->getQuery(true);
  392. $query = $db->getQuery(true);
  393. // Create the base subQuery select statement.
  394. $subQuery->select('m.userid AS `user_id`, m.thread AS `topic_id`, m.catid AS `category_id`, SUM(m.hold=0) AS `posts`, MAX(IF(m.hold=0,m.id,0)) AS `last_post_id`, MAX(IF(m.parent=0,1,0)) AS `owner`')
  395. ->from($db->quoteName('#__kunena_messages', 'm'))
  396. ->where($db->quoteName('m.userid') . ' > 0 AND ' . $db->quoteName('m.moved') . ' = 0 ' . $where)
  397. ->group('m.userid, m.thread');
  398. // Create the base insert statement.
  399. $query->insert($db->quoteName('#__kunena_user_topics') . ' (`user_id`, `topic_id`, `category_id`, `posts`, `last_post_id`, `owner`) ' . $subQuery . '
  400. ON DUPLICATE KEY UPDATE `category_id` = VALUES(`category_id`), `posts` = VALUES(`posts`), `last_post_id` = VALUES(`last_post_id`)');
  401. $db->setQuery($query);
  402. try
  403. {
  404. $db->execute();
  405. }
  406. catch (ExecutionFailureException $e)
  407. {
  408. KunenaError::displayDatabaseError($e);
  409. return false;
  410. }
  411. $rows = $db->getAffectedRows();
  412. // Find user topics where last post doesn't exist and reset values in it
  413. $query = $db->getQuery(true);
  414. $query->update($db->quoteName('#__kunena_user_topics', 'ut'))
  415. ->leftJoin($db->quoteName('#__kunena_messages', 'm') . ' ON ' . $db->quoteName('ut.last_post_id') . ' = ' . $db->quoteName('m.id') . ' AND ' . $db->quoteName('m.hold') . ' = 0')
  416. ->set($db->quoteName('posts') . ' = 0')
  417. ->set($db->quoteName('last_post_id') . ' = 0')
  418. ->where($db->quoteName('m.id') . ' IS NULL ' . $where2);
  419. $db->setQuery($query);
  420. try
  421. {
  422. $db->execute();
  423. }
  424. catch (ExecutionFailureException $e)
  425. {
  426. KunenaError::displayDatabaseError($e);
  427. return false;
  428. }
  429. $rows += $db->getAffectedRows();
  430. // Delete entries that have default values
  431. $query = $db->getQuery(true)
  432. ->delete("#__kunena_user_topics")
  433. ->where(["posts = 0",
  434. "owner = 0",
  435. "favorite = 0",
  436. "subscribed = 0",
  437. "params = ''",
  438. "{$where3}",]
  439. );
  440. $db->setQuery($query);
  441. try
  442. {
  443. $db->execute();
  444. }
  445. catch (ExecutionFailureException $e)
  446. {
  447. KunenaError::displayDatabaseError($e);
  448. return false;
  449. }
  450. $rows += $db->getAffectedRows();
  451. return $rows;
  452. }
  453. }