%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/sender/lib/posting/ |
| Current File : /home/bitrix/www/bitrix/modules/sender/lib/posting/builder.php |
<?php
/**
* Bitrix Framework
* @package bitrix
* @subpackage sender
* @copyright 2001-2012 Bitrix
*/
namespace Bitrix\Sender\Posting;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Application;
use Bitrix\Sender\Connector;
use Bitrix\Sender\Integration;
use Bitrix\Sender\Entity;
use Bitrix\Sender\MailingSubscriptionTable;
use Bitrix\Sender\Recipient;
use Bitrix\Sender\Message;
use Bitrix\Sender\PostingTable;
use Bitrix\Sender\ContactTable;
use Bitrix\Sender\MailingGroupTable;
use Bitrix\Sender\PostingRecipientTable;
use Bitrix\Sender\Internals\Model\LetterSegmentTable;
use Bitrix\Sender\Internals\SqlBatch;
Loc::loadMessages(__FILE__);
/**
* Class Builder
* @package Bitrix\Sender\Posting
*/
class Builder
{
/** @var bool $checkDuplicates Check duplicates. */
protected $checkDuplicates = true;
/** @var array $groupCount Group count. */
protected $groupCount = array();
/** @var integer $postingId Posting ID. */
protected $postingId;
/** @var array $postingData Posting data. */
protected $postingData;
/** @var integer $typeId Type ID. */
protected $typeId;
/**
* Create instance.
*
* @return static
*/
public static function create()
{
return new static();
}
/**
* Shaper constructor.
*
* @param integer|null $postingId Posting ID.
* @param bool $checkDuplicates Check duplicates.
*/
public function __construct($postingId = null, $checkDuplicates = true)
{
if ($postingId)
{
$this->run($postingId, $checkDuplicates);
}
}
/**
* Load.
*
* @param integer $postingId Posting ID.
* @param bool $checkDuplicates Check duplicates.
*/
public function run($postingId, $checkDuplicates = true)
{
$postingData = PostingTable::getList(array(
'select' => array('*', 'MESSAGE_TYPE' => 'MAILING_CHAIN.MESSAGE_CODE'),
'filter' => array('ID' => $postingId),
'limit' => 1
))->fetch();
if(!$postingData)
{
return;
}
$this->postingData = $postingData;
$this->checkDuplicates = $checkDuplicates;
$this->postingId = $postingId;
$this->groupCount = array();
if(!$checkDuplicates)
{
if($this->postingData['STATUS'] === PostingTable::STATUS_NEW)
{
self::clean($postingId);
$this->checkDuplicates = false;
}
}
$message = Message\Adapter::create($this->postingData['MESSAGE_TYPE']);
foreach ($message->getSupportedRecipientTypes() as $typeId)
{
if (!Recipient\Type::getCode($typeId))
{
continue;
}
$this->typeId = $typeId;
$this->runForRecipientType();
}
PostingTable::update(
array('ID' => $postingId),
array(
'COUNT_SEND_ALL' => PostingRecipientTable::getCount(array('POSTING_ID' => $postingId))
)
);
}
protected function runForRecipientType()
{
// fetch all connectors for getting emails
$groups = array();
$groups = array_merge($groups, $this->getLetterConnectors($this->postingData['MAILING_CHAIN_ID']));
$groups = array_merge($groups, $this->getSubscriptionConnectors($this->postingData['MAILING_ID']));
// sort groups by include value
usort(
$groups,
function ($a, $b)
{
if ($a['INCLUDE'] == $b['INCLUDE'])
{
return 0;
}
return ($a['INCLUDE'] > $b['INCLUDE']) ? -1 : 1;
}
);
// import recipients
foreach($groups as $group)
{
if (is_array($group['ENDPOINT']) && !(isset($group['CONNECTOR']) && $group['CONNECTOR'] instanceof Connector\Base))
{
$group['CONNECTOR'] = Connector\Manager::getConnector($group['ENDPOINT']);
}
if(empty($group['CONNECTOR']))
{
continue;
}
$connector = $group['CONNECTOR'];
$connector->setDataTypeId($this->typeId);
if (is_array($group['ENDPOINT']['FIELDS']))
{
$connector->setFieldValues($group['ENDPOINT']['FIELDS']);
}
$this->fill($connector, $group['INCLUDE'], $group['GROUP_ID']);
}
// update group counter of addresses
foreach($this->groupCount as $groupId => $count)
{
Entity\Segment::updateAddressCounters(
$groupId,
array(
new Connector\DataCounter(array(
$this->typeId => $count
))
)
);
}
}
protected static function clean($postingId)
{
$primary = array('POSTING_ID' => $postingId);
PostingRecipientTable::delete($primary);
PostingTable::update(
array('ID' => $postingId),
array(
'COUNT_SEND_ALL' => 0,
'COUNT_SEND_NONE' => 0,
'COUNT_SEND_ERROR' => 0,
'COUNT_SEND_SUCCESS' => 0,
)
);
}
protected function getTypeCode()
{
return Recipient\Type::getCode($this->typeId);
}
protected function getSubscriptionConnectors($campaignId)
{
$groups = array();
$groups[] = array(
'INCLUDE' => true,
'ENDPOINT' => array('FIELDS' => array('MAILING_ID' => $campaignId)),
'GROUP_ID' => null,
'CONNECTOR' => new Integration\Sender\Connectors\Subscriber
);
$groups[] = array(
'INCLUDE' => false,
'ENDPOINT' => array('FIELDS' => array('MAILING_ID' => $campaignId)),
'GROUP_ID' => null,
'CONNECTOR' => new Integration\Sender\Connectors\UnSubscribers
);
return $groups;
}
protected function getCampaignGroups($campaignId)
{
$groups = array();
$groupConnectorDb = MailingGroupTable::getList(array(
'select' => array(
'INCLUDE',
'CONNECTOR_ENDPOINT' => 'GROUP.GROUP_CONNECTOR.ENDPOINT',
'GROUP_ID'
),
'filter' => array(
'=MAILING_ID' => $campaignId,
),
'order' => array('INCLUDE' => 'DESC', 'GROUP_ID' => 'ASC')
));
while($group = $groupConnectorDb->fetch())
{
$groups[] = array(
'INCLUDE' => $group['INCLUDE'],
'ENDPOINT' => $group['CONNECTOR_ENDPOINT'],
'GROUP_ID' => $group['GROUP_ID'],
'CONNECTOR' => null
);
}
return $groups;
}
protected function getLetterConnectors($letterId)
{
$groups = array();
$groupConnectors = LetterSegmentTable::getList(array(
'select' => array(
'INCLUDE',
'CONNECTOR_ENDPOINT' => 'SEGMENT.GROUP_CONNECTOR.ENDPOINT',
'SEGMENT_ID'
),
'filter' => array(
'=LETTER_ID' => $letterId,
),
'order' => array('INCLUDE' => 'DESC', 'LETTER_ID' => 'ASC')
));
while($group = $groupConnectors->fetch())
{
$groups[] = array(
'INCLUDE' => $group['INCLUDE'],
'ENDPOINT' => $group['CONNECTOR_ENDPOINT'],
'GROUP_ID' => $group['SEGMENT_ID'],
'CONNECTOR' => null
);
}
return $groups;
}
protected function setRecipientIdentificators(array &$dataList)
{
if (count($dataList) === 0)
{
return;
}
$codes = array_keys($dataList);
$tableName = ContactTable::getTableName();
$subsTableName = MailingSubscriptionTable::getTableName();
$existed = [];
$contactCodeFilter = [];
$connection = Application::getConnection();
$primariesString = SqlBatch::getInString($codes);
$recipientDb = $connection->query(
"select c.ID, c.NAME, c.CODE, c.BLACKLISTED, s.IS_UNSUB " .
"from $tableName c " .
"left join $subsTableName s on " .
"c.ID = s.CONTACT_ID " .
"and s.MAILING_ID=" . (int) $this->postingData['MAILING_ID'] . " " .
"where c.TYPE_ID = " . (int) $this->typeId . " and c.CODE in ($primariesString)"
);
while ($row = $recipientDb->fetch())
{
$existed[] = $row['CODE'];
if ($row['BLACKLISTED'] === 'Y' || $row['IS_UNSUB'] === 'Y')
{
unset($dataList[$row['CODE']]);
continue;
}
$dataList[$row['CODE']]['CONTACT_ID'] = $row['ID'];
$name = isset($dataList[$row['CODE']]['NAME']) ? $dataList[$row['CODE']]['NAME'] : null;
if ($name && $name !== $row['NAME'])
{
$contactCodeFilter[] = $row['CODE'];
}
}
// update existed contact names
$this->updateContacts($dataList, $contactCodeFilter);
// exit if no new contacts
if (count($existed) === count($codes))
{
return;
}
// add new contacts
$list = array_diff($codes, $existed);
$batch = array();
$sqlDateTimeFunction = Application::getConnection()->getSqlHelper()->getCurrentDateTimeFunction();
$updateFieldsOnDuplicate = array(
array('NAME' => 'DATE_UPDATE', 'VALUE' => $sqlDateTimeFunction),
);
foreach ($list as $code)
{
$batchItem = array(
'TYPE_ID' => $this->typeId,
'CODE' => $code,
'DATE_INSERT' => array('VALUE' => $sqlDateTimeFunction),
'DATE_UPDATE' => array('VALUE' => $sqlDateTimeFunction),
);
$key = 'NAME';
if (isset($dataList[$key]) && $dataList[$key])
{
$batchItem[$key] = $dataList[$key];
if (!in_array($key, $updateFieldsOnDuplicate))
{
$updateFieldsOnDuplicate[] = $key;
}
}
$batch[] = $batchItem;
}
SqlBatch::insert($tableName, $batch, $updateFieldsOnDuplicate);
$recipientDb = $connection->query(
"select ID, CODE " .
"from $tableName " .
"where TYPE_ID = " . (int) $this->typeId . " and CODE in ($primariesString)"
);
while ($row = $recipientDb->fetch())
{
$dataList[$row['CODE']]['CONTACT_ID'] = $row['ID'];
}
}
protected function fill(Connector\Base $connector, $isInclude = false, $groupId = null)
{
$count = 0;
$typeCode = $this->getTypeCode();
$result = $connector->getResult();
while (true)
{
$dataList = array();
$maxPart = 500;
while ($data = $result->fetch())
{
if (!isset($data[$typeCode]) || !$data[$typeCode])
{
continue;
}
$primary = Recipient\Normalizer::normalize($data[$typeCode], $this->typeId);
if (strlen($primary) <= 0)
{
continue;
}
$dataList[$primary] = $data;
$count++;
$maxPart--;
if ($maxPart == 0)
{
break;
}
}
if (count($dataList) === 0)
{
break;
}
$this->setRecipientIdentificators($dataList);
if ($isInclude)
{
// add address if not exists
if ($this->checkDuplicates)
{
$primariesString = SqlBatch::getInString(array_keys($dataList));
$connection = Application::getConnection();
$rowDb = $connection->query(
"select r.CODE " .
"from b_sender_posting_recipient pr, b_sender_contact r " .
"where pr.CONTACT_ID = r.ID " .
"and pr.POSTING_ID = " . (int) $this->postingId . " " .
"and r.TYPE_ID = " . (int) $this->typeId . " " .
"and r.CODE in ($primariesString)"
);
while ($row = $rowDb->fetch())
{
unset($dataList[$row['CODE']]);
}
}
if (empty($dataList))
{
continue;
}
$this->addPostingRecipients($dataList);
}
else
{
$this->removePostingRecipients($dataList);
}
}
$this->incGroupCounters($groupId, $count);
}
protected function removePostingRecipients(array &$list)
{
$primaries = array();
foreach($list as $code => $data)
{
if (!isset($data['CONTACT_ID']) || !$data['CONTACT_ID'])
{
continue;
}
$primaries[] = (int) $data['CONTACT_ID'];
}
if (count($primaries) === 0)
{
return;
}
$connection = Application::getConnection();
$primariesString = implode(',', $primaries);
$connection->query(
"delete " .
"from b_sender_posting_recipient " .
"where POSTING_ID = " . (int) $this->postingId . " " .
"and CONTACT_ID in (" . $primariesString . ")"
);
}
protected function updateContacts(array &$list, array $codeFilter)
{
$fields = [];
foreach ($codeFilter as $code)
{
if (!isset($list[$code]))
{
continue;
}
$item = $list[$code];
$fields[] = ['ID' => $item['CONTACT_ID'], 'NAME' => $item['NAME']];
}
SqlBatch::update(ContactTable::getTableName(), $fields);
}
protected function addPostingRecipients(array &$list)
{
$dataList = array();
foreach($list as $code => $data)
{
$recipientInsert = array(
'CONTACT_ID' => (int) $data['CONTACT_ID'],
'STATUS' => PostingRecipientTable::SEND_RESULT_NONE,
'POSTING_ID' => (int) $this->postingId,
'USER_ID' => null,
'FIELDS' => null
);
if (array_key_exists('USER_ID', $data) && intval($data['USER_ID']) > 0)
{
$recipientInsert['USER_ID'] = intval($data['USER_ID']);
}
if (array_key_exists('FIELDS', $data) && count($data['FIELDS']) > 0)
{
$recipientInsert['FIELDS'] = serialize($data['FIELDS']);
}
$dataList[] = $recipientInsert;
}
if(count($dataList) == 0)
{
return;
}
SqlBatch::insert(
PostingRecipientTable::getTableName(),
$dataList,
array('USER_ID', 'FIELDS')
);
}
protected function incGroupCounters($groupId = null, $count = 0)
{
if (!$groupId)
{
return;
}
if (array_key_exists($groupId, $this->groupCount))
{
$this->groupCount[$groupId] += $count;
}
else
{
$this->groupCount[$groupId] = $count;
}
}
}