Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
subscribe.php
1<?php
2namespace Bitrix\Catalog;
3
13 Bitrix\Landing\Connector\Iblock as IblockConnector;
14
15Loc::loadMessages(__FILE__);
16
52class SubscribeTable extends Entity\DataManager
53{
54 const EVENT_ADD_CONTACT_TYPE = 'onAddContactType';
55
57 const LIMIT_SEND = 50;
58 const AGENT_TIME_OUT = 10;
59 const AGENT_INTERVAL = 10;
60
61 private static $oldProductAvailable = array();
62 private static $agentNoticeCreated = false;
63 private static $agentRepeatedNoticeCreated = false;
64
70 public static function getTableName()
71 {
72 return 'b_catalog_subscribe';
73 }
74
80 public static function getMap()
81 {
82 return array(
83 'ID' => array(
84 'data_type' => 'integer',
85 'primary' => true,
86 'autocomplete' => true,
87 ),
88 'DATE_FROM' => array(
89 'data_type' => 'datetime',
90 'required' => true,
91 'default_value' => new DateTime(),
92 ),
93 'DATE_TO' => array(
94 'data_type' => 'datetime',
95 ),
96 'USER_CONTACT' => array(
97 'data_type' => 'string',
98 'required' => true,
99 ),
100 'CONTACT_TYPE' => array(
101 'data_type' => 'integer',
102 'required' => true,
103 ),
104 'USER_ID' => array(
105 'data_type' => 'integer',
106 ),
107 'USER' => array(
108 'data_type' => 'Bitrix\Main\UserTable',
109 'reference' => array('=this.USER_ID' => 'ref.ID'),
110 ),
111 'ITEM_ID' => array(
112 'data_type' => 'integer',
113 ),
114 'PRODUCT' => array(
115 'data_type' => 'Bitrix\Catalog\ProductTable',
116 'reference' => array('=this.ITEM_ID' => 'ref.ID'),
117 ),
118 'IBLOCK_ELEMENT' => array(
119 'data_type' => 'Bitrix\Iblock\ElementTable',
120 'reference' => array('=this.ITEM_ID' => 'ref.ID'),
121 ),
122 'NEED_SENDING' => array(
123 'data_type' => 'boolean',
124 'values' => array('N', 'Y'),
125 'default_value' => 'N',
126 'validation' => array(__CLASS__, 'validateNeedSending'),
127 ),
128 'SITE_ID' => array(
129 'data_type' => 'string',
130 'required' => true,
131 'validation' => array(__CLASS__, 'validateSiteId'),
132 ),
133 'LANDING_SITE_ID' => array(
134 'data_type' => 'integer',
135 ),
136 );
137 }
138
144 public static function validateNeedSending()
145 {
146 return array(
147 new Entity\Validator\Length(null, 1),
148 );
149 }
150
156 public static function validateSiteId()
157 {
158 return array(
159 new Entity\Validator\Length(null, 2),
160 );
161 }
162
169 public static function onUserDelete($userId)
170 {
171 $userId = (int)$userId;
172 if ($userId <= 0)
173 return false;
174
175 $connection = Application::getConnection();
176 $helper = $connection->getSqlHelper();
177 $connection->queryExecute('update '.$helper->quote(static::getTableName()).' set '
178 .$helper->quote('DATE_TO').' = '.$helper->getCurrentDateTimeFunction().', '
179 .$helper->quote('USER_ID').' = \'NULL\' where '.$helper->quote('USER_ID').' = '.$userId
180 );
181
182 return true;
183 }
184
191 public static function onIblockElementDelete($productId)
192 {
193 $productId = (int)$productId;
194 if ($productId <= 0)
195 return true;
196
197 $connection = Application::getConnection();
198 $helper = $connection->getSqlHelper();
199 $connection->queryExecute('delete from '.$helper->quote(static::getTableName()).' where '
200 .$helper->quote('ITEM_ID').' = '.$productId
201 );
202
203 return true;
204 }
205
213 public static function onSaleOrderSaved(Event $event)
214 {
215 if(!$event->getParameter('IS_NEW'))
216 return;
217
218 $order = $event->getParameter('ENTITY');
219
220 if($order instanceof Sale\Order)
221 {
222 $userId = $order->getUserId();
223 $siteId = $order->getSiteId();
224 $basketObject = $order->getBasket();
225 $listProductId = array();
227 foreach ($basketObject->getBasketItems() as $item)
228 $listProductId[] = $item->getProductId();
229
230 if(!$userId || empty($listProductId))
231 return;
232
233 $user = \CUser::getList('ID', 'ASC',
234 array('ID' => $userId) , array('FIELDS' => array('EMAIL'))
235 )->fetch();
236 if($user['EMAIL'])
237 {
238 $listSubscribe = static::getList(array(
239 'select' => array('ID'),
240 'filter' => array(
241 '=USER_CONTACT' => $user['EMAIL'],
242 '=SITE_ID' => $siteId,
243 'ITEM_ID' => $listProductId,
244 ),
245 ))->fetchAll();
246 $listSubscribeId = array();
247 foreach($listSubscribe as $subscribe)
248 $listSubscribeId[] = $subscribe['ID'];
249
250 static::unSubscribe($listSubscribeId);
251 }
252 }
253 }
254
262 public static function getContactTypes()
263 {
264 $contactTypes = array();
265
266 $event = new Event('catalog', static::EVENT_ADD_CONTACT_TYPE, array(&$contactTypes));
267 $event->send();
268
269 if(!is_array($contactTypes))
270 return array();
271
272 $availableFields = array('ID', 'NAME', 'RULE', 'HANDLER');
273 foreach($contactTypes as $typeId => $typeData)
274 {
275 $currentFields = array_keys($typeData);
276 $divergenceFields = array_diff($availableFields, $currentFields);
277 if(!empty($divergenceFields))
278 {
279 unset($contactTypes[$typeId]);
280 continue;
281 }
282 if(!is_string($typeData['NAME']) || !is_string($typeData['RULE']) || !is_callable($typeData['HANDLER']))
283 {
284 unset($contactTypes[$typeId]);
285 }
286 }
287
288 return $contactTypes;
289 }
290
297 public static function onAddContactType(&$contactTypes)
298 {
299 $contactTypes[static::CONTACT_TYPE_EMAIL] = array(
300 'ID' => static::CONTACT_TYPE_EMAIL,
301 'NAME' => Loc::getMessage('CONTACT_TYPE_EMAIL_NAME'),
302 'RULE' => '/@/i',
303 'HANDLER' => function(Event $event)
304 {
305 $eventData = $event->getParameters();
306 $eventObject = new \CEvent;
307 foreach($eventData as $userContact => $dataList)
308 {
309 foreach($dataList as $data)
310 {
311 $eventObject->send($data['EVENT_NAME'], $data['SITE_ID'], $data);
312 }
313 }
314 return true;
315 }
316 );
317 }
318
327 public static function onProductUpdate($productId, $fields)
328 {
329 return static::checkOldProductAvailable($productId, $fields);
330 }
331
339 public static function onProductSetAvailableUpdate($productId, $fields)
340 {
341 return static::checkOldProductAvailable($productId, $fields);
342 }
343
350 public static function runAgentToSendNotice($productId)
351 {
352 $productId = (int)$productId;
353 if ($productId <= 0)
354 return false;
355
356 $connection = Application::getConnection();
357 $helper = $connection->getSqlHelper();
358 $connection->queryExecute('update '.$helper->quote(static::getTableName()).' set '
359 .$helper->quote('NEED_SENDING').' = \'Y\' where '.$helper->quote('ITEM_ID').' = '.$productId
360 .' and ('.$helper->quote('DATE_TO').' is null or '.$helper->quote('DATE_TO').' > '
361 .$helper->getCurrentDateTimeFunction().')'
362 );
363
364 if (!static::$agentNoticeCreated)
365 {
366 $t = DateTime::createFromTimestamp(time() + static::AGENT_TIME_OUT);
367 static::$agentNoticeCreated = true;
368 \CAgent::AddAgent(
369 '\Bitrix\Catalog\SubscribeTable::sendNotice();',
370 'catalog',
371 'N',
372 static::AGENT_INTERVAL,
373 '',
374 'Y',
375 $t->toString(),
376 100,
377 false,
378 false
379 );
380 }
381
382 return true;
383 }
384
391 public static function runAgentToSendRepeatedNotice($productId)
392 {
393 $productId = (int)$productId;
394 if ($productId <= 0 || (string)Option::get('catalog', 'subscribe_repeated_notify') != 'Y')
395 return false;
396
397 $connection = Application::getConnection();
398 $helper = $connection->getSqlHelper();
399 $connection->queryExecute('update '.$helper->quote(static::getTableName()).' set '
400 .$helper->quote('NEED_SENDING').' = \'Y\' where '.$helper->quote('ITEM_ID').' = '.$productId
401 .' and ('.$helper->quote('DATE_TO').' is null or '.$helper->quote('DATE_TO').' > '
402 .$helper->getCurrentDateTimeFunction().')'
403 );
404
405 if (!static::$agentRepeatedNoticeCreated)
406 {
407 $t = DateTime::createFromTimestamp(time() + static::AGENT_TIME_OUT);
408 static::$agentRepeatedNoticeCreated = true;
409 \CAgent::AddAgent(
410 'Bitrix\Catalog\SubscribeTable::sendRepeatedNotice();',
411 'catalog',
412 'N',
413 static::AGENT_INTERVAL,
414 '',
415 'Y',
416 $t->toString(),
417 100,
418 false,
419 false
420 );
421 }
422
423 return true;
424 }
425
433 public static function checkPermissionSubscribe($subscribe)
434 {
435 return $subscribe == 'Y' || ($subscribe == 'D' && (string)Option::get('catalog', 'default_subscribe') == 'Y');
436 }
437
445 public static function setOldProductAvailable($productId, $available)
446 {
447 if(!$productId || !$available)
448 {
449 return false;
450 }
451
452 static::$oldProductAvailable[$productId]['AVAILABLE'] = $available;
453
454 return true;
455 }
456
462 public static function sendNotice()
463 {
464 if(static::checkLastUpdate())
465 return '\Bitrix\Catalog\SubscribeTable::sendNotice();';
466
467 list($listSubscribe, $totalCount) = static::getSubscriptionsData();
468
469 if(empty($listSubscribe))
470 {
471 static::$agentNoticeCreated = false;
472 return '';
473 }
474
475 $anotherStep = (int)$totalCount['CNT'] > static::LIMIT_SEND;
476
477 list($dataSendToNotice, $listNotifiedSubscribeId) =
478 static::prepareDataForNotice($listSubscribe, 'CATALOG_PRODUCT_SUBSCRIBE_NOTIFY');
479
480 static::startEventNotification($dataSendToNotice);
481
482 if($listNotifiedSubscribeId)
483 static::setNeedSending($listNotifiedSubscribeId);
484
485 if($anotherStep)
486 {
487 return '\Bitrix\Catalog\SubscribeTable::sendNotice();';
488 }
489 else
490 {
491 static::$agentNoticeCreated = false;
492 return '';
493 }
494 }
495
501 public static function sendRepeatedNotice()
502 {
503 if(static::checkLastUpdate())
504 return 'Bitrix\Catalog\SubscribeTable::sendRepeatedNotice();';
505
506 list($listSubscribe, $totalCount) = static::getSubscriptionsData();
507
508 if(empty($listSubscribe))
509 {
510 static::$agentRepeatedNoticeCreated = false;
511 return '';
512 }
513
514 $anotherStep = (int)$totalCount['CNT'] > static::LIMIT_SEND;
515
516 list($dataSendToNotice, $listNotifiedSubscribeId) =
517 static::prepareDataForNotice($listSubscribe, 'CATALOG_PRODUCT_SUBSCRIBE_NOTIFY_REPEATED');
518
519 static::startEventNotification($dataSendToNotice);
520
521 if($listNotifiedSubscribeId)
522 static::setNeedSending($listNotifiedSubscribeId);
523
524 if($anotherStep)
525 {
526 return 'Bitrix\Catalog\SubscribeTable::sendRepeatedNotice();';
527 }
528 else
529 {
530 static::$agentRepeatedNoticeCreated = false;
531 return '';
532 }
533 }
534
542 protected static function checkOldProductAvailable($productId, $fields)
543 {
544 $productId = (int)$productId;
545 if ($productId <= 0 || (empty(static::$oldProductAvailable[$productId]))
546 || !static::checkPermissionSubscribe($fields['SUBSCRIBE']))
547 {
548 return false;
549 }
550
551 if(static::$oldProductAvailable[$productId]['AVAILABLE'] == ProductTable::STATUS_NO
552 && $fields['AVAILABLE'] == ProductTable::STATUS_YES)
553 {
554 static::runAgentToSendNotice($productId);
555 }
556 elseif(static::$oldProductAvailable[$productId]['AVAILABLE'] == ProductTable::STATUS_YES
557 && $fields['AVAILABLE'] == ProductTable::STATUS_NO)
558 {
559 static::runAgentToSendRepeatedNotice($productId);
560 }
561
562 unset(static::$oldProductAvailable[$productId]);
563
564 return true;
565 }
566
572 protected static function checkLastUpdate()
573 {
574 $lastUpdate = ProductTable::getList(
575 array(
576 'select' => array('TIMESTAMP_X'),
577 'order' => array('TIMESTAMP_X' => 'DESC'),
578 'limit' => 1
579 )
580 )->fetch();
581 if (empty($lastUpdate) || !($lastUpdate['TIMESTAMP_X'] instanceof DateTime))
582 return true;
583
584 return (time() - $lastUpdate['TIMESTAMP_X']->getTimestamp() < static::AGENT_TIME_OUT);
585 }
586
587 protected static function getSubscriptionsData()
588 {
589 global $DB;
590
591 $filter = array(
592 '=NEED_SENDING' => 'Y',
593 '!=PRODUCT.SUBSCRIBE' => 'N',
594 array(
595 'LOGIC' => 'OR',
596 array('=DATE_TO' => false),
597 array('>DATE_TO' => date($DB->dateFormatToPHP(\CLang::getDateFormat('FULL')), time()))
598 )
599 );
600
601 /* Compatibility with the sale subscribe option */
602 $notifyOption = Option::get('sale', 'subscribe_prod');
603 $notify = array();
604 if($notifyOption <> '')
605 $notify = unserialize($notifyOption, ['allowed_classes' => false]);
606 if(is_array($notify))
607 {
608 $listSiteId = array();
609 foreach($notify as $siteId => $data)
610 {
611 if($data['use'] != 'Y')
612 $listSiteId[] = $siteId;
613 }
614 if($listSiteId)
615 $filter['!=SITE_ID'] = $listSiteId;
616 }
617
618 $listSubscribe = static::getList(array(
619 'select'=>array(
620 'ID',
621 'USER_CONTACT',
622 'CONTACT_TYPE',
623 'DATE_TO',
624 'PRODUCT_NAME' => 'IBLOCK_ELEMENT.NAME',
625 'DETAIL_PAGE_URL' => 'IBLOCK_ELEMENT.IBLOCK.DETAIL_PAGE_URL',
626 'IBLOCK_ID' => 'IBLOCK_ELEMENT.IBLOCK_ID',
627 'TYPE' => 'PRODUCT.TYPE',
628 'ITEM_ID',
629 'SITE_ID',
630 'LANDING_SITE_ID',
631 'USER_NAME' => 'USER.NAME',
632 'USER_LAST_NAME' => 'USER.LAST_NAME',
633 ),
634 'filter' => $filter,
635 'limit' => static::LIMIT_SEND,
636 ))->fetchAll();
637
638 $totalCount = static::getList(array(
639 'select' => array('CNT'),
640 'filter' => $filter,
641 'runtime' => array(new Entity\ExpressionField('CNT', 'COUNT(*)'))
642 ))->fetch();
643
644 return array($listSubscribe, $totalCount);
645 }
646
647 protected static function prepareDataForNotice(array $listSubscribe, $eventName)
648 {
649 /* Preparation of data for the mail template */
650 $itemIdGroupByIblock = array();
651 foreach($listSubscribe as $key => $subscribeData)
652 $itemIdGroupByIblock[$subscribeData['IBLOCK_ID']][$subscribeData['ITEM_ID']] = $subscribeData['ITEM_ID'];
653
654 $detailPageUrlGroupByItemId = array();
655 if(!empty($itemIdGroupByIblock))
656 {
657 foreach($itemIdGroupByIblock as $iblockId => $listItemId)
658 {
659 $queryObject = \CIBlockElement::getList(array('ID'=>'ASC'),
660 array('IBLOCK_ID' => $iblockId, 'ID' => $listItemId), false, false, array('DETAIL_PAGE_URL'));
661 while($result = $queryObject->getNext())
662 $detailPageUrlGroupByItemId[$result['ID']] = $result['DETAIL_PAGE_URL'];
663 }
664 }
665
666 $dataSendToNotice = array();
667 $listNotifiedSubscribeId = array();
668 foreach($listSubscribe as $key => $subscribeData)
669 {
670 $pageUrl = self::getPageUrl($subscribeData, $detailPageUrlGroupByItemId);
671 if ($pageUrl == '')
672 {
673 continue;
674 }
675
676 $listNotifiedSubscribeId[] = $subscribeData['ID'];
677
678 $subscribeData['EVENT_NAME'] = $eventName;
679 $subscribeData['USER_NAME'] = $subscribeData['USER_NAME'] ?
680 $subscribeData['USER_NAME'] : Loc::getMessage('EMAIL_TEMPLATE_USER_NAME');
681 $subscribeData['EMAIL_TO'] = $subscribeData['USER_CONTACT'];
682 $subscribeData['NAME'] = $subscribeData['PRODUCT_NAME'];
683 $subscribeData['PAGE_URL'] = $pageUrl;
684 $subscribeData['PRODUCT_ID'] = $subscribeData['ITEM_ID'];
685 $subscribeData['CHECKOUT_URL'] = \CHTTP::urlAddParams($pageUrl, array(
686 'action' => 'BUY', 'id' => $subscribeData['PRODUCT_ID']));
687 $subscribeData['CHECKOUT_URL_PARAMETERS'] = \CHTTP::urlAddParams('', array(
688 'action' => 'BUY', 'id' => $subscribeData['PRODUCT_ID']));
689 $subscribeData['UNSUBSCRIBE_URL'] = \CHTTP::urlAddParams(
690 self::getUnsubscribeUrl($subscribeData),
691 array('unSubscribe' => 'Y', 'subscribeId' => $subscribeData['ID'],
692 'userContact' => $subscribeData['USER_CONTACT'], 'productId' => $subscribeData['PRODUCT_ID']));
693 $subscribeData['UNSUBSCRIBE_URL_PARAMETERS'] = \CHTTP::urlAddParams('',
694 array('unSubscribe' => 'Y', 'subscribeId' => $subscribeData['ID'],
695 'userContact' => $subscribeData['USER_CONTACT'], 'productId' => $subscribeData['PRODUCT_ID']));
696
697 $dataSendToNotice[$subscribeData['CONTACT_TYPE']][$subscribeData['USER_CONTACT']][$key] = $subscribeData;
698 }
699
700 return array($dataSendToNotice, $listNotifiedSubscribeId);
701 }
702
703 private static function getPageUrl(array $subscribeData, array $detailPageUrlGroupByItemId)
704 {
705 $pageUrl = "";
706
707 if (!empty($subscribeData['LANDING_SITE_ID']))
708 {
709 $pageUrl = Loader::includeModule('landing') ?
710 IblockConnector::getElementUrl($subscribeData['LANDING_SITE_ID'], $subscribeData['ITEM_ID']) : "";
711 }
712 elseif (!empty($detailPageUrlGroupByItemId[$subscribeData['ITEM_ID']]))
713 {
714 $pageUrl = self::getProtocol().self::getServerName($subscribeData['SITE_ID']).
715 $detailPageUrlGroupByItemId[$subscribeData['ITEM_ID']];
716 }
717
718 return $pageUrl;
719 }
720
721 private static function getUnsubscribeUrl(array $subscribeData)
722 {
723 if (!empty($subscribeData['LANDING_SITE_ID']))
724 {
725 $unsubscribeUrl = '';
726 if (Loader::includeModule('landing'))
727 {
728 $unsubscribeUrl = \Bitrix\Landing\Syspage::getSpecialPage(
729 $subscribeData['LANDING_SITE_ID'],
730 'personal',
731 ['SECTION' => 'subscribe']
732 );
733 }
734 }
735 else
736 {
737 $unsubscribeUrl = self::getProtocol().self::getServerName(
738 $subscribeData['SITE_ID']).'/personal/subscribe/';
739 }
740
741 return $unsubscribeUrl;
742 }
743
744 private static function getProtocol()
745 {
746 $currentApplication = Application::getInstance();
747 $context = $currentApplication->getContext();
748
749 if ($protocol = Option::get('main', 'mail_link_protocol'))
750 {
751 if (mb_strrpos($protocol, '://') === false)
752 $protocol .= '://';
753 }
754 else
755 {
756 if ($context->getServer()->getServerName())
757 {
758 $protocol = ($context->getRequest()->isHttps() ? 'https://' : 'http://');
759 }
760 else
761 {
762 $protocol = 'https://';
763 }
764 }
765
766 unset($currentApplication);
767 unset($context);
768
769 return $protocol;
770 }
771
772 private static function getServerName($siteId)
773 {
774 $serverName = '';
775 $iterator = \CSite::GetByID($siteId);
776 $site = $iterator->fetch();
777 unset($iterator);
778 if (!empty($site))
779 $serverName = (string)$site['SERVER_NAME'];
780 unset($site);
781 if ($serverName == '')
782 {
783 $serverName = (defined('SITE_SERVER_NAME') && SITE_SERVER_NAME != '' ?
784 SITE_SERVER_NAME : (string)Option::get('main', 'server_name', '', $siteId)
785 );
786 if ($serverName == '')
787 {
788 $currentApplication = Application::getInstance();
789 $context = $currentApplication->getContext();
790 $serverName = $context->getServer()->getServerName();
791 unset($currentApplication);
792 unset($context);
793 }
794 }
795
796 return $serverName;
797 }
798
799 protected static function startEventNotification(array $dataSendToNotice)
800 {
801 $contactTypes = static::getContactTypes();
802 foreach($contactTypes as $typeId => $typeData)
803 {
804 if (empty($dataSendToNotice[$typeId]))
805 {
806 continue;
807 }
808
809 $eventKey = EventManager::getInstance()
810 ->addEventHandler('catalog', 'OnSubscribeSubmit', $typeData['HANDLER']);
811
812 $event = new Event('catalog', 'OnSubscribeSubmit', $dataSendToNotice[$typeId]);
813 $event->send();
814
815 EventManager::getInstance()->removeEventHandler('catalog', 'OnSubscribeSubmit', $eventKey);
816 }
817 }
818
819 private static function setNeedSending(array $listSubscribeId, $needSending = 'N')
820 {
821 if(empty($listSubscribeId))
822 return;
823
824 $connection = Application::getConnection();
825 $helper = $connection->getSqlHelper();
826 $connection->queryExecute('update '.$helper->quote(static::getTableName()).' set '
827 .$helper->quote('NEED_SENDING').' = \''.$needSending.'\' where '
828 .$helper->quote('ID').' in ('.implode(',', $listSubscribeId).')'
829 );
830 }
831
832 private static function unSubscribe(array $listSubscribeId)
833 {
834 if(empty($listSubscribeId))
835 return;
836
837 $connection = Application::getConnection();
838 $helper = $connection->getSqlHelper();
839 $connection->queryExecute('update '.$helper->quote(static::getTableName()).' set '
840 .$helper->quote('NEED_SENDING').' = \'N\', '.$helper->quote('DATE_TO').' ='
841 .$helper->getCurrentDateTimeFunction().' where '
842 .$helper->quote('ID').' in ('.implode(',', $listSubscribeId).')'
843 );
844 }
845}
static onProductUpdate($productId, $fields)
static checkOldProductAvailable($productId, $fields)
static prepareDataForNotice(array $listSubscribe, $eventName)
static onProductSetAvailableUpdate($productId, $fields)
static checkPermissionSubscribe($subscribe)
static setOldProductAvailable($productId, $available)
static onAddContactType(&$contactTypes)
static runAgentToSendRepeatedNotice($productId)
static startEventNotification(array $dataSendToNotice)
static runAgentToSendNotice($productId)
static onIblockElementDelete($productId)
static getElementUrl($siteId, $elementId)
Definition iblock.php:14
static getConnection($name="")
send($sender=null)
Definition event.php:139
getParameter($key)
Definition event.php:80
static loadMessages($file)
Definition loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
static getList(array $parameters=array())
static createFromTimestamp($timestamp)
Definition datetime.php:246