1
0

BxDolLiveUpdates.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. class BxDolLiveUpdates extends BxDolFactory implements iBxDolSingleton
  10. {
  11. protected $_oQuery;
  12. protected $_aSystems;
  13. protected $_aSystemsActive;
  14. protected $_iProfileId;
  15. protected $_iInterval;
  16. protected $_iCacheTTL;
  17. protected $_sCacheKey;
  18. protected $_sJsClass;
  19. protected $_sJsObject;
  20. protected function __construct()
  21. {
  22. parent::__construct();
  23. /**
  24. * Note. Currently Live Updates are associated with profiles (Profile ID) and therefore they are used for logged in members only.
  25. * If it's needed Session ID can be used instead of Profile ID. In this case Live Updates can be used for visitors too. Don't forget
  26. * to update BxBaseLiveUpdates::init if Session ID will be used.
  27. */
  28. $this->_iProfileId = (int)bx_get_logged_profile_id();
  29. if(!$this->_iProfileId)
  30. return;
  31. $this->_oQuery = new BxDolLiveUpdatesQuery();
  32. $this->_iInterval = (int)$this->_oQuery->getParam('sys_live_updates_interval');
  33. $this->_iCacheTTL = 86400;
  34. $this->_sCacheKey = 'sys_live_updates_' . $this->_iProfileId;
  35. $this->_sJsClass = 'BxDolLiveUpdates';
  36. $this->_sJsObject = 'oLiveUpdates';
  37. $this->_aSystems = $this->_getCachedSystems();
  38. $this->_aSystemsActive = array_keys($this->_aSystems);
  39. }
  40. /**
  41. * get live updates instanse
  42. * @return ready to use class instance
  43. */
  44. public static function getInstance()
  45. {
  46. if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
  47. $GLOBALS['bxDolClasses'][__CLASS__] = new BxTemplLiveUpdates();
  48. return $GLOBALS['bxDolClasses'][__CLASS__];
  49. }
  50. /**
  51. *
  52. * Is called via Ajax Requests only.
  53. */
  54. public function perform()
  55. {
  56. $iIndex = (int)bx_get('index');
  57. $mixedSystemsActive = bx_get('systems_active');
  58. if($mixedSystemsActive !== false)
  59. $this->_aSystemsActive = $mixedSystemsActive;
  60. $this->_aSystems = $this->_getCachedSystems();
  61. if(empty($this->_aSystems) || !is_array($this->_aSystems))
  62. return array();
  63. $aCached = $this->_getCachedData();
  64. $aRequested = $this->_getRequestedData($iIndex, true, $aCached);
  65. $aResult = array();
  66. $bUpdateCache = false;
  67. foreach($aRequested as $sName => $aData) {
  68. $bCached = isset($aCached[$sName]);
  69. if($bCached && (int)$aCached[$sName] == (int)$aData['count'])
  70. continue;
  71. if($bCached) {
  72. $aResultData = array('count_new' => $aData['count'], 'count_old' => $aCached[$sName]);
  73. if(isset($aData['data']))
  74. $aResultData = array_merge($aResultData, $aData['data']);
  75. $aResult[] = array(
  76. 'data' => $aResultData,
  77. 'method' => $aData['method']
  78. );
  79. }
  80. $aCached[$sName] = $aData['count'];
  81. $bUpdateCache = true;
  82. }
  83. if($bUpdateCache)
  84. $this->_updateCached('data', $aCached);
  85. return $aResult;
  86. }
  87. /**
  88. *
  89. * Add transient live update for current user on this current page.
  90. * @param string $sName - unique name.
  91. * @param integer $iFrequency - call frequency.
  92. * @param string $sServiceCall - serialized service call.
  93. * @param boolean $bActive - add active/not active live update.
  94. */
  95. public function add($sName, $iFrequency, $sServiceCall, $bActive = true)
  96. {
  97. if(!$this->_iProfileId)
  98. return false;
  99. if(!in_array($sName, $this->_aSystemsActive))
  100. $this->_aSystemsActive[] = $sName;
  101. if(empty($this->_aSystems[$sName])) {
  102. $this->_aSystems[$sName] = array(
  103. 'name' => $sName,
  104. 'frequency' => $iFrequency,
  105. 'service_call' => $sServiceCall,
  106. 'active' => $bActive ? 1 : 0
  107. );
  108. $this->_updateCached('systems', $this->_aSystems);
  109. }
  110. $mixedResponce = $this->_getRequestedDataBySystem($this->_aSystems[$sName]);
  111. if($mixedResponce !== false) {
  112. $aCachedData = $this->_getCachedData();
  113. $aCachedData[$sName] = $mixedResponce['count'];
  114. $this->_updateCached('data', $aCachedData);
  115. }
  116. return true;
  117. }
  118. protected function _getCacheInfo()
  119. {
  120. return array(
  121. $this->_oQuery->getDbCacheObject(),
  122. $this->_oQuery->genDbCacheKey($this->_sCacheKey),
  123. $this->_iCacheTTL
  124. );
  125. }
  126. protected function _getCached($sType)
  127. {
  128. list($oCache, $sCacheKey, $iCacheTtl) = $this->_getCacheInfo();
  129. $aCached = $oCache->getData($sCacheKey, $iCacheTtl);
  130. if(empty($aCached[$sType])) {
  131. switch($sType) {
  132. case 'systems':
  133. $aCached[$sType] = $this->_oQuery->getSystems();
  134. break;
  135. case 'data':
  136. if(!isset($aCached[$sType]))
  137. $aCached[$sType] = array();
  138. $aRequested = $this->_getRequestedData();
  139. foreach($this->_aSystems as $sName => $aSystem)
  140. $aCached[$sType][$sName] = !empty($aRequested[$sName]['count']) ? (int)$aRequested[$sName]['count'] : 0;
  141. break;
  142. }
  143. if(!empty($aCached[$sType]))
  144. $oCache->setData($sCacheKey, $aCached, $iCacheTtl);
  145. }
  146. return $aCached[$sType];
  147. }
  148. protected function _getCachedSystems()
  149. {
  150. $aSystems = $this->_getCached('systems');
  151. if(!empty($aSystems) && !empty($this->_aSystemsActive))
  152. $aSystems = array_intersect_key($aSystems, array_flip($this->_aSystemsActive));
  153. return $aSystems;
  154. }
  155. protected function _getCachedData()
  156. {
  157. return $this->_getCached('data');
  158. }
  159. protected function _updateCached($sKey, $aData)
  160. {
  161. list($oCache, $sCacheKey, $iCacheTtl) = $this->_getCacheInfo();
  162. $aCached = $oCache->getData($sCacheKey, $iCacheTtl);
  163. $aCached[$sKey] = $aData;
  164. $oCache->setData($sCacheKey, $aCached, $iCacheTtl);
  165. }
  166. protected function _getRequestedData($iIndex = 0, $bIndexCheck = false, $aCachedData = array())
  167. {
  168. $aResult = array();
  169. foreach($this->_aSystems as $sName => $aSystem) {
  170. if(empty($aSystem) || !is_array($aSystem) || (int)$aSystem['active'] != 1)
  171. continue;
  172. if($bIndexCheck && $iIndex % (int)$aSystem['frequency'] != 0)
  173. continue;
  174. $mixedResponce = $this->_getRequestedDataBySystem($aSystem, (!empty($aCachedData) && isset($aCachedData[$sName]) ? (int)$aCachedData[$sName] : 0));
  175. if($mixedResponce === false)
  176. continue;
  177. $aResult[$sName] = $mixedResponce;
  178. }
  179. return $aResult;
  180. }
  181. protected function _getRequestedDataBySystem($aSystem, $iCachedData = 0)
  182. {
  183. if(!BxDolService::isSerializedService($aSystem['service_call']))
  184. return false;
  185. $aResponce = BxDolService::callSerialized($aSystem['service_call'], array('count' => (int)$iCachedData));
  186. if(empty($aResponce) || !is_array($aResponce) || !isset($aResponce['count'], $aResponce['method']))
  187. return false;
  188. return $aResponce;
  189. }
  190. }
  191. /** @} */