PageRenderTime 59ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/sender/lib/postingmanager.php

https://gitlab.com/alexprowars/bitrix
PHP | 422 lines | 279 code | 47 blank | 96 comment | 21 complexity | 2098423578a5e6265b849c84d93a74ce MD5 | raw file
  1. <?php
  2. /**
  3. * Bitrix Framework
  4. * @package bitrix
  5. * @subpackage sender
  6. * @copyright 2001-2012 Bitrix
  7. */
  8. namespace Bitrix\Sender;
  9. use Bitrix\Main\Config\Option;
  10. use Bitrix\Main\Event;
  11. use Bitrix\Main\Localization\Loc;
  12. use Bitrix\Main\Type;
  13. use Bitrix\Sender\Entity;
  14. use Bitrix\Sender\Integration\Seo\Ads\MessageMarketingFb;
  15. use Bitrix\Sender\Posting\ThreadStrategy\IThreadStrategy;
  16. use Bitrix\Sender\Posting\ThreadStrategy\ThreadStrategyContext;
  17. use function MongoDB\BSON\fromPHP;
  18. Loc::loadMessages(__FILE__);
  19. /**
  20. * Class PostingManager
  21. * @package Bitrix\Sender
  22. */
  23. class PostingManager
  24. {
  25. const SEND_RESULT_ERROR = false;
  26. const SEND_RESULT_SENT = true;
  27. const SEND_RESULT_CONTINUE = 'CONTINUE';
  28. const SEND_RESULT_WAIT = 'WAIT';
  29. const SEND_RESULT_WAITING_RECIPIENT = 'WAITING_RECIPIENT';
  30. public static $threadId;
  31. /** @var int $checkStatusStep */
  32. protected static $checkStatusStep = 20;
  33. /** @var int $emailSentPerIteration */
  34. protected static $emailSentPerIteration = 0;
  35. /**
  36. * Handler of read event.
  37. *
  38. * @param array $data Data.
  39. *
  40. * @return array
  41. */
  42. public static function onMailEventMailRead(array $data)
  43. {
  44. $id = intval($data['RECIPIENT_ID']);
  45. if ($id > 0)
  46. {
  47. static::read($id);
  48. }
  49. return $data;
  50. }
  51. /**
  52. * Do read actions.
  53. *
  54. * @param integer $recipientId Recipient ID.
  55. *
  56. * @return void
  57. */
  58. public static function read($recipientId)
  59. {
  60. $postingContactPrimary = ['ID' => $recipientId];
  61. $row = PostingRecipientTable::getRowById($postingContactPrimary);
  62. if (!$row)
  63. {
  64. return;
  65. }
  66. if ($row['ID'])
  67. {
  68. PostingReadTable::add(
  69. [
  70. 'POSTING_ID' => $row['POSTING_ID'],
  71. 'RECIPIENT_ID' => $row['ID'],
  72. ]
  73. );
  74. }
  75. if ($row['CONTACT_ID'])
  76. {
  77. ContactTable::update(
  78. $row['CONTACT_ID'],
  79. [
  80. 'IS_READ' => 'Y',
  81. ]
  82. );
  83. }
  84. }
  85. /**
  86. * Handler of click event.
  87. *
  88. * @param array $data Data.
  89. *
  90. * @return array
  91. */
  92. public static function onMailEventMailClick(array $data)
  93. {
  94. $id = intval($data['RECIPIENT_ID']);
  95. $url = $data['URL'];
  96. if ($id > 0 && $url <> '')
  97. {
  98. static::click($id, $url);
  99. }
  100. return $data;
  101. }
  102. /**
  103. * Do click actions.
  104. *
  105. * @param integer $recipientId Recipient ID.
  106. * @param string $url Url.
  107. *
  108. * @return void
  109. * @throws \Bitrix\Main\ArgumentException
  110. */
  111. public static function click($recipientId, $url)
  112. {
  113. $postingContactPrimary = ['ID' => $recipientId];
  114. $row = PostingRecipientTable::getRowById($postingContactPrimary);
  115. if (!$row)
  116. {
  117. return;
  118. }
  119. if ($row['ID'])
  120. {
  121. $read = PostingReadTable::getRowById(
  122. [
  123. 'POSTING_ID' => $row['POSTING_ID'],
  124. 'RECIPIENT_ID' => $row['ID']
  125. ]
  126. );
  127. if ($read === null)
  128. {
  129. static::read($recipientId);
  130. }
  131. $postingDb = PostingTable::getList(
  132. [
  133. 'select' => ['ID'],
  134. 'filter' => ['=ID' => $row['POSTING_ID']],
  135. ]
  136. );
  137. if ($postingDb->fetch())
  138. {
  139. $deleteParameters = ['bx_sender_conversion_id'];
  140. $letter = Entity\Letter::createInstanceByPostingId($row['POSTING_ID']);
  141. $linkParams = $letter->getMessage()
  142. ->getConfiguration()
  143. ->get('LINK_PARAMS');
  144. if ($linkParams)
  145. {
  146. $parametersTmp = [];
  147. parse_str($linkParams, $parametersTmp);
  148. if (is_array($parametersTmp))
  149. {
  150. $parametersTmp = array_keys($parametersTmp);
  151. $deleteParameters = array_merge($deleteParameters, $parametersTmp);
  152. }
  153. }
  154. $uri = new \Bitrix\Main\Web\Uri($url);
  155. $fixedUrl = $uri->deleteParams($deleteParameters, false)
  156. ->getUri();
  157. $fixedUrl = urldecode($fixedUrl);
  158. if(mb_strpos($fixedUrl, 'pub/mail/unsubscribe.php') === false)
  159. {
  160. $addClickDb = PostingClickTable::add(
  161. [
  162. 'POSTING_ID' => $row['POSTING_ID'],
  163. 'RECIPIENT_ID' => $row['ID'],
  164. 'URL' => $fixedUrl
  165. ]
  166. );
  167. }
  168. if ($addClickDb && $addClickDb->isSuccess())
  169. {
  170. // send event
  171. $eventData = [
  172. 'URL' => $url,
  173. 'URL_FIXED' => $fixedUrl,
  174. 'CLICK_ID' => $addClickDb->getId(),
  175. 'RECIPIENT' => $row
  176. ];
  177. $event = new Event('sender', 'OnAfterRecipientClick', [$eventData]);
  178. $event->send();
  179. }
  180. }
  181. }
  182. if ($row['CONTACT_ID'])
  183. {
  184. ContactTable::update(
  185. $row['CONTACT_ID'],
  186. [
  187. 'IS_CLICK' => 'Y',
  188. ]
  189. );
  190. }
  191. }
  192. /**
  193. * Get chain list for resending.
  194. *
  195. * @param integer $mailingId Mailing ID.
  196. *
  197. * @return array|null
  198. * @throws \Bitrix\Main\ArgumentException
  199. */
  200. public static function getChainReSend($mailingId)
  201. {
  202. $result = [];
  203. $mailChainDb = MailingChainTable::getList(
  204. [
  205. 'select' => ['ID'],
  206. 'filter' => [
  207. '=MAILING.ID' => $mailingId,
  208. '=MAILING.ACTIVE' => 'Y',
  209. '=REITERATE' => 'N',
  210. '=MAILING_CHAIN.STATUS' => MailingChainTable::STATUS_END,
  211. ]
  212. ]
  213. );
  214. while ($mailChain = $mailChainDb->fetch())
  215. {
  216. $result[] = $mailChain['ID'];
  217. }
  218. return (empty($result) ? null : $result);
  219. }
  220. /**
  221. * Send letter by message from posting to address.
  222. *
  223. * @param integer $mailingChainId Chain ID.
  224. * @param string $address Address.
  225. *
  226. * @return bool
  227. * @throws \Bitrix\Main\DB\Exception
  228. */
  229. public static function sendToAddress($mailingChainId, $address)
  230. {
  231. $recipientEmail = $address;
  232. $emailParts = explode('@', $recipientEmail);
  233. $recipientName = $emailParts[0];
  234. global $USER;
  235. $mailingChain = MailingChainTable::getRowById(['ID' => $mailingChainId]);
  236. $fields = [
  237. 'NAME' => $recipientName,
  238. 'EMAIL_TO' => $address,
  239. 'USER_ID' => $USER->GetID(),
  240. 'SENDER_CHAIN_ID' => $mailingChain["ID"],
  241. 'SENDER_CHAIN_CODE' => 'sender_chain_item_'.$mailingChain["ID"]
  242. ];
  243. $letter = new Entity\Letter($mailingChainId);
  244. $message = $letter->getMessage();
  245. $siteId = MailingTable::getMailingSiteId($mailingChain['MAILING_ID']);
  246. $message->getReadTracker()
  247. ->setModuleId('sender')
  248. ->setFields(['RECIPIENT_ID' => 0])
  249. ->setSiteId($siteId);
  250. $message->getClickTracker()
  251. ->setModuleId('sender')
  252. ->setFields(['RECIPIENT_ID' => 0])
  253. ->setUriParameters(['bx_sender_conversion_id' => 0])
  254. ->setSiteId($siteId);
  255. $message->getUnsubTracker()
  256. ->setModuleId('sender')
  257. ->setFields(
  258. [
  259. 'MAILING_ID' => !empty($mailingChain) ? $mailingChain['MAILING_ID'] : 0,
  260. 'EMAIL' => $address,
  261. 'TEST' => 'Y'
  262. ]
  263. )
  264. ->setSiteId($siteId);
  265. $message->getUnsubTracker()
  266. ->setHandlerUri(Option::get('sender', 'unsub_link'));
  267. $message->setFields($fields);
  268. $result = $message->send();
  269. return $result ? static::SEND_RESULT_SENT : static::SEND_RESULT_ERROR;
  270. }
  271. /**
  272. * Send posting.
  273. *
  274. * @param integer $id Posting ID.
  275. * @param int $timeout Timeout.
  276. * @param int $maxMailCount Max mail count.
  277. *
  278. * @return bool|string
  279. * @throws \Bitrix\Main\ArgumentException
  280. * @throws \Bitrix\Main\DB\Exception
  281. */
  282. public static function send($id, $timeout = 0, $maxMailCount = 0)
  283. {
  284. $letter = Entity\Letter::createInstanceByPostingId($id);
  285. $sender = new Posting\Sender($letter);
  286. $sender->setThreadStrategy(
  287. MessageMarketingFb::checkSelf($sender->getMessage()->getCode()) ?
  288. ThreadStrategyContext::buildStrategy(
  289. IThreadStrategy::SINGLE
  290. ): Runtime\Env::getThreadContext()
  291. )
  292. ->setLimit($maxMailCount)
  293. ->setTimeout($timeout)
  294. ->send();
  295. static::$threadId = $sender->getThreadStrategy()->getThreadId();
  296. switch ($sender->getResultCode())
  297. {
  298. case Posting\Sender::RESULT_CONTINUE:
  299. $result = static::SEND_RESULT_CONTINUE;
  300. break;
  301. case Posting\Sender::RESULT_ERROR:
  302. $result = static::SEND_RESULT_ERROR;
  303. break;
  304. case Posting\Sender::RESULT_WAITING_RECIPIENT:
  305. $result = static::SEND_RESULT_WAITING_RECIPIENT;
  306. break;
  307. case Posting\Sender::RESULT_WAIT:
  308. $result = static::SEND_RESULT_WAIT;
  309. break;
  310. case Posting\Sender::RESULT_SENT:
  311. default:
  312. $result = static::SEND_RESULT_SENT;
  313. break;
  314. }
  315. $limiter = $sender->getExceededLimiter();
  316. if ($result === static::SEND_RESULT_CONTINUE && $limiter)
  317. {
  318. // update planned date only with timed limit;
  319. if ($limiter->getParameter('sendingStart'))
  320. {
  321. $currentTime = $limiter->getParameter('currentTime');
  322. $sendingStart = $limiter->getParameter('sendingStart');
  323. $sendingStartDate = (new \DateTime())->setTimestamp($sendingStart);
  324. $sendingStartDate = $currentTime > $sendingStart
  325. ? $sendingStartDate->add(\DateInterval::createFromDateString('1 day'))
  326. : $sendingStartDate;
  327. $date = Type\DateTime::createFromPhp($sendingStartDate);
  328. }
  329. elseif ($limiter->getUnit())
  330. {
  331. $date = new Type\Date();
  332. $date->add('1 day');
  333. }
  334. else
  335. {
  336. $date = new Type\DateTime();
  337. $date->add('2 minute');
  338. }
  339. $letter->getState()->updatePlannedDateSend($date);
  340. }
  341. return $result;
  342. }
  343. /**
  344. * Lock posting for preventing double sending.
  345. *
  346. * @param integer $id ID.
  347. * @param $threadId
  348. *
  349. * @return bool
  350. * @throws \Bitrix\Main\Db\SqlQueryException
  351. * @throws \Bitrix\Main\SystemException
  352. * @deprecated
  353. * @use \Bitrix\Sender\Posting\Sender::lock
  354. */
  355. public static function lockPosting($id, $threadId)
  356. {
  357. return Posting\Sender::lock($id, $threadId);
  358. }
  359. /**
  360. * UnLock posting that was locking for preventing double sending.
  361. *
  362. * @param integer $id ID.
  363. * @param $threadId
  364. *
  365. * @return bool
  366. * @throws \Bitrix\Main\Db\SqlQueryException
  367. * @throws \Bitrix\Main\SystemException
  368. * @deprecated
  369. * @use \Bitrix\Sender\Posting\Sender::unlock
  370. */
  371. public static function unlockPosting($id, $threadId)
  372. {
  373. return Posting\Sender::unlock($id, $threadId);
  374. }
  375. }