BxTimelineDb.php 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  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 Timeline Timeline
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. class BxTimelineDb extends BxBaseModNotificationsDb
  12. {
  13. protected $_sTableEvent2User;
  14. protected $_sTableRepostsTrack;
  15. protected $_sTableHotTrack;
  16. protected $_aTablesMedia;
  17. protected $_aTablesMedia2Events;
  18. /*
  19. * Constructor.
  20. */
  21. function __construct(&$oConfig)
  22. {
  23. parent::__construct($oConfig);
  24. $CNF = &$this->_oConfig->CNF;
  25. $this->_sTableEvent2User = $this->_sPrefix . 'events2users';
  26. $this->_sTableRepostsTrack = $this->_sPrefix . 'reposts_track';
  27. $this->_sTableHotTrack = $this->_sPrefix . 'hot_track';
  28. $this->_aTablesMedia = array(
  29. $CNF['FIELD_PHOTO'] => $this->_sPrefix . 'photos',
  30. $CNF['FIELD_VIDEO'] => $this->_sPrefix . 'videos',
  31. $CNF['FIELD_FILE'] => $this->_sPrefix . 'files'
  32. );
  33. $this->_aTablesMedia2Events = array(
  34. $CNF['FIELD_PHOTO'] => $this->_sPrefix . 'photos2events',
  35. $CNF['FIELD_VIDEO'] => $this->_sPrefix . 'videos2events',
  36. $CNF['FIELD_FILE'] => $this->_sPrefix . 'files2events'
  37. );
  38. }
  39. public function deleteModuleEvents($aData)
  40. {
  41. foreach($aData['handlers'] as $aHandler) {
  42. //Delete system events.
  43. $this->deleteEvent(array('type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
  44. //Delete reposted events.
  45. $aEvents = $this->getEvents(array('browse' => 'reposted_by_descriptor', 'type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
  46. foreach($aEvents as $aEvent) {
  47. $aContent = unserialize($aEvent['content']);
  48. if(isset($aContent['type']) && $aContent['type'] == $aHandler['alert_unit'] && isset($aContent['action']) && $aContent['action'] == $aHandler['alert_action'])
  49. $this->deleteEvent(array('id' => (int)$aEvent['id']));
  50. }
  51. }
  52. }
  53. public function updateStatusAdmin($iContentId, $isActive)
  54. {
  55. $CNF = $this->_oConfig->CNF;
  56. $sQuery = $this->prepare("UPDATE `" . $CNF['TABLE_ENTRIES'] . "` SET `active` = ? WHERE `" . $CNF['FIELD_ID'] . "` = ?", $isActive ? '1' : '0', $iContentId);
  57. return $this->query($sQuery);
  58. }
  59. public function activateModuleEvents($aData, $bActivate = true)
  60. {
  61. $iActivate = $bActivate ? 1 : 0;
  62. foreach($aData['handlers'] as $aHandler) {
  63. //Activate (deactivate) system events.
  64. $this->updateEvent(array('active' => $iActivate), array('type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
  65. //Activate (deactivate) reposted events.
  66. $aEvents = $this->getEvents(array('browse' => 'reposted_by_descriptor', 'type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
  67. foreach($aEvents as $aEvent) {
  68. $aContent = unserialize($aEvent['content']);
  69. if(isset($aContent['type']) && $aContent['type'] == $aHandler['alert_unit'] && isset($aContent['action']) && $aContent['action'] == $aHandler['alert_action'])
  70. $this->updateEvent(array('active' => $iActivate), array('id' => (int)$aEvent['id']));
  71. }
  72. }
  73. }
  74. public function getMaxDuration($aParams)
  75. {
  76. $aParams['browse'] = 'last';
  77. if(isset($aParams['timeline']))
  78. unset($aParams['timeline']);
  79. $aEvent = $this->getEvents($aParams);
  80. if(empty($aEvent) || !is_array($aEvent))
  81. return 0;
  82. $iNowYear = date('Y', time());
  83. return (int)$aEvent['year'] < $iNowYear ? (int)$aEvent['year'] : 0;
  84. }
  85. //--- Repost related methods ---//
  86. public function insertRepostTrack($iEventId, $iAuthorId, $sAuthorIp, $iRepostedId)
  87. {
  88. $iNow = time();
  89. $iAuthorNip = bx_get_ip_hash($sAuthorIp);
  90. $sQuery = $this->prepare("INSERT INTO `{$this->_sTableRepostsTrack}` SET `event_id` = ?, `author_id` = ?, `author_nip` = ?, `reposted_id` = ?, `date` = ?", $iEventId, $iAuthorId, $iAuthorNip, $iRepostedId, $iNow);
  91. return (int)$this->query($sQuery) > 0;
  92. }
  93. public function deleteRepostTrack($iEventId)
  94. {
  95. $sQuery = $this->prepare("DELETE FROM `{$this->_sTableRepostsTrack}` WHERE `event_id` = ?", $iEventId);
  96. return (int)$this->query($sQuery) > 0;
  97. }
  98. public function updateRepostCounter($iId, $iCounter, $iIncrement = 1)
  99. {
  100. return (int)$this->updateEvent(array('reposts' => (int)$iCounter + $iIncrement), array('id' => $iId)) > 0;
  101. }
  102. public function getReposted($sType, $sAction, $iObjectId)
  103. {
  104. $bSystem = $this->_oConfig->isSystem($sType, $sAction);
  105. if($bSystem)
  106. $aParams = array('browse' => 'descriptor', 'type' => $sType, 'action' => $sAction, 'object_id' => $iObjectId);
  107. else
  108. $aParams = array('browse' => 'id', 'value' => $iObjectId);
  109. $aReposted = $this->getEvents($aParams);
  110. if($bSystem && (empty($aReposted) || !is_array($aReposted))) {
  111. $iOwnerId = 0;
  112. $iDate = 0;
  113. $sStatus = BX_TIMELINE_STATUS_DELETED;
  114. $mixedResult = $this->_oConfig->getSystemDataByDescriptor($sType, $sAction, $iObjectId);
  115. if(is_array($mixedResult)) {
  116. $iOwnerId = !empty($mixedResult['owner_id']) ? (int)$mixedResult['owner_id'] : 0;
  117. $iDate = !empty($mixedResult['date']) ? (int)$mixedResult['date'] : 0;
  118. if($this->_oConfig->isUnhideRestored() && !empty($iOwnerId) && !empty($iDate))
  119. $sStatus = BX_TIMELINE_STATUS_ACTIVE;
  120. }
  121. $iId = $this->insertEvent(array(
  122. 'owner_id' => $iOwnerId,
  123. 'type' => $sType,
  124. 'action' => $sAction,
  125. 'object_id' => $iObjectId,
  126. 'object_owner_id' => $iOwnerId,
  127. 'object_privacy_view' => $this->_oConfig->getPrivacyViewDefault('object'),
  128. 'content' => '',
  129. 'title' => '',
  130. 'description' => '',
  131. 'date' => $iDate,
  132. 'status' => $sStatus
  133. ));
  134. $aReposted = $this->getEvents(array('browse' => 'id', 'value' => $iId));
  135. }
  136. return $aReposted;
  137. }
  138. function getRepostedBy($iRepostedId)
  139. {
  140. $sQuery = $this->prepare("SELECT `author_id` FROM `{$this->_sTableRepostsTrack}` WHERE `reposted_id`=?", $iRepostedId);
  141. return $this->getColumn($sQuery);
  142. }
  143. function getReposts($iRepostedId)
  144. {
  145. return $this->getAll("SELECT * FROM `{$this->_sTableRepostsTrack}` WHERE `reposted_id`=:reposted_id", array(
  146. 'reposted_id' => $iRepostedId
  147. ));
  148. }
  149. function isReposted($iRepostedId, $iOwnerId, $iAuthorId)
  150. {
  151. $sQuery = $this->prepare("SELECT
  152. `te`.`id`
  153. FROM `{$this->_sTableRepostsTrack}` AS `tst`
  154. LEFT JOIN `{$this->_sTable}` AS `te` ON `tst`.`event_id`=`te`.`id`
  155. WHERE `tst`.`author_id`=? AND `tst`.`reposted_id`=? AND `te`.`owner_id`=?", $iAuthorId, $iRepostedId, $iOwnerId);
  156. return (int)$this->getOne($sQuery) > 0;
  157. }
  158. //--- Photo uploader related methods ---//
  159. public function saveMedia($sType, $iEventId, $iItemId)
  160. {
  161. return (int)$this->query("INSERT INTO `" . $this->_aTablesMedia2Events[$sType] . "` SET `event_id`=:event_id, `media_id`=:media_id", array(
  162. 'event_id' => $iEventId,
  163. 'media_id' => $iItemId
  164. )) > 0;
  165. }
  166. public function deleteMedia($sType, $iEventId)
  167. {
  168. return (int)$this->query("DELETE FROM `" . $this->_aTablesMedia2Events[$sType] . "` WHERE `event_id`=:event_id", array(
  169. 'event_id' => $iEventId
  170. )) > 0;
  171. }
  172. public function getMedia($sType, $iEventId, $iOffset = 0, $bFullInfo = false)
  173. {
  174. $sTableMedia = $this->_aTablesMedia[$sType];
  175. $sTableMedia2Events = $this->_aTablesMedia2Events[$sType];
  176. $sMethod = 'getColumn';
  177. $sSelectClause = "`tme`.`media_id` AS `id`";
  178. if($bFullInfo) {
  179. $sMethod = 'getAll';
  180. $sSelectClause = "`tm`.*, `tme`.`event_id` AS `event_id`";
  181. }
  182. $sLimitAddon = '';
  183. if($iOffset != 0)
  184. $sLimitAddon = $this->prepareAsString(" OFFSET ?", $iOffset);
  185. $sQuery = $this->prepare("SELECT " . $sSelectClause . "
  186. FROM `" . $sTableMedia2Events . "` AS `tme`
  187. LEFT JOIN `" . $sTableMedia . "` AS `tm` ON `tme`.`media_id`=`tm`.`id`
  188. WHERE `tme`.`event_id`=?" . $sLimitAddon, $iEventId);
  189. return $this->$sMethod($sQuery);
  190. }
  191. public function getMediaById($sType, $iMediaId)
  192. {
  193. $sTableMedia = $this->_aTablesMedia[$sType];
  194. $sTableMedia2Events = $this->_aTablesMedia2Events[$sType];
  195. return $this->getRow("SELECT `tm`.*, `tme`.`event_id` AS `event_id` FROM `" . $sTableMedia2Events . "` AS `tme` LEFT JOIN `" . $sTableMedia . "` AS `tm` ON `tme`.`media_id`=`tm`.`id` WHERE `tme`.`media_id`=:media_id LIMIT 1", array(
  196. 'media_id' => $iMediaId
  197. ));
  198. }
  199. //--- Link attach related methods ---//
  200. public function getUnusedLinks($iUserId)
  201. {
  202. return $this->getLinksBy(array(
  203. 'type' => 'unused',
  204. 'profile_id' => $iUserId
  205. ));
  206. }
  207. public function deleteUnusedLinks($iUserId, $iLinkId = 0)
  208. {
  209. $aBindings = array(
  210. 'profile_id' => $iUserId
  211. );
  212. $sWhereAddon = '';
  213. if(!empty($iLinkId)) {
  214. $aBindings['id'] = $iLinkId;
  215. $sWhereAddon = " AND `id`=:id";
  216. }
  217. return $this->query("DELETE FROM `" . $this->_sPrefix . "links` WHERE `profile_id`=:profile_id" . $sWhereAddon, $aBindings);
  218. }
  219. public function saveLink($iEventId, $iLinkId)
  220. {
  221. $aBindings = array(
  222. 'event_id' => $iEventId,
  223. 'link_id' => $iLinkId
  224. );
  225. $iId = $this->getOne("SELECT `id` FROM `" . $this->_sPrefix . "links2events` WHERE `event_id`=:event_id AND `link_id`=:link_id LIMIT 1", $aBindings);
  226. if(!empty($iId))
  227. return true;
  228. return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "links2events` SET `event_id`=:event_id, `link_id`=:link_id", $aBindings) > 0;
  229. }
  230. public function deleteLink($iId)
  231. {
  232. return (int)$this->query("DELETE FROM `tl`, `tle` USING `" . $this->_sPrefix . "links` AS `tl` LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id` WHERE `tl`.`id` = :id", array(
  233. 'id' => $iId
  234. )) > 0;
  235. }
  236. public function deleteLinks($iEventId)
  237. {
  238. return (int)$this->query("DELETE FROM `tl`, `tle` USING `" . $this->_sPrefix . "links` AS `tl` LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id` WHERE `tle`.`event_id` = :event_id", array(
  239. 'event_id' => $iEventId
  240. )) > 0;
  241. }
  242. public function getLinks($iEventId)
  243. {
  244. return $this->getLinksBy(array('type' => 'event_id', 'event_id' => $iEventId));
  245. }
  246. public function getLinksBy($aParams = array())
  247. {
  248. $CNF = &$this->_oConfig->CNF;
  249. $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
  250. $sSelectClause = "`tl`.*";
  251. $sJoinClause = $sWhereClause = $sGroupClause = $sOrderClause = $sLimitClause = "";
  252. switch($aParams['type']) {
  253. case 'id':
  254. $aMethod['name'] = 'getRow';
  255. $aMethod['params'][1] = array(
  256. 'id' => $aParams['id']
  257. );
  258. $sWhereClause = " AND `tl`.`id`=:id";
  259. if(!empty($aParams['profile_id'])) {
  260. $aMethod['params'][1]['profile_id'] = $aParams['profile_id'];
  261. $sWhereClause .= " AND `tl`.`profile_id`=:profile_id";
  262. }
  263. break;
  264. case 'event_id':
  265. $aMethod['params'][1] = array(
  266. 'event_id' => $aParams['event_id']
  267. );
  268. $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id`";
  269. $sWhereClause = " AND `tle`.`event_id`=:event_id";
  270. break;
  271. case 'unused':
  272. $aBindings = array(
  273. 'profile_id' => $aParams['profile_id']
  274. );
  275. if(isset($aParams['short']) && $aParams['short'] === true) {
  276. $aMethod['name'] = 'getPairs';
  277. $aMethod['params'][1] = 'url';
  278. $aMethod['params'][2] = 'id';
  279. $aMethod['params'][3] = $aBindings;
  280. }
  281. else
  282. $aMethod['params'][1] = $aBindings;
  283. $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id`";
  284. $sWhereClause = " AND `tl`.`profile_id`=:profile_id AND ISNULL(`tle`.`event_id`)";
  285. $sOrderClause = "`tl`.`added` DESC";
  286. break;
  287. }
  288. $sOrderClause = !empty($sOrderClause) ? "ORDER BY " . $sOrderClause : $sOrderClause;
  289. $sLimitClause = !empty($sLimitClause) ? "LIMIT " . $sLimitClause : $sLimitClause;
  290. $aMethod['params'][0] = "SELECT
  291. " . $sSelectClause . "
  292. FROM `" . $this->_sPrefix . "links` AS `tl` " . $sJoinClause . "
  293. WHERE 1" . $sWhereClause . " " . $sGroupClause . " " . $sOrderClause . " " . $sLimitClause;
  294. return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
  295. }
  296. public function getHot()
  297. {
  298. return $this->fromCache($this->_oConfig->getCacheHotKey(), 'getColumn', "SELECT `event_id` FROM `" . $this->_sTableHotTrack . "`");
  299. }
  300. public function clearHot()
  301. {
  302. $this->cleanCache($this->_oConfig->getCacheHotKey());
  303. return $this->query("TRUNCATE TABLE `" . $this->_sTableHotTrack . "`");
  304. }
  305. public function getHotTrackByDate($iInterval = 24)
  306. {
  307. $aBindings = [
  308. 'interval' => $iInterval
  309. ];
  310. $sQuery = "SELECT
  311. `te`.`id` AS `event_id`,
  312. `te`.`date` AS `value`
  313. FROM `" . $this->_sTable . "` AS `te`
  314. WHERE (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `te`.`date` > (UNIX_TIMESTAMP() - 3600 * :interval)";
  315. return $this->getPairs($sQuery, 'event_id', 'value', $aBindings);
  316. }
  317. public function getHotTrackByCommentsDate($sModule, $sTableTrack, $iInterval = 24, $iThresholdAge = 0, $iThresholdCount = 0)
  318. {
  319. $aBindings = [
  320. 'module' => $sModule,
  321. 'interval' => $iInterval
  322. ];
  323. $sQueryWhere = " AND (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`cmt_time` > (UNIX_TIMESTAMP() - 3600 * :interval)";
  324. if($iThresholdAge != 0) {
  325. $aBindings['threshold_age'] = $iThresholdAge;
  326. $sQueryWhere .= " AND (UNIX_TIMESTAMP() - `te`.`date`) / 86400 <= :threshold_age";
  327. }
  328. $sQueryGroup = "`te`.`id`";
  329. if($iThresholdCount != 0) {
  330. $aBindings['threshold_count'] = $iThresholdCount;
  331. $sQueryGroup .= " HAVING COUNT(DISTINCT `tt`.`cmt_author_id`) >= :threshold_count";
  332. }
  333. $sQuery = "SELECT
  334. `te`.`id` as `event_id`,
  335. MAX(`tt`.`cmt_time`) AS `value`
  336. FROM `" . $this->_sTable . "` AS `te`
  337. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`id`=`tt`.`cmt_object_id` AND `te`.`object_owner_id`<>`tt`.`cmt_author_id` AND `te`.`type`=:module
  338. WHERE 1 " . $sQueryWhere . "
  339. GROUP BY " . $sQueryGroup;
  340. return $this->getPairs($sQuery, 'event_id', 'value', $aBindings);
  341. }
  342. public function getHotTrackByCommentsDateModule($sModule, $sTableTrack, $iInterval = 24, $iThresholdAge = 0, $iThresholdCount = 0)
  343. {
  344. $aBindings = [
  345. 'module' => $sModule,
  346. 'interval' => $iInterval
  347. ];
  348. $sQueryWhere = " AND (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`cmt_time` > (UNIX_TIMESTAMP() - 3600 * :interval)";
  349. if($iThresholdAge != 0) {
  350. $aBindings['threshold_age'] = $iThresholdAge;
  351. $sQueryWhere .= " AND (UNIX_TIMESTAMP() - `te`.`date`) / 86400 <= :threshold_age";
  352. }
  353. $sQueryGroup = "`te`.`object_id`";
  354. if($iThresholdCount != 0) {
  355. $aBindings['threshold_count'] = $iThresholdCount;
  356. $sQueryGroup .= " HAVING COUNT(DISTINCT `tt`.`cmt_author_id`) >= :threshold_count";
  357. }
  358. $sQuery = "SELECT
  359. `te`.`id` as `event_id`,
  360. MAX(`tt`.`cmt_time`) AS `value`
  361. FROM `" . $this->_sTable . "` AS `te`
  362. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`object_id`=`tt`.`cmt_object_id` AND `te`.`object_owner_id`<>`tt`.`cmt_author_id` AND `te`.`type`=:module
  363. WHERE 1 " . $sQueryWhere . "
  364. GROUP BY " . $sQueryGroup;
  365. return $this->getPairs($sQuery, 'event_id', 'value', $aBindings);
  366. }
  367. public function getHotTrackByVotesDate($sModule, $sTableTrack, $iInterval = 24, $iThresholdAge = 0, $iThresholdCount = 0)
  368. {
  369. $aBindings = [
  370. 'module' => $sModule,
  371. 'interval' => $iInterval
  372. ];
  373. $sQueryWhere = " AND (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`date` > (UNIX_TIMESTAMP() - 3600 * :interval)";
  374. if($iThresholdAge != 0) {
  375. $aBindings['threshold_age'] = $iThresholdAge;
  376. $sQueryWhere .= " AND (UNIX_TIMESTAMP() - `te`.`date`) / 86400 <= :threshold_age";
  377. }
  378. $sQueryGroup = "`te`.`id`";
  379. if($iThresholdCount != 0) {
  380. $aBindings['threshold_count'] = $iThresholdCount;
  381. $sQueryGroup .= " HAVING COUNT(DISTINCT `tt`.`author_id`) >= :threshold_count";
  382. }
  383. $sQuery = "SELECT
  384. `te`.`id` as `event_id`,
  385. MAX(`tt`.`date`) AS `value`
  386. FROM `" . $this->_sTable . "` AS `te`
  387. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`id`=`tt`.`object_id` AND `te`.`object_owner_id`<>`tt`.`author_id` AND `te`.`type`=:module
  388. WHERE 1 " . $sQueryWhere . "
  389. GROUP BY " . $sQueryGroup;
  390. return $this->getPairs($sQuery, 'event_id', 'value', $aBindings);
  391. }
  392. public function getHotTrackByVotesDateModule($sModule, $sTableTrack, $iInterval = 24, $iThresholdAge = 0, $iThresholdCount = 0)
  393. {
  394. $aBindings = [
  395. 'module' => $sModule,
  396. 'interval' => $iInterval
  397. ];
  398. $sQueryWhere = " AND (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`date` > (UNIX_TIMESTAMP() - 3600 * :interval)";
  399. if($iThresholdAge != 0) {
  400. $aBindings['threshold_age'] = $iThresholdAge;
  401. $sQueryWhere .= " AND (UNIX_TIMESTAMP() - `te`.`date`) / 86400 <= :threshold_age";
  402. }
  403. $sQueryGroup = "`te`.`object_id`";
  404. if($iThresholdCount != 0) {
  405. $aBindings['threshold_count'] = $iThresholdCount;
  406. $sQueryGroup .= " HAVING COUNT(DISTINCT `tt`.`author_id`) >= :threshold_count";
  407. }
  408. $sQuery = "SELECT
  409. `te`.`id` as `event_id`,
  410. MAX(`tt`.`date`) AS `value`
  411. FROM `" . $this->_sTable . "` AS `te`
  412. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`object_id`=`tt`.`object_id` AND `te`.`object_owner_id`<>`tt`.`author_id` AND `te`.`type`=:module
  413. WHERE 1 " . $sQueryWhere . "
  414. GROUP BY " . $sQueryGroup;
  415. return $this->getPairs($sQuery, 'event_id', 'value', $aBindings);
  416. }
  417. /**
  418. * Hot Track by Sum of Votes during specified Period is currently disabled.
  419. */
  420. public function getHotTrackByVotesSum($sModule, $sTableTrack, $iInterval = 24)
  421. {
  422. $sQuery = "SELECT
  423. `te`.`id` as `event_id`,
  424. SUM(`tt`.`value`) AS `value`
  425. FROM `" . $this->_sTable . "` AS `te`
  426. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`id`=`tt`.`object_id` AND `te`.`type`=:module
  427. WHERE (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`date` > (UNIX_TIMESTAMP() - 3600 * :interval)
  428. GROUP BY `te`.`id`";
  429. return $this->getAll($sQuery, array('module' => $sModule, 'interval' => $iInterval));
  430. }
  431. /**
  432. * Hot Track by Sum of Votes during specified Period is currently disabled.
  433. */
  434. public function getHotTrackByVotesSumModule($sModule, $sTableTrack, $iInterval = 24)
  435. {
  436. $sQuery = "SELECT
  437. `te`.`id` as `event_id`,
  438. SUM(`tt`.`value`) AS `value`
  439. FROM `" . $this->_sTable . "` AS `te`
  440. INNER JOIN `" . $sTableTrack . "` AS `tt` ON `te`.`object_id`=`tt`.`object_id` AND `te`.`type`=:module
  441. WHERE (`te`.`system` <> 0 OR `te`.`owner_id` = 0) AND `tt`.`date` > (UNIX_TIMESTAMP() - 3600 * :interval)
  442. GROUP BY `te`.`object_id`";
  443. return $this->getAll($sQuery, array('module' => $sModule, 'interval' => $iInterval));
  444. }
  445. public function updateHotTrack($aTrack)
  446. {
  447. return (int)$this->query("REPLACE INTO `" . $this->_sTableHotTrack . "` SET " . $this->arrayToSQL($aTrack)) > 0;
  448. }
  449. public function getEvents($aParams)
  450. {
  451. bx_alert($this->_oConfig->getName(), 'get_events_before', 0, 0, array(
  452. 'params' => &$aParams,
  453. ));
  454. list($sMethod, $sSelectClause, $mixedJoinClause, $mixedWhereClause, $sOrderClause, $sLimitClause) = $this->_getSqlPartsEvents($aParams);
  455. $bCount = isset($aParams['count']) && $aParams['count'] === true;
  456. if($bCount) {
  457. $sMethod = 'getOne';
  458. $sSelectClause = 'COUNT(*)';
  459. $sOrderClause = '';
  460. $sLimitClause = '';
  461. }
  462. $aAlertParams = $aParams;
  463. unset($aAlertParams['browse']);
  464. bx_alert($this->_oConfig->getName(), 'get_events', 0, 0, array(
  465. 'browse' => $aParams['browse'],
  466. 'params' => $aAlertParams,
  467. 'table' => $this->_sTable,
  468. 'method' => &$sMethod,
  469. 'select_clause' => &$sSelectClause,
  470. 'join_clause' => &$mixedJoinClause,
  471. 'where_clause' => &$mixedWhereClause,
  472. 'order_clause' => &$sOrderClause,
  473. 'limit_clause' => &$sLimitClause
  474. ));
  475. $sSqlMask = "SELECT {select}
  476. FROM `{$this->_sTable}`
  477. INNER JOIN `sys_profiles` ON `{$this->_sTable}`.`object_owner_id`=`sys_profiles`.`id` AND `sys_profiles`.`status`='active' LEFT JOIN `{$this->_sTableHandlers}` ON `{$this->_sTable}`.`type`=`{$this->_sTableHandlers}`.`alert_unit` AND `{$this->_sTable}`.`action`=`{$this->_sTableHandlers}`.`alert_action` {join}
  478. WHERE 1 {where} {order} {limit}";
  479. if(is_string($mixedWhereClause)) {
  480. $aSqlMarkers = array(
  481. 'select' => $sSelectClause,
  482. 'join' => $mixedJoinClause,
  483. 'where' => $mixedWhereClause,
  484. 'order' => $sOrderClause,
  485. 'limit' => $sLimitClause
  486. );
  487. return $this->$sMethod(bx_replace_markers($sSqlMask, $aSqlMarkers));
  488. }
  489. $bJoinAsArray = !empty($mixedJoinClause) && is_array($mixedJoinClause);
  490. $sOrderSubclause = $sLimitSubclause = '';
  491. if(!$bCount) {
  492. $sOrderSubclause = $sOrderClause;
  493. $sLimitSubclause = isset($aParams['per_page']) ? 'LIMIT 0, ' . ($aParams['start'] + $aParams['per_page']) : '';
  494. }
  495. $aSqlParts = array();
  496. foreach($mixedWhereClause as $sKey => $sValue) {
  497. $aSqlMarkers = array(
  498. 'select' => $sSelectClause,
  499. 'join' => $bJoinAsArray ? (isset($mixedJoinClause[$sKey]) ? $mixedJoinClause[$sKey] : '') : $mixedJoinClause,
  500. 'where' => $sValue,
  501. 'order' => $sOrderSubclause,
  502. 'limit' => $sLimitSubclause
  503. );
  504. $sSqlPart = bx_replace_markers($sSqlMask, $aSqlMarkers);
  505. $aSqlParts[] = !$bCount ? $sSqlPart : (int)$this->$sMethod($sSqlPart);
  506. }
  507. return $bCount ? array_sum($aSqlParts) : $this->$sMethod(bx_replace_markers('(' . implode(') UNION (', $aSqlParts) . ') {order} {limit}', array(
  508. 'order' => str_replace('`' . $this->_sTable . '`.', '', $sOrderClause),
  509. 'limit' => str_replace('`' . $this->_sTable . '`.', '', $sLimitClause),
  510. )));
  511. }
  512. protected function _getFilterAddon($iOwnerId, $sFilter)
  513. {
  514. switch($sFilter) {
  515. /**
  516. * Direct posts in Timeline made by a timeline owner ($iOwnerId)
  517. */
  518. case BX_TIMELINE_FILTER_OWNER:
  519. $sFilterAddon = $this->prepareAsString(" AND `{$this->_sTable}`.`action`='' AND `{$this->_sTable}`.`object_id`=? ", $iOwnerId);
  520. break;
  521. /**
  522. * Direct posts in Timeline made by users except a timeline owner ($iOwnerId)
  523. */
  524. case BX_TIMELINE_FILTER_OTHER:
  525. $sFilterAddon = $this->prepareAsString(" AND `{$this->_sTable}`.`action`='' AND `{$this->_sTable}`.`object_id`<>? ", $iOwnerId);
  526. break;
  527. /**
  528. * All (Direct and System) posts in Timeline (owned by $iOwnerId) made by users except the viewer
  529. */
  530. case BX_TIMELINE_FILTER_OTHER_VIEWER:
  531. $sFilterAddon = $this->prepareAsString(" AND (`{$this->_sTable}`.`action`<>'' OR (`{$this->_sTable}`.`action`='' AND `{$this->_sTable}`.`object_id`<>?)) ", bx_get_logged_profile_id());
  532. break;
  533. case BX_TIMELINE_FILTER_ALL:
  534. default:
  535. $sFilterAddon = "";
  536. }
  537. return $sFilterAddon;
  538. }
  539. protected function _getSqlPartsEvents($aParams)
  540. {
  541. $sMethod = 'getAll';
  542. $sSelectClause = "`{$this->_sTable}`.*";
  543. $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
  544. switch($aParams['browse']) {
  545. case 'owner_id':
  546. $sWhereClause = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`=? ", $aParams['value']);
  547. break;
  548. case 'common_by_object':
  549. $sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
  550. $sWhereClause = $this->prepareAsString("AND `{$this->_sTable}`.`system`='0' AND `{$this->_sTable}`.`object_id`=? ", $aParams['value']);
  551. break;
  552. case 'descriptor':
  553. $sMethod = 'getRow';
  554. $sWhereClause = "";
  555. if(isset($aParams['type']))
  556. $sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`type`=? ", $aParams['type']);
  557. if(isset($aParams['action']))
  558. $sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`action`=? ", $aParams['action']);
  559. if(isset($aParams['object_id']))
  560. $sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`object_id`=? ", $aParams['object_id']);
  561. $sLimitClause = "LIMIT 1";
  562. break;
  563. case 'reposted_by_track':
  564. $sJoinClause = $this->prepareAsString("INNER JOIN `" . $this->_sTableRepostsTrack . "` AS `trt` ON `{$this->_sTable}`.`id`=`trt`.`event_id` AND `trt`.`reposted_id`=?", $aParams['value']);
  565. break;
  566. case 'reposted_by_descriptor':
  567. $sWhereClause = "";
  568. if(isset($aParams['type']))
  569. $sWhereClause .= "AND `{$this->_sTable}`.`content` LIKE " . $this->escape('%' . $aParams['type'] . '%');
  570. if(isset($aParams['action']))
  571. $sWhereClause .= "AND `{$this->_sTable}`.`content` LIKE " . $this->escape('%' . $aParams['action'] . '%');
  572. break;
  573. case 'list':
  574. list($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause) = parent::_getSqlPartsEvents($aParams);
  575. if(in_array($aParams['type'], array(BX_TIMELINE_TYPE_CHANNELS, BX_TIMELINE_TYPE_FEED, BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS)))
  576. $sSelectClause = "DISTINCT " . $sSelectClause;
  577. break;
  578. case 'ids':
  579. $sWhereClause = "AND `{$this->_sTable}`.`id` IN (" . $this->implode_escape($aParams['ids']) . ") ";
  580. break;
  581. default:
  582. list($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause) = parent::_getSqlPartsEvents($aParams);
  583. }
  584. $sSelectClause .= ", DAYOFYEAR(FROM_UNIXTIME(`{$this->_sTable}`.`date`)) AS `days`, DAYOFYEAR(NOW()) AS `today`, ROUND((UNIX_TIMESTAMP() - `{$this->_sTable}`.`date`)/86400) AS `ago_days`, YEAR(FROM_UNIXTIME(`{$this->_sTable}`.`date`)) AS `year`";
  585. if(in_array($aParams['browse'], array('list', 'ids')) && (!isset($aParams['newest']) || $aParams['newest'] === false)) {
  586. $sOrderClause = "";
  587. switch($aParams['type']) {
  588. case BX_TIMELINE_TYPE_HOT:
  589. $sOrderClause = "`{$this->_sTable}`.`sticked` DESC, `{$this->_sTableHotTrack}`.`value` DESC, ";
  590. break;
  591. case BX_BASE_MOD_NTFS_TYPE_PUBLIC:
  592. case BX_BASE_MOD_NTFS_TYPE_CONNECTIONS:
  593. case BX_TIMELINE_TYPE_CHANNELS:
  594. case BX_TIMELINE_TYPE_FEED:
  595. case BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS:
  596. $sOrderClause = "`{$this->_sTable}`.`sticked` DESC, ";
  597. break;
  598. case BX_BASE_MOD_NTFS_TYPE_OWNER:
  599. $sOrderClause = "`{$this->_sTable}`.`pinned` DESC, ";
  600. break;
  601. }
  602. $sOrderClause = "ORDER BY " . $sOrderClause . "`{$this->_sTable}`.`date` DESC, `{$this->_sTable}`.`id` DESC";
  603. }
  604. return array($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause);
  605. }
  606. protected function _getSqlPartsEventsListStatusAdmin($aParams)
  607. {
  608. $iViewerId = !empty($aParams['viewer_id']) ? $aParams['viewer_id'] : bx_get_logged_profile_id();
  609. if(isset($aParams['moderator']) && $aParams['moderator'] === true)
  610. return '';
  611. //--- Check viewer as event author.
  612. $sWhereClause = $this->prepareAsString("`{$this->_sTable}`.`object_owner_id`=?", $iViewerId);
  613. //--- Check viewer as an administrator/moderator of event author.
  614. $aGroups = [];
  615. $aModules = bx_srv('system', 'get_modules_by_type', ['profile']);
  616. foreach($aModules as $aModule) {
  617. $oModule = BxDolModule::getInstance($aModule['name']);
  618. if(!$oModule || !($oModule instanceof BxBaseModGroupsModule))
  619. continue;
  620. $aGroups = array_merge($aGroups, $oModule->getGroupsByFan($iViewerId, [
  621. BX_BASE_MOD_GROUPS_ROLE_ADMINISTRATOR,
  622. BX_BASE_MOD_GROUPS_ROLE_MODERATOR
  623. ]));
  624. }
  625. if(!empty($aGroups))
  626. $sWhereClause .= " OR `{$this->_sTable}`.`object_owner_id` IN (" . $this->implode_escape($aGroups) . ")";
  627. return $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0' AND (" . $sWhereClause . "), 1, `{$this->_sTable}`.`status_admin`=?) ", isset($aParams['status_admin']) ? $aParams['status_admin'] : BX_TIMELINE_STATUS_ACTIVE);
  628. }
  629. protected function _getSqlPartsEventsList($aParams)
  630. {
  631. $sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
  632. $mixedJoinClause = $mixedWhereClause = "";
  633. $sWhereClauseStatus = "AND `{$this->_sTable}`.`active`='1' ";
  634. $sWhereClauseStatus .= $this->prepareAsString("AND `{$this->_sTable}`.`status`=? ", isset($aParams['status']) ? $aParams['status'] : BX_TIMELINE_STATUS_ACTIVE);
  635. $sWhereClauseStatus .= $this->_getSqlPartsEventsListStatusAdmin($aParams);
  636. //--- Apply filter
  637. $sWhereClauseFilter = "";
  638. if(isset($aParams['filter']))
  639. $sWhereClauseFilter = $this->_getFilterAddon($aParams['owner_id'], $aParams['filter']);
  640. //--- Apply timeline
  641. $sWhereClauseTimeline = "";
  642. if(isset($aParams['timeline']) && !empty($aParams['timeline']) && strpos($aParams['timeline'], '-') !== false) {
  643. list($iY, $iM, $iD) = explode('-', $aParams['timeline']);
  644. $sWhereClauseTimeline = $this->prepareAsString("AND `date`<=? ", mktime(23, 59, 59, (int)$iM, (int)$iD, (int)$iY));
  645. }
  646. //--- Apply modules or handlers filter
  647. $sWhereClauseModules = "";
  648. if(!empty($aParams['modules']) && is_array($aParams['modules']))
  649. $sWhereClauseModules = "AND `" . $this->_sTable . "`.`type` IN (" . $this->implode_escape($aParams['modules']) . ") ";
  650. $sWhereClauseHidden = "";
  651. if(empty($sWhereClauseModules)) {
  652. $aHidden = $this->_oConfig->getHandlersHidden();
  653. $sWhereClauseHidden = !empty($aHidden) && is_array($aHidden) ? "AND `" . $this->_sTableHandlers . "`.`id` NOT IN (" . $this->implode_escape($aHidden) . ") " : "";
  654. }
  655. //--- Apply mute filter
  656. $sWhereClauseMuted = "";
  657. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('connection_mute'));
  658. if($oConnection) {
  659. $aMuted = $oConnection->getConnectedContent(bx_get_logged_profile_id());
  660. if(!empty($aMuted) && is_array($aMuted)) {
  661. $sMuted = "NOT IN (". $this->implode_escape($aMuted) . ")";
  662. $sWhereClauseMuted = "AND `{$this->_sTable}`.`owner_id` $sMuted AND `{$this->_sTable}`.`object_owner_id` $sMuted ";
  663. }
  664. }
  665. //--- Apply unpublished (date in future) filter
  666. $sWhereClauseUnpublished = $this->prepareAsString("AND IF(`{$this->_sTable}`.`system`='0' AND `{$this->_sTable}`.`object_id` = ?, 1, `{$this->_sTable}`.`date` <= UNIX_TIMESTAMP()) ", bx_get_logged_profile_id());
  667. //--- Apply content filter
  668. $oCf = BxDolContentFilter::getInstance();
  669. $sWhereClauseCf = $oCf->isEnabled() ? $oCf->getSQLParts($this->_sTable, 'object_cf') . ' ' : '';
  670. //--- Check type
  671. $mixedWhereSubclause = "";
  672. switch($aParams['type']) {
  673. //--- Feed: Hot
  674. case BX_TIMELINE_TYPE_HOT:
  675. //--- Apply privacy filter
  676. $aPrivacyGroups = array(BX_DOL_PG_ALL);
  677. if(isLogged())
  678. $aPrivacyGroups[] = BX_DOL_PG_MEMBERS;
  679. $aQueryParts = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'))->getContentByGroupAsSQLPart($aPrivacyGroups);
  680. $mixedWhereClause .= $aQueryParts['where'] . " ";
  681. //--- Select Hot posts.
  682. $mixedJoinClause .= " LEFT JOIN `{$this->_sTableHotTrack}` ON `{$this->_sTable}`.`id`=`{$this->_sTableHotTrack}`.`event_id`";
  683. $mixedWhereSubclause = "NOT ISNULL(`{$this->_sTableHotTrack}`.`value`)";
  684. //--- Select Promoted posts.
  685. $mixedWhereSubclause .= " OR `{$this->_sTable}`.`promoted` <> '0'";
  686. break;
  687. //--- Feed: Public
  688. case BX_BASE_MOD_NTFS_TYPE_PUBLIC:
  689. //--- Apply privacy filter
  690. $aPrivacyGroups = array(BX_DOL_PG_ALL);
  691. if(isLogged())
  692. $aPrivacyGroups[] = BX_DOL_PG_MEMBERS;
  693. $aQueryParts = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'))->getContentByGroupAsSQLPart($aPrivacyGroups);
  694. $mixedWhereClause .= $aQueryParts['where'] . " ";
  695. if($this->_oConfig->isShowAll())
  696. break;
  697. //--- Select All System posts
  698. $mixedWhereSubclause = "`{$this->_sTable}`.`system`='1'";
  699. //--- Select Public (Direct) posts created on Home Page Timeline (Public Feed)
  700. $mixedWhereSubclause .= $this->prepareAsString(" OR `{$this->_sTable}`.`owner_id`=?", 0);
  701. //--- Select Promoted posts.
  702. $mixedWhereSubclause .= " OR `{$this->_sTable}`.`promoted` <> '0'";
  703. break;
  704. //--- Feed: Profile
  705. case BX_BASE_MOD_NTFS_TYPE_OWNER:
  706. if(empty($aParams['owner_id']))
  707. break;
  708. //--- Select Own (System and Direct) posts from Profile's Timeline.
  709. $mixedWhereSubclause = $this->prepareAsString("(`{$this->_sTable}`.`owner_id` = ?)", $aParams['owner_id']);
  710. //--- Select Own Public (Direct) posts from Home Page Timeline (Public Feed).
  711. $mixedWhereSubclause .= $this->prepareAsString(" OR (`{$this->_sTable}`.`owner_id` = '0' AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` = ?, 1))", $aParams['owner_id']);
  712. break;
  713. //--- Feed: All Profile Connections
  714. case BX_BASE_MOD_NTFS_TYPE_CONNECTIONS:
  715. if(empty($aParams['owner_id']))
  716. break;
  717. $mixedJoinClause = array();
  718. $mixedWhereSubclause = array();
  719. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  720. //--- Join System and Direct posts received by and made by following members. 'LEFT' join is essential to apply different conditions.
  721. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
  722. $aJoin1 = $aQueryParts['join'];
  723. $mixedJoinClause['p1'] = "LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
  724. $mixedWhereSubclause['p1'] = "NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
  725. //--- Exclude Own (Direct) posts on timelines of following members.
  726. //--- Note. Disabled for now.
  727. //$mixedWhereSubclause['p1'] .= $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1)", $aParams['owner_id']);
  728. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'object_id', $aParams['owner_id']);
  729. $aJoin2 = $aQueryParts['join'];
  730. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'object_id', $aParams['owner_id']);
  731. $aJoin2 = $aQueryParts['join'];
  732. $aJoin2['table_alias'] = 'cc';
  733. $aJoin2['condition'] = str_replace('`c`', '`' . $aJoin2['table_alias'] . '`', $aJoin2['condition']);
  734. $mixedJoinClause['p2'] = "LEFT JOIN `" . $aJoin2['table'] . "` AS `" . $aJoin2['table_alias'] . "` ON `" . $this->_sTable . "`.`system`='0' AND " . $aJoin2['condition'];
  735. $mixedWhereSubclause['p2'] = "NOT ISNULL(`" . $aJoin2['table_alias'] . "`.`content`)";
  736. //--- Select Promoted posts.
  737. $mixedWhereSubclause['p3'] = "`{$this->_sTable}`.`promoted` <> '0'";
  738. break;
  739. //--- Feed: Profile Connections to Channel contexts only
  740. case BX_TIMELINE_TYPE_CHANNELS:
  741. if(empty($aParams['owner_id']))
  742. break;
  743. $mixedJoinClause = array();
  744. $mixedWhereSubclause = array();
  745. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  746. //--- Join System posts received by following channels.
  747. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
  748. $aJoin1 = $aQueryParts['join'];
  749. $mixedJoinClause['p1'] = "LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
  750. $mixedWhereSubclause['p1'] = "`{$this->_sTable}`.`type`='bx_channels' AND NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
  751. //--- Exclude Own (Direct) posts on timelines of following members.
  752. //--- Note. Disabled for now.
  753. //$mixedWhereSubclause['p1'] = $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1)", $aParams['owner_id']);
  754. //--- Select Promoted posts.
  755. $mixedWhereSubclause['p2'] = "`{$this->_sTable}`.`promoted` <> '0'";
  756. break;
  757. //--- Feed: Profile + Profile Connections to Non-Channel contexts
  758. case BX_TIMELINE_TYPE_FEED:
  759. if(empty($aParams['owner_id']))
  760. break;
  761. $mixedJoinClause = array();
  762. $mixedWhereSubclause = array();
  763. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  764. //--- Select Own (System and Direct) posts from Profile's Timeline.
  765. $sWhereSubclauseOwnProfile = $this->prepareAsString("(`{$this->_sTable}`.`owner_id` = ?)", $aParams['owner_id']);
  766. //--- Select Own Public (Direct) posts from Home Page Timeline (Public Feed).
  767. $sWhereSubclauseOwnPublic = $this->prepareAsString("(`{$this->_sTable}`.`owner_id` = '0' AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` = ?, 1))", $aParams['owner_id']);
  768. $mixedWhereSubclause['p1'] = "(" . $sWhereSubclauseOwnProfile . " OR " . $sWhereSubclauseOwnPublic . ")";
  769. //--- Join System and Direct posts received by and made by following members. 'LEFT' join is essential to apply different conditions.
  770. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
  771. $aJoin1 = $aQueryParts['join'];
  772. $mixedJoinClause['p2'] = "LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
  773. $mixedWhereSubclause['p2'] = "`{$this->_sTable}`.`type`<>'bx_channels' AND NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
  774. //--- Exclude Own (Direct) posts on timelines of following members.
  775. //--- Note. Disabled for now and next check is used instead.
  776. //$mixedWhereSubclause['p2'] = $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1))", $aParams['owner_id']);
  777. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'object_owner_id', $aParams['owner_id']);
  778. $aJoin2 = $aQueryParts['join'];
  779. $aJoin2['table_alias'] = 'cc';
  780. $aJoin2['condition'] = str_replace('`c`', '`' . $aJoin2['table_alias'] . '`', $aJoin2['condition']);
  781. $mixedJoinClause['p3'] = "LEFT JOIN `" . $aJoin2['table'] . "` AS `" . $aJoin2['table_alias'] . "` ON `" . $this->_sTable . "`.`system` = 0 AND `" . $this->_sTable . "`.`object_privacy_view` > 0 AND " . $aJoin2['condition'];
  782. $mixedWhereSubclause['p3'] = "NOT ISNULL(`" . $aJoin2['table_alias'] . "`.`content`)";
  783. //--- Select Promoted posts.
  784. $mixedWhereSubclause['p4'] = "`{$this->_sTable}`.`promoted` <> '0'";
  785. break;
  786. //--- Feed: Profile + All Profile Connections
  787. case BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS:
  788. if(empty($aParams['owner_id']))
  789. break;
  790. $mixedJoinClause = array();
  791. $mixedWhereSubclause = array();
  792. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  793. //--- Select Own (System and Direct) posts from Profile's Timeline.
  794. $sWhereSubclauseOwnProfile = $this->prepareAsString("(`{$this->_sTable}`.`owner_id` = ?)", $aParams['owner_id']);
  795. //--- Select Own Public (Direct) posts from Home Page Timeline (Public Feed).
  796. $sWhereSubclauseOwnPublic = $this->prepareAsString("(`{$this->_sTable}`.`owner_id` = '0' AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` = ?, 1))", $aParams['owner_id']);
  797. $mixedWhereSubclause['p1'] = "(" . $sWhereSubclauseOwnProfile . " OR " . $sWhereSubclauseOwnPublic . ")";
  798. //--- Join System and Direct posts received by and made by following members. 'LEFT' join is essential to apply different conditions.
  799. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
  800. $aJoin1 = $aQueryParts['join'];
  801. $mixedJoinClause['p2'] = "LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
  802. $mixedWhereSubclause['p2'] = "NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
  803. //--- Exclude Own (Direct) posts on timelines of following members.
  804. //--- Note. Disabled for now and next check is used instead.
  805. //$mixedWhereSubclause['p2'] = $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1))", $aParams['owner_id']);
  806. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'object_id', $aParams['owner_id']);
  807. $aJoin2 = $aQueryParts['join'];
  808. $aJoin2['table_alias'] = 'cc';
  809. $aJoin2['condition'] = str_replace('`c`', '`' . $aJoin2['table_alias'] . '`', $aJoin2['condition']);
  810. $mixedJoinClause['p3'] = "LEFT JOIN `" . $aJoin2['table'] . "` AS `" . $aJoin2['table_alias'] . "` ON `" . $this->_sTable . "`.`system`='0' AND " . $aJoin2['condition'];
  811. $mixedWhereSubclause['p3'] = "NOT ISNULL(`" . $aJoin2['table_alias'] . "`.`content`)";
  812. //--- Select Promoted posts.
  813. $mixedWhereSubclause['p4'] = "`{$this->_sTable}`.`promoted` <> '0'";
  814. break;
  815. //--- Feed: Profile Connections to contexts from Selected module
  816. default:
  817. if(empty($aParams['owner_id']))
  818. break;
  819. $mixedJoinClause = [];
  820. $mixedWhereSubclause = [];
  821. $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
  822. //--- Join System posts received by following channels.
  823. $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
  824. $aJoin1 = $aQueryParts['join'];
  825. $mixedJoinClause['p1'] = "INNER JOIN `sys_profiles` AS `p` ON `" . $this->_sTable ."`.`owner_id`=`p`.`id` AND `p`.`type`='" . $aParams['type'] . "'";
  826. $mixedJoinClause['p1'] .= " LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
  827. $mixedWhereSubclause['p1'] = "NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
  828. if(!empty($aParams['context']))
  829. $mixedWhereSubclause['p1'] .= $this->prepareAsString(" AND `" . $aJoin1['table_alias'] . "`.`content`=?", $aParams['context']);
  830. //--- Exclude Own (Direct) posts on timelines of following members.
  831. //--- Note. Disabled for now.
  832. //$mixedWhereSubclause['p1'] = $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1)", $aParams['owner_id']);
  833. //--- Select Promoted posts.
  834. $mixedWhereSubclause['p2'] = "`" . $this->_sTable . "`.`promoted` <> '0'";
  835. break;
  836. }
  837. $aAlertParams = $aParams;
  838. unset($aAlertParams['type'], $aAlertParams['owner_id']);
  839. bx_alert($this->_oConfig->getName(), 'get_list_by_type', 0, 0, array(
  840. 'type' => $aParams['type'],
  841. 'owner_id' => $aParams['owner_id'],
  842. 'params' => $aAlertParams,
  843. 'table' => $this->_sTable,
  844. 'join_clause' => &$mixedJoinClause,
  845. 'where_clause' => &$mixedWhereClause,
  846. 'where_clause_status' => &$sWhereClauseStatus,
  847. 'where_clause_filter' => &$sWhereClauseFilter,
  848. 'where_clause_timeline' => &$sWhereClauseTimeline,
  849. 'where_clause_modules' => &$sWhereClauseModules,
  850. 'where_clause_hidden' => &$sWhereClauseHidden,
  851. 'where_clause_muted' => &$sWhereClauseMuted,
  852. 'where_clause_unpublished' => &$sWhereClauseUnpublished,
  853. 'where_clause_cf' => &$sWhereClauseCf,
  854. 'where_subclause' => &$mixedWhereSubclause
  855. ));
  856. $mixedWhereClause .= $sWhereClauseStatus;
  857. $mixedWhereClause .= $sWhereClauseFilter;
  858. $mixedWhereClause .= $sWhereClauseTimeline;
  859. $mixedWhereClause .= $sWhereClauseModules;
  860. $mixedWhereClause .= $sWhereClauseHidden;
  861. $mixedWhereClause .= $sWhereClauseMuted;
  862. $mixedWhereClause .= $sWhereClauseUnpublished;
  863. $mixedWhereClause .= $sWhereClauseCf;
  864. if(!empty($mixedWhereSubclause)) {
  865. if(is_array($mixedWhereSubclause)) {
  866. $aWhereClause = array();
  867. foreach($mixedWhereSubclause as $sKey => $sValue)
  868. $aWhereClause[$sKey] = $mixedWhereClause . "AND " . $sValue . " ";
  869. $mixedWhereClause = $aWhereClause;
  870. }
  871. else
  872. $mixedWhereClause .= "AND (" . $mixedWhereSubclause . ") ";
  873. }
  874. return array($mixedJoinClause, $mixedWhereClause);
  875. }
  876. public function getMenuItemMaxOrder($sSetName)
  877. {
  878. return $this->getOne("SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`=:set_name LIMIT 1", [
  879. 'set_name' => $sSetName
  880. ]);
  881. }
  882. public function getMenuItemId($sSetName, $sName)
  883. {
  884. return (int)$this->getOne("SELECT `id` FROM `sys_menu_items` WHERE `set_name`=:set_name AND `name`=:name LIMIT 1", [
  885. 'set_name' => $sSetName,
  886. 'name' => $sName
  887. ]);
  888. }
  889. public function insertMenuItem($sSetName, $sModule, $sName, $sTitle, $iOrder)
  890. {
  891. return $this->query("INSERT INTO `sys_menu_items` SET " . $this->arrayToSQL([
  892. 'set_name' => $sSetName,
  893. 'module' => $sModule,
  894. 'name' => $sName,
  895. 'title_system' => $sTitle,
  896. 'title' => $sTitle,
  897. 'link' => 'javascript:void(0)',
  898. 'onclick' => "javascript:{js_object_view}.changeFeed(this, '" . $sModule . "')",
  899. 'target' => '_self',
  900. 'collapsed' => 1,
  901. 'order' => $iOrder
  902. ]));
  903. }
  904. public function deleteMenuItem($sSetName, $sName)
  905. {
  906. return $this->query("DELETE FROM `sys_menu_items` WHERE `set_name`=:set_name AND `name`=:name LIMIT 1", [
  907. 'set_name' => $sSetName,
  908. 'name' => $sName
  909. ]);
  910. }
  911. }
  912. /** @} */