BxDolConnection.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
  4. * CC-BY License - http://creativecommons.org/licenses/by/3.0/
  5. *
  6. * @defgroup DolphinCore Dolphin Core
  7. * @{
  8. */
  9. bx_import('BxDolConnectionQuery');
  10. /**
  11. * Default limit for connections lists
  12. */
  13. define('BX_CONNECTIONS_LIST_LIMIT', 1000);
  14. /**
  15. * Connections order: no order
  16. */
  17. define('BX_CONNECTIONS_ORDER_NONE', 0);
  18. /**
  19. * Connections order: by addded time, asceding
  20. */
  21. define('BX_CONNECTIONS_ORDER_ADDED_ASC', 1);
  22. /**
  23. * Connections order: by addded time, desceding
  24. */
  25. define('BX_CONNECTIONS_ORDER_ADDED_DESC', 2);
  26. /**
  27. * Connection type: one-way
  28. */
  29. define('BX_CONNECTIONS_TYPE_ONE_WAY', 'one-way');
  30. /**
  31. * Connection type: mutual
  32. */
  33. define('BX_CONNECTIONS_TYPE_MUTUAL', 'mutual');
  34. /**
  35. * @page objects
  36. * @section connection Connection
  37. * @ref BxDolConnection
  38. */
  39. /**
  40. * Connection is usefull when you need to organize some sorts of connections between different content,
  41. * for example: friends, contacts, favorites, block lists, subscriptions, etc.
  42. *
  43. * Two types of connections are supported one way connections (block list, favourites) and mutual (friends).
  44. *
  45. * For automatic handling of connections (like, add/remove connection in frontend) refer to JS function: @see bx_conn_action()
  46. *
  47. * @section connection_create Creating the Connection object:
  48. *
  49. * Step 1:
  50. * Add record to 'sys_objects_connection' table:
  51. * - object: name of the connection object, in the format: vendor prefix, underscore, module prefix, underscore, internal identifier or nothing;
  52. * for example: bx_blogs_favorites - favorite blogs for users in blogs module.
  53. * - table: table name with connections, see step 2
  54. * - type: 'one-way' or 'mutual'
  55. * - override_class_name: user defined class name which is derived from one of base classes.
  56. * - override_class_file: the location of the user defined class, leave it empty if class is located in system folders.
  57. *
  58. * Step 2:
  59. * Create table for connections:
  60. * @code
  61. * CREATE TABLE `my_sample_connections` (
  62. * `id` int(11) NOT NULL AUTO_INCREMENT,
  63. * `initiator` int(11) NOT NULL,
  64. * `content` int(11) NOT NULL,
  65. * `mutual` tinyint(4) NOT NULL, -- can re removed for one-way connections
  66. * `added` int(10) unsigned NOT NULL,
  67. * PRIMARY KEY (`id`),
  68. * UNIQUE KEY `initiator` (`initiator`,`content`),
  69. * KEY `content` (`content`)
  70. * )
  71. * @endcode
  72. *
  73. *
  74. * @section example Example of usage
  75. *
  76. * Check if two profiles are friends:
  77. * @code
  78. * bx_import('BxDolConnection'); // import connection class
  79. * $oConnectionFriends = BxDolConnection::getObjectInstance('bx_profiles_friends'); // get friends connections object
  80. * if ($oConnectionFriends) // check if connections is available for using
  81. * echo $oConnectionFriends->isConnected (100, 200, true) ? "100 and 200 are friends" : "100 and 200 aren't friends"; // check if profiles with IDs 100 and 200 have mutual connections
  82. * @endcode
  83. *
  84. * Get mutual content IDs (friends IDs)
  85. * @code
  86. * bx_import('BxDolConnection'); // import connection class
  87. * $oConnectionFriends = BxDolConnection::getObjectInstance('bx_profiles_friends'); // get friends connections object
  88. * if ($oConnectionFriends) // check if connections is available for using
  89. * print_r($oConnection->getConnectedContent(100, 1)); // print array of friends IDs of 100's profile
  90. * @endcode
  91. *
  92. */
  93. class BxDolConnection extends BxDol implements iBxDolFactoryObject {
  94. protected $_sObject;
  95. protected $_aObject;
  96. protected $_oQuery;
  97. protected $_sType;
  98. /**
  99. * Constructor
  100. * @param $aObject array of connection options
  101. */
  102. protected function __construct($aObject) {
  103. parent::__construct();
  104. $this->_sObject = $aObject['object'];
  105. $this->_aObject = $aObject;
  106. $this->_sType = $aObject['type'];
  107. $this->_oQuery = new BxDolConnectionQuery($aObject);
  108. }
  109. /**
  110. * Get connection object instance by object name
  111. * @param $sObject object name
  112. * @return object instance or false on error
  113. */
  114. static public function getObjectInstance($sObject) {
  115. if (!$sObject)
  116. return false;
  117. if (isset($GLOBALS['bxDolClasses']['BxDolConnection!'.$sObject]))
  118. return $GLOBALS['bxDolClasses']['BxDolConnection!'.$sObject];
  119. $aObject = BxDolConnectionQuery::getConnectionObject($sObject);
  120. if (!$aObject || !is_array($aObject))
  121. return false;
  122. $sClass = empty($aObject['override_class_name']) ? 'BxDolConnection' : $aObject['override_class_name'];
  123. if (!empty($aObject['override_class_file']))
  124. require_once(BX_DIRECTORY_PATH_ROOT . $aObject['override_class_file']);
  125. else
  126. bx_import($sClass);
  127. $o = new $sClass($aObject);
  128. return ($GLOBALS['bxDolClasses']['BxDolConnection!'.$sObject] = $o);
  129. }
  130. /**
  131. * Add new connection.
  132. * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
  133. * @return array
  134. */
  135. public function actionAdd ($iContent = 0) {
  136. if (!$iContent)
  137. $iContent = bx_process_input($_POST['id'], BX_DATA_INT);
  138. return $this->_action (bx_get_logged_profile_id(), $iContent, 'addConnection', '_sys_conn_err_connection_already_exists', true);
  139. }
  140. /**
  141. * Remove connection.
  142. * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
  143. * @return array
  144. */
  145. public function actionRemove ($iContent = 0) {
  146. if (!$iContent)
  147. $iContent = bx_process_input($_POST['id'], BX_DATA_INT);
  148. $a = $this->actionReject($iContent);
  149. if (false == $a['err'])
  150. return $a;
  151. return $this->_action (bx_get_logged_profile_id(), $iContent, 'removeConnection', '_sys_conn_err_connection_does_not_exists');
  152. }
  153. /**
  154. * Reject connection request.
  155. * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
  156. * @return array
  157. */
  158. public function actionReject ($iContent = 0) {
  159. if (!$iContent)
  160. $iContent = bx_process_input($_POST['id'], BX_DATA_INT);
  161. return $this->_action ($iContent, bx_get_logged_profile_id(), 'removeConnection', '_sys_conn_err_connection_does_not_exists');
  162. }
  163. protected function _action ($iInitiator, $iContent, $sMethod, $sErrorKey, $isMutual = false) {
  164. bx_import('BxDolLanguages');
  165. if (!$iContent || !$iInitiator)
  166. return array ('err' => true, 'msg' => _t('_sys_conn_err_input_data_is_not_defined'));
  167. if (!$this->$sMethod((int)$iInitiator, (int)$iContent)) {
  168. if ($isMutual && BX_CONNECTIONS_TYPE_MUTUAL == $this->_sType && $this->isConnected((int)$iInitiator, (int)$iContent, false) && !$this->isConnected((int)$iInitiator, (int)$iContent, true))
  169. return array ('err' => true, 'msg' => _t('_sys_conn_err_connection_is_awaiting_confirmation'));
  170. return array ('err' => true, 'msg' => _t($sErrorKey));
  171. }
  172. return array ('err' => false, 'msg' => _t('_sys_conn_msg_success'));
  173. }
  174. public function outputActionResult ($mixed, $sFormat = 'json') {
  175. switch ($sFormat) {
  176. case 'json':
  177. default:
  178. header('Content-Type: application/json; charset=utf-8');
  179. echo json_encode($mixed);
  180. }
  181. exit;
  182. }
  183. /**
  184. * Add new connection.
  185. * @param $iInitiator initiator of the connection, in most cases some profile id
  186. * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
  187. * @return true - if connection was added, false - if connection already exists or error occured
  188. */
  189. public function addConnection ($iInitiator, $iContent) {
  190. $iMutual = 0;
  191. if (!$this->_oQuery->addConnection((int)$iInitiator, (int)$iContent, $iMutual))
  192. return false;
  193. bx_alert($this->_sObject, 'connection_added', 0, getLoggedId(), array(
  194. 'initiator' => (int)$iInitiator,
  195. 'content' => (int)$iContent,
  196. 'mutual' => (int)$iMutual,
  197. 'object' => $this,
  198. ));
  199. return true;
  200. }
  201. /**
  202. * Remove connection.
  203. * @param $iInitiator initiator of the connection
  204. * @param $iContent connected content or other profile id in case of friends
  205. * @return true - if connection was removed, false - if connection isn't exist or error occured
  206. */
  207. public function removeConnection ($iInitiator, $iContent) {
  208. if (!($aConnection = $this->_oQuery->getConnection((int)$iInitiator, (int)$iContent))) // connection doesn't exist
  209. return false;
  210. if (!$this->_oQuery->removeConnection((int)$iInitiator, (int)$iContent))
  211. return false;
  212. bx_alert($this->_sObject, 'connection_removed', 0, getLoggedId(), array(
  213. 'initiator' => (int)$iInitiator,
  214. 'content' => (int)$iContent,
  215. 'mutual' => isset($aConnection['mutual']) ? $aConnection['mutual'] : 0,
  216. 'object' => $this,
  217. ));
  218. return true;
  219. }
  220. /**
  221. * Get common content IDs between two initiators
  222. * @param $iInitiator1 one initiator
  223. * @param $iInitiator2 second initiator
  224. * @param $isMutual get mutual connections only
  225. * @return array of available connections
  226. */
  227. public function getCommonContent ($iInitiator1, $iInitiator2, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE) {
  228. return $this->_oQuery->getCommonContent($iInitiator1, $iInitiator2, $isMutual, $iStart, $iLimit, $iOrder);
  229. }
  230. /**
  231. * Get connected content IDs
  232. * @param $iInitiator initiator of the connection
  233. * @param $isMutual get mutual connections only
  234. * @return array of available connections
  235. */
  236. public function getConnectedContent ($iInitiator, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE) {
  237. return $this->_oQuery->getConnectedContent($iInitiator, $isMutual, $iStart, $iLimit, $iOrder);
  238. }
  239. /**
  240. * Get connected initiators IDs
  241. * @param $iContent content of the connection
  242. * @param $isMutual get mutual connections only
  243. * @return array of available connections
  244. */
  245. public function getConnectedInitiators ($iContent, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE) {
  246. return $this->_oQuery->getConnectedInitiators($iContent, $isMutual, $iStart, $iLimit, $iOrder);
  247. }
  248. /**
  249. * Get necessary parts of SQL query to use connections in other queries
  250. * @param $sContentTable content table or alias
  251. * @param $sContentField content table field or field alias
  252. * @param $iInitiator initiator of the connection
  253. * @param $isMutual get mutual connections only
  254. * @return array of SQL string parts, for now 'join' part only is returned
  255. */
  256. public function getCommonContentAsSQLParts ($sContentTable, $sContentField, $iInitiator1, $iInitiator2, $isMutual = false) {
  257. return $this->_oQuery->getCommonContentSQLParts($sContentTable, $sContentField, $iInitiator1, $iInitiator2, $isMutual);
  258. }
  259. /**
  260. * Get necessary parts of SQL query to use connections in other queries
  261. * @param $sContentTable content table or alias
  262. * @param $sContentField content table field or field alias
  263. * @param $iInitiator initiator of the connection
  264. * @param $isMutual get mutual connections only
  265. * @return array of SQL string parts, for now 'join' part only is returned
  266. */
  267. public function getConnectedContentAsSQLParts ($sContentTable, $sContentField, $iInitiator, $isMutual = false) {
  268. return $this->_oQuery->getConnectedContentSQLParts($sContentTable, $sContentField, $iInitiator, $isMutual);
  269. }
  270. /**
  271. * Get necessary parts of SQL query to use connections in other queries
  272. * @param $sContentTable content table or alias
  273. * @param $sContentField content table field or field alias
  274. * @param $iContent content of the connection
  275. * @param $isMutual get mutual connections only
  276. * @return array of SQL string parts, for now 'join' part only is returned
  277. */
  278. public function getConnectedInitiatorsAsSQLParts ($sContentTable, $sContentField, $iContent, $isMutual = false) {
  279. return $this->_oQuery->getConnectedInitiatorsSQLParts($sContentTable, $sContentField, $iContent, $isMutual);
  280. }
  281. /**
  282. * Get necessary condition array to use connections in search classes
  283. * @param $sContentField content table field name
  284. * @param $iInitiator initiator of the connection
  285. * @param $iMutual get mutual connections only
  286. * @return array of conditions, for now with 'restriction' and 'join' parts
  287. */
  288. public function getCommonContentAsCondition ($sContentField, $iInitiator1, $iInitiator2, $iMutual = false) {
  289. return array(
  290. 'restriction' => array (
  291. 'connections_' . $this->_sObject => array(
  292. 'value' => $iInitiator1,
  293. 'field' => 'initiator',
  294. 'operator' => '=',
  295. 'table' => 'c',
  296. ),
  297. 'connections_mutual_' . $this->_sObject => array(
  298. 'value' => $iMutual,
  299. 'field' => 'mutual',
  300. 'operator' => '=',
  301. 'table' => 'c',
  302. ),
  303. 'connections2_' . $this->_sObject => array(
  304. 'value' => $iInitiator2,
  305. 'field' => 'initiator',
  306. 'operator' => '=',
  307. 'table' => 'c2',
  308. ),
  309. 'connections2_mutual_' . $this->_sObject => array(
  310. 'value' => $iMutual,
  311. 'field' => 'mutual',
  312. 'operator' => '=',
  313. 'table' => 'c2',
  314. ),
  315. ),
  316. 'join' => array (
  317. 'connections_' . $this->_sObject => array(
  318. 'type' => 'INNER',
  319. 'table' => $this->_aObject['table'],
  320. 'table_alias' => 'c',
  321. 'mainField' => $sContentField,
  322. 'onField' => 'content',
  323. 'joinFields' => array(),
  324. ),
  325. 'connections2_' . $this->_sObject => array(
  326. 'type' => 'INNER',
  327. 'table' => $this->_aObject['table'],
  328. 'table_alias' => 'c2',
  329. 'mainTable' => 'c',
  330. 'mainField' => 'content',
  331. 'onField' => 'content',
  332. 'joinFields' => array(),
  333. ),
  334. ),
  335. );
  336. }
  337. /**
  338. * Get necessary condition array to use connections in search classes
  339. * @param $sContentField content table field name
  340. * @param $iInitiator initiator of the connection
  341. * @param $iMutual get mutual connections only
  342. * @return array of conditions, for now with 'restriction' and 'join' parts
  343. */
  344. public function getConnectedContentAsCondition ($sContentField, $iInitiator, $iMutual = false) {
  345. return array(
  346. 'restriction' => array (
  347. 'connections_' . $this->_sObject => array(
  348. 'value' => $iInitiator,
  349. 'field' => 'initiator',
  350. 'operator' => '=',
  351. 'table' => $this->_aObject['table'],
  352. ),
  353. 'connections_mutual_' . $this->_sObject => array(
  354. 'value' => $iMutual,
  355. 'field' => 'mutual',
  356. 'operator' => '=',
  357. 'table' => $this->_aObject['table'],
  358. ),
  359. ),
  360. 'join' => array (
  361. 'connections_' . $this->_sObject => array(
  362. 'type' => 'INNER',
  363. 'table' => $this->_aObject['table'],
  364. 'mainField' => $sContentField,
  365. 'onField' => 'content',
  366. 'joinFields' => array(),//'initiator'),
  367. ),
  368. ),
  369. );
  370. }
  371. /**
  372. * Get necessary condition array to use connections in search classes
  373. * @param $sContentField content table field name
  374. * @param $iInitiator initiator of the connection
  375. * @param $iMutual get mutual connections only
  376. * @return array of conditions, for now with 'restriction' and 'join' parts
  377. */
  378. public function getConnectedInitiatorsAsCondition ($sContentField, $iContent, $iMutual = false) {
  379. return array(
  380. 'restriction' => array (
  381. 'connections_' . $this->_sObject => array(
  382. 'value' => $iContent,
  383. 'field' => 'content',
  384. 'operator' => '=',
  385. 'table' => $this->_aObject['table'],
  386. ),
  387. 'connections_mutual_' . $this->_sObject => array(
  388. 'value' => $iMutual,
  389. 'field' => 'mutual',
  390. 'operator' => '=',
  391. 'table' => $this->_aObject['table'],
  392. ),
  393. ),
  394. 'join' => array (
  395. 'connections_' . $this->_sObject => array(
  396. 'type' => 'INNER',
  397. 'table' => $this->_aObject['table'],
  398. 'mainField' => $sContentField,
  399. 'onField' => 'initiator',
  400. 'joinFields' => array(),//'initiator'),
  401. ),
  402. ),
  403. );
  404. }
  405. /**
  406. * Check if initiator and content are connected.
  407. * In case if friends this function in conjunction with isMutual parameter can be used to check pending friend requests.
  408. * @param $iInitiator initiator of the connection
  409. * @param $iContent connected content or other profile id in case of friends
  410. * @return true - if content and initiator are connected or false - in all other cases
  411. */
  412. public function isConnected ($iInitiator, $iContent, $isMutual = false) {
  413. $oConnection = $this->_oQuery->getConnection ($iInitiator, $iContent);
  414. if (!$oConnection)
  415. return false;
  416. return false === $isMutual ? true : $oConnection['mutual'];
  417. }
  418. /**
  419. * Check if initiator and content are connected but connetion is not mutual, for checking pending connection requests.
  420. * This method makes sense only when type of connection is mutual.
  421. * @param $iInitiator initiator of the connection
  422. * @param $iContent connected content or other profile id in case of friends
  423. * @return true - if content and initiator are connected but connection is not mutual or false in all other cases
  424. */
  425. public function isConnectedNotMutual ($iInitiator, $iContent) {
  426. $oConnection = $this->_oQuery->getConnection ($iInitiator, $iContent);
  427. if (!$oConnection)
  428. return false;
  429. return $oConnection['mutual'] ? false : true;
  430. }
  431. }
  432. /** @} */