PageRenderTime 57ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/seo/lib/retargeting/internals/queue.php

https://gitlab.com/alexprowars/bitrix
PHP | 397 lines | 337 code | 38 blank | 22 comment | 27 complexity | e6f37902b3487d3c50653e1646c01478 MD5 | raw file
  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage seo
  6. * @copyright 2001-2013 Bitrix
  7. */
  8. namespace Bitrix\Seo\Retargeting\Internals;
  9. use Bitrix\Main\Application;
  10. use \Bitrix\Main\Entity;
  11. use \Bitrix\Main\Localization\Loc;
  12. use \Bitrix\Main\Type\DateTime;
  13. use Bitrix\Seo\Retargeting\Service;
  14. Loc::loadMessages(__FILE__);
  15. /**
  16. * Class QueueTable
  17. *
  18. * DO NOT WRITE ANYTHING BELOW THIS
  19. *
  20. * <<< ORMENTITYANNOTATION
  21. * @method static EO_Queue_Query query()
  22. * @method static EO_Queue_Result getByPrimary($primary, array $parameters = array())
  23. * @method static EO_Queue_Result getById($id)
  24. * @method static EO_Queue_Result getList(array $parameters = array())
  25. * @method static EO_Queue_Entity getEntity()
  26. * @method static \Bitrix\Seo\Retargeting\Internals\EO_Queue createObject($setDefaultValues = true)
  27. * @method static \Bitrix\Seo\Retargeting\Internals\EO_Queue_Collection createCollection()
  28. * @method static \Bitrix\Seo\Retargeting\Internals\EO_Queue wakeUpObject($row)
  29. * @method static \Bitrix\Seo\Retargeting\Internals\EO_Queue_Collection wakeUpCollection($rows)
  30. */
  31. class QueueTable extends Entity\DataManager
  32. {
  33. const MODULE_ID = 'seo';
  34. const PORTION_QUANTITY = 50;
  35. const ACTION_IMPORT = 'IMP';
  36. const ACTION_IMPORT_AND_AUTO_REMOVE = 'IAR';
  37. const ACTION_REMOVE = 'REM';
  38. const ACTION_AUTO_REMOVE = 'ARM';
  39. protected static $isAgentAdded = array();
  40. public static function getTableName()
  41. {
  42. return 'b_seo_service_rtg_queue';
  43. }
  44. public static function getMap()
  45. {
  46. $fieldsMap = array(
  47. 'ID' => array(
  48. 'data_type' => 'integer',
  49. 'primary' => true,
  50. 'autocomplete' => true,
  51. ),
  52. 'DATE_INSERT' => array(
  53. 'data_type' => 'datetime',
  54. 'default_value' => new DateTime()
  55. ),
  56. 'TYPE' => array(
  57. 'data_type' => 'string',
  58. 'required' => true,
  59. ),
  60. 'CLIENT_ID' => array(
  61. 'data_type' => 'string',
  62. ),
  63. 'ACCOUNT_ID' => array(
  64. 'data_type' => 'string',
  65. ),
  66. 'AUDIENCE_ID' => array(
  67. 'data_type' => 'string',
  68. 'required' => true,
  69. ),
  70. 'PARENT_ID' => array(
  71. 'data_type' => 'string',
  72. ),
  73. 'CONTACT_TYPE' => array(
  74. 'data_type' => 'string',
  75. 'required' => true,
  76. ),
  77. 'VALUE' => array(
  78. 'data_type' => 'string',
  79. 'required' => true,
  80. ),
  81. 'ACTION' => array(
  82. 'data_type' => 'enum',
  83. 'values' => array(
  84. self::ACTION_IMPORT,
  85. self::ACTION_REMOVE,
  86. self::ACTION_IMPORT_AND_AUTO_REMOVE,
  87. self::ACTION_AUTO_REMOVE,
  88. ),
  89. 'default_value' => self::ACTION_IMPORT_AND_AUTO_REMOVE,
  90. 'required' => true,
  91. ),
  92. 'DATE_AUTO_REMOVE' => array(
  93. 'data_type' => 'datetime',
  94. )
  95. );
  96. return $fieldsMap;
  97. }
  98. protected static function processQueueAutoRemoveAgentName()
  99. {
  100. return __CLASS__ . '::processQueueAutoRemoveAgent();';
  101. }
  102. protected static function getProcessQueueAgentName($type)
  103. {
  104. return __CLASS__ . '::processQueueAgent("' . $type . '");';
  105. }
  106. public static function processQueueAutoRemoveAgent()
  107. {
  108. $queueDb = static::getList(array(
  109. 'select' => array('ID'),
  110. 'filter' => array('=ACTION' => self::ACTION_AUTO_REMOVE),
  111. 'limit' => 1
  112. ));
  113. if ($queueDb->fetch())
  114. {
  115. $connection = Application::getConnection();
  116. $sql = "UPDATE " . self::getTableName() . " " .
  117. "SET ACTION='" . self::ACTION_REMOVE . "' " .
  118. "WHERE ACTION='" . self::ACTION_AUTO_REMOVE . "' " .
  119. "AND DATE_AUTO_REMOVE <= " . $connection->getSqlHelper()->getCurrentDateTimeFunction();
  120. $connection->query($sql);
  121. if ($connection->getAffectedRowsCount() > 0)
  122. {
  123. $types = Service::getTypes();
  124. foreach ($types as $type)
  125. {
  126. static::addQueueAgent($type);
  127. }
  128. }
  129. return static::processQueueAutoRemoveAgentName();
  130. }
  131. else
  132. {
  133. return '';
  134. }
  135. }
  136. public static function processQueueAgent($type)
  137. {
  138. try
  139. {
  140. $hasQueue = static::processQueue($type);
  141. }
  142. catch(\Exception $e)
  143. {
  144. $hasQueue = false;
  145. }
  146. if (!$hasQueue)
  147. {
  148. return '';
  149. }
  150. else
  151. {
  152. return static::getProcessQueueAgentName($type);
  153. }
  154. }
  155. protected static function processQueue($type)
  156. {
  157. $hasQueue = false;
  158. $queryData = array();
  159. $audience = Service::getAudience($type);
  160. $maxQuantity = $audience->getMaxContactsPerPacket();
  161. $maxQuantity = $maxQuantity > 1000 ? 1000 : $maxQuantity;
  162. $queueDb = static::getList(array(
  163. 'filter' => array(
  164. '=TYPE' => $type,
  165. '=ACTION' => array(
  166. self::ACTION_IMPORT,
  167. self::ACTION_REMOVE,
  168. self::ACTION_IMPORT_AND_AUTO_REMOVE,
  169. )
  170. ),
  171. 'limit' => $maxQuantity
  172. ));
  173. while ($queueItem = $queueDb->fetch())
  174. {
  175. $hasQueue = true;
  176. $isRemove = $queueItem['ACTION'] == self::ACTION_REMOVE ? 'Y' : 'N';
  177. $queryId = $queueItem['TYPE'];
  178. $queryId .= '_' . $queueItem['PARENT_ID'];
  179. $queryId .= '_' . $queueItem['CLIENT_ID'];
  180. $queryId .= '_' . $queueItem['ACCOUNT_ID'];
  181. $queryId .= '_' . $queueItem['AUDIENCE_ID'];
  182. $queryId .= '_' . $isRemove;
  183. if (!isset($queryData[$queryId]))
  184. {
  185. $queryData[$queryId] = array(
  186. 'CLIENT_ID' => $queueItem['CLIENT_ID'],
  187. 'ACCOUNT_ID' => $queueItem['ACCOUNT_ID'],
  188. 'AUDIENCE_ID' => $queueItem['AUDIENCE_ID'],
  189. 'PARENT_ID' => $queueItem['PARENT_ID'],
  190. 'IS_REMOVE' => $isRemove,
  191. 'CONTACTS' => array(),
  192. 'DELETE_ID_LIST' => array(),
  193. 'AUTO_REMOVE_ID_LIST' => array(),
  194. );
  195. }
  196. $contactType = $queueItem['CONTACT_TYPE'];
  197. if (!isset($queryData[$queryId]['CONTACTS'][$contactType]))
  198. {
  199. $queryData[$queryId]['CONTACTS'][$contactType] = array();
  200. }
  201. $queryData[$queryId]['CONTACTS'][$contactType][] = $queueItem['VALUE'];
  202. if ($queueItem['ACTION'] == self::ACTION_IMPORT_AND_AUTO_REMOVE)
  203. {
  204. $queryData[$queryId]['AUTO_REMOVE_ID_LIST'][] = $queueItem['ID'];
  205. }
  206. else
  207. {
  208. $queryData[$queryId]['DELETE_ID_LIST'][] = $queueItem['ID'];
  209. }
  210. }
  211. $lastClientId = null;
  212. $service = null;
  213. $authAdapter = Service::getAuthAdapter($type);
  214. foreach ($queryData as $queryId => $query)
  215. {
  216. foreach ($query['CONTACTS'] as $contactType => $contacts)
  217. {
  218. $query['CONTACTS'][$contactType] = array_unique($contacts);
  219. }
  220. if ($lastClientId != $query['CLIENT_ID'] || !$service || !$authAdapter)
  221. {
  222. $lastClientId = $query['CLIENT_ID'];
  223. $service = new Service();
  224. $service->setClientId($lastClientId);
  225. $authAdapter->setService($service);
  226. }
  227. $audience->setService($service);
  228. $audience->getRequest()->setAuthAdapter($authAdapter);
  229. $audience->disableQueueMode();
  230. $audience->setAccountId($query['ACCOUNT_ID']);
  231. $contactTypes = $audience->isSupportMultiTypeContacts() ? array('') : array_keys($query['CONTACTS']);
  232. foreach ($contactTypes as $contactType)
  233. {
  234. if ($query['IS_REMOVE'] != 'Y')
  235. {
  236. $audienceImportResult = $audience->addContacts(
  237. $query['AUDIENCE_ID'],
  238. $query['CONTACTS'],
  239. array(
  240. 'type' => $contactType
  241. )
  242. );
  243. }
  244. else
  245. {
  246. $audienceImportResult = $audience->deleteContacts(
  247. $query['AUDIENCE_ID'],
  248. $query['CONTACTS'],
  249. array(
  250. 'type' => $contactType
  251. )
  252. );
  253. }
  254. if ($audienceImportResult->isSuccess())
  255. {
  256. if (!empty($query['DELETE_ID_LIST']))
  257. {
  258. $portions = self::divideListIntoPortions($query['DELETE_ID_LIST']);
  259. foreach ($portions as $portion)
  260. {
  261. Application::getConnection()->query(
  262. "DELETE FROM " . self::getTableName() . " WHERE ID IN (" . implode(',', $portion) . ")"
  263. );
  264. }
  265. }
  266. if (!empty($query['AUTO_REMOVE_ID_LIST']))
  267. {
  268. $portions = self::divideListIntoPortions($query['AUTO_REMOVE_ID_LIST']);
  269. foreach ($portions as $portion)
  270. {
  271. Application::getConnection()->query(
  272. "UPDATE " . self::getTableName() . " SET ACTION='" . self::ACTION_AUTO_REMOVE . "'" .
  273. "WHERE ID IN (" . implode(',', $portion) . ")"
  274. );
  275. }
  276. static::addQueueAutoRemoveAgent();
  277. }
  278. }
  279. else
  280. {
  281. Application::getConnection()->query(
  282. "DELETE FROM " . self::getTableName() .
  283. " WHERE TYPE = '" . Application::getConnection()->getSqlHelper()->forSql($type) . "'" .
  284. " AND ACTION in ('" . implode("', '", [self::ACTION_IMPORT, self::ACTION_IMPORT_AND_AUTO_REMOVE, self::ACTION_REMOVE]) . "')" .
  285. " AND DATE_INSERT < '" . (new DateTime())->add('-1 day')->format("Y-m-d H:i:s") . "'"
  286. );
  287. }
  288. }
  289. }
  290. return $hasQueue;
  291. }
  292. protected static function divideListIntoPortions($list)
  293. {
  294. $portions = array();
  295. $deleteCount = count($list);
  296. $portionCount = ceil($deleteCount / self::PORTION_QUANTITY);
  297. $deleteNum = 0;
  298. for ($portionNum = 0; $portionNum < $portionCount; $portionNum++)
  299. {
  300. $deleteList = array();
  301. $deletePortionCount = ($portionNum + 1) * self::PORTION_QUANTITY;
  302. for (; $deleteNum < $deletePortionCount; $deleteNum++)
  303. {
  304. if ($deleteNum >= $deleteCount)
  305. {
  306. break;
  307. }
  308. $deleteList[] = (int) $list[$deleteNum];
  309. }
  310. $portions[] = $deleteList;
  311. }
  312. return $portions;
  313. }
  314. protected static function addQueueAutoRemoveAgent()
  315. {
  316. if (isset(static::$isAgentAdded['sys.auto_remove']))
  317. {
  318. return;
  319. }
  320. $agentName = static::processQueueAutoRemoveAgentName();
  321. $agent = new \CAgent();
  322. $agentsDb = $agent->GetList(array("ID" => "DESC"), array(
  323. "MODULE_ID" => self::MODULE_ID,
  324. "NAME" => $agentName,
  325. ));
  326. if (!$agentsDb->Fetch())
  327. {
  328. $agent->AddAgent($agentName, self::MODULE_ID, "N", 86400, null, "Y", "");
  329. }
  330. }
  331. protected static function addQueueAgent($type)
  332. {
  333. if (isset(static::$isAgentAdded[$type]))
  334. {
  335. return;
  336. }
  337. $agent = new \CAgent();
  338. if ($type)
  339. {
  340. $agentName = static::getProcessQueueAgentName($type);
  341. $agentsDb = $agent->GetList(array("ID" => "DESC"), array(
  342. "MODULE_ID" => self::MODULE_ID,
  343. "NAME" => $agentName,
  344. ));
  345. if (!$agentsDb->Fetch())
  346. {
  347. $interval = ($type == 'yandex' ? 900 : 30); // yandex queues must be processed rarely
  348. $agent->AddAgent($agentName, self::MODULE_ID, "N", $interval, null, "Y", "");
  349. }
  350. }
  351. static::$isAgentAdded[$type] = true;
  352. }
  353. public static function onAfterAdd(Entity\Event $event)
  354. {
  355. $fields = $event->getParameter('fields');
  356. $type = $fields['TYPE'];
  357. static::addQueueAgent($type);
  358. }
  359. }