BxDolVoteReactionsQuery.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. /**
  10. * @see BxDolVote
  11. */
  12. class BxDolVoteReactionsQuery extends BxDolVoteQuery
  13. {
  14. public function __construct(&$oModule)
  15. {
  16. parent::__construct($oModule);
  17. }
  18. public function getVote($iObjectId)
  19. {
  20. $aReactions = $this->_oModule->getReactions();
  21. $aReactionsGot = $this->getAllWithKey('SELECT * FROM ' . $this->_sTable . ' WHERE `object_id` = :object_id ORDER BY `count` DESC', 'reaction', array('object_id' => $iObjectId));
  22. // Free-picked emoji (Many mode) are counted under their code; add the ones this object has.
  23. if($this->_oModule->isFreeEmojiAllowed())
  24. foreach($aReactionsGot as $sName => $aRow)
  25. if((int)$aRow['count'] > 0 && !in_array($sName, $aReactions) && $this->_oModule->getReaction($sName) !== false)
  26. $aReactions[] = $sName;
  27. $aResult = array();
  28. foreach($aReactions as $sName) {
  29. $iCount = $iSum = 0;
  30. if(!empty($aReactionsGot[$sName])) {
  31. $iCount = (int)$aReactionsGot[$sName]['count'];
  32. $iSum = (int)$aReactionsGot[$sName]['sum'];
  33. }
  34. $aResult['count_' . $sName] = $iCount;
  35. $aResult['sum_' . $sName] = $iSum;
  36. $aResult['rate_' . $sName] = $iCount != 0 ? $iSum / $iCount : 0;
  37. }
  38. return $aResult;
  39. }
  40. public function putVote($iObjectId, $iAuthorId, $sAuthorIp, $aData, $bUndo = false)
  41. {
  42. $sReaction = $aData['reaction'];
  43. $aReaction = $this->_oModule->getReaction($sReaction);
  44. if($aReaction === false)
  45. return false;
  46. $iValue = (int)$aData['value'];
  47. $fValueFinal = $iValue * (float)$aReaction['weight'];
  48. $sQuery = "SELECT `object_id` FROM `{$this->_sTable}` WHERE `object_id` = :object_id AND `reaction` = :reaction LIMIT 1";
  49. $bExists = (int)$this->getOne($sQuery, array('object_id' => $iObjectId, 'reaction' => $sReaction)) != 0;
  50. if(!$bExists && $bUndo)
  51. return false;
  52. if(!$bExists)
  53. $sQuery = $this->prepare("INSERT INTO {$this->_sTable} SET `object_id` = ?, `reaction` = ?, `count` = '1', `sum` = ?", $iObjectId, $sReaction, $fValueFinal);
  54. else
  55. $sQuery = $this->prepare("UPDATE `{$this->_sTable}` SET `count` = `count` " . ($bUndo ? "-" : "+") . " 1, `sum` = `sum` " . ($bUndo ? "-" : "+") . " ? WHERE `object_id` = ? AND `reaction` = ?", $fValueFinal, $iObjectId, $sReaction);
  56. if((int)$this->query($sQuery) == 0)
  57. return false;
  58. if($bUndo)
  59. return $this->_deleteTrackReaction($iObjectId, $iAuthorId, $sReaction);
  60. $iNow = time();
  61. $iAuthorNip = bx_get_ip_hash($sAuthorIp);
  62. $sQuery = $this->prepare("INSERT INTO `{$this->_sTableTrack}` SET `object_id` = ?, `author_id` = ?, `author_nip` = ?, `reaction` = ?, `value` = ?, `date` = ?", $iObjectId, $iAuthorId, $iAuthorNip, $sReaction, $iValue, $iNow);
  63. if((int)$this->query($sQuery) > 0)
  64. return $this->lastId();
  65. return false;
  66. }
  67. /**
  68. * The author's reactions to the object, oldest first.
  69. */
  70. public function getReactionsBy($iObjectId, $iAuthorId)
  71. {
  72. return $this->getColumn("SELECT `reaction` FROM `{$this->_sTableTrack}` WHERE `object_id` = :object_id AND `author_id` = :author_id ORDER BY `id` ASC", [
  73. 'object_id' => $iObjectId,
  74. 'author_id' => $iAuthorId
  75. ]);
  76. }
  77. /**
  78. * The author's latest reaction to the object (what the do-button shows).
  79. */
  80. public function getTrackLatest($iObjectId, $iAuthorId)
  81. {
  82. return $this->getRow("SELECT * FROM `{$this->_sTableTrack}` WHERE `object_id` = :object_id AND `author_id` = :author_id ORDER BY `id` DESC LIMIT 1", [
  83. 'object_id' => $iObjectId,
  84. 'author_id' => $iAuthorId
  85. ]);
  86. }
  87. public function getTrackReaction($iObjectId, $iAuthorId, $sReaction)
  88. {
  89. return $this->getRow("SELECT * FROM `{$this->_sTableTrack}` WHERE `object_id` = :object_id AND `author_id` = :author_id AND `reaction` = :reaction LIMIT 1", [
  90. 'object_id' => $iObjectId,
  91. 'author_id' => $iAuthorId,
  92. 'reaction' => $sReaction
  93. ]);
  94. }
  95. protected function _deleteTrackReaction($iObjectId, $iAuthorId, $sReaction)
  96. {
  97. $iId = (int)$this->getOne("SELECT `id` FROM `{$this->_sTableTrack}` WHERE `object_id` = :object_id AND `author_id` = :author_id AND `reaction` = :reaction LIMIT 1", [
  98. 'object_id' => $iObjectId,
  99. 'author_id' => $iAuthorId,
  100. 'reaction' => $sReaction
  101. ]);
  102. if(!$iId)
  103. return false;
  104. if((int)$this->query("DELETE FROM `{$this->_sTableTrack}` WHERE `id` = :id LIMIT 1", ['id' => $iId]) > 0)
  105. return $iId;
  106. return false;
  107. }
  108. public function getSqlParts($sMainTable, $sMainField)
  109. {
  110. if(empty($this->_sTable) || empty($sMainTable) || empty($sMainField))
  111. return array();
  112. $sFields = $sJoin = '';
  113. $aReactions = $this->_oModule->getReactions();
  114. foreach($aReactions as $iIndex => $sName) {
  115. $sFields .= ", `t{$iIndex}`.`count` as `vote_count_{$sName}`, (`t{$iIndex}`.`sum` / `t{$iIndex}`.`count`) AS `vote_rate_{$sName}` ";
  116. $sJoin .= " LEFT JOIN `{$this->_sTable}` AS `t{$iIndex}` ON (`t{$iIndex}`.`object_id` = `{$sMainTable}`.`{$sMainField}` AND `t{$iIndex}`.`reaction` = '{$sName}') ";
  117. }
  118. return array (
  119. 'fields' => $sFields,
  120. 'join' => $sJoin,
  121. );
  122. }
  123. public function getPerformed($aParams = array())
  124. {
  125. $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
  126. $aBindings = array();
  127. $sSelectClause = '`tt`.*';
  128. $sJoinClause = $sWhereClause = '';
  129. $sLimitClause = isset($aParams['start']) && !empty($aParams['per_page']) ? "LIMIT " . $aParams['start'] . ", " . $aParams['per_page'] : "";
  130. if(!empty($aParams['type']))
  131. switch($aParams['type']) {
  132. case 'by':
  133. $aBindings['object_id'] = $aParams['object_id'];
  134. $sJoinClause = "INNER JOIN `sys_profiles` AS `tp` ON `tt`.`author_id`=`tp`.`id` AND `tp`.`status`='active'";
  135. $sWhereClause = "AND `tt`.`object_id` = :object_id";
  136. if(!empty($aParams['reaction'])) {
  137. $aMethod['name'] = 'getColumn';
  138. $aBindings['reaction'] = $aParams['reaction'];
  139. $sSelectClause = "`tt`.`author_id`";
  140. $sWhereClause .= " AND `tt`.`reaction`=:reaction";
  141. }
  142. else {
  143. $aMethod['name'] = 'getAll';
  144. $sSelectClause = "`tt`.`author_id`, `tt`.`reaction`";
  145. }
  146. break;
  147. }
  148. $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $this->_sTableTrack . "` AS `tt` " . $sJoinClause . " WHERE 1 " . $sWhereClause . $sLimitClause;
  149. $aMethod['params'][] = $aBindings;
  150. return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
  151. }
  152. /**
  153. * Update trigger table.
  154. * @param integer $iObjectId - object ID;
  155. * @param array $aEntry - contains data received from BxDolVoteReactionsQuery::getVote method;
  156. * @return boolean - operation result.
  157. */
  158. protected function _updateTriggerTable($iObjectId, $aEntry)
  159. {
  160. $iCounted = $iTotalCount = $fTotalRate = 0;
  161. foreach($aEntry as $sKey => $mixedValue) {
  162. if(strncmp($sKey, 'count_', 6) !== 0)
  163. continue;
  164. $sName = substr($sKey, 6);
  165. $iCount = (int)$mixedValue;
  166. if($iCount == 0)
  167. continue;
  168. $iTotalCount += $iCount;
  169. $fTotalRate += (float)$aEntry['rate_' . $sName];
  170. $iCounted += 1;
  171. }
  172. return (int)$this->query("UPDATE `{$this->_sTriggerTable}` SET `{$this->_sTriggerFieldCount}`=:count, `{$this->_sTriggerFieldRate}`=:rate WHERE `{$this->_sTriggerFieldId}`=:id", array(
  173. 'count' => $iTotalCount,
  174. 'rate' => $iCounted != 0 ? $fTotalRate / $iCounted : 0,
  175. 'id' => $iObjectId
  176. )) > 0;
  177. }
  178. protected function _deleteAuthorEntriesTableMain($aTrack)
  179. {
  180. $aReaction = $this->_oModule->getReaction($aTrack['reaction']);
  181. return $this->query("UPDATE `{$this->_sTable}` SET `count`=`count`-1, `sum`=`sum`-:value WHERE `object_id`=:object_id AND `reaction`=:reaction", array(
  182. 'value' => (int)$aTrack['value'] * (float)$aReaction['weight'],
  183. 'object_id' => $aTrack['object_id'],
  184. 'reaction' => $aTrack['reaction']
  185. ));
  186. }
  187. }
  188. /** @} */