%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/sender/lib/internals/ |
| Current File : //home/bitrix/www/bitrix/modules/sender/lib/internals/countercalculation.php |
<?php
/**
* Bitrix Framework
* @package bitrix
* @subpackage sender
* @copyright 2001-2012 Bitrix
*/
namespace Bitrix\Sender\Internals;
use Bitrix\Main\Application;
use Bitrix\Main\Config\Option;
use Bitrix\Sender\Runtime;
class CounterCalculation
{
private static $optionName = '~update_counters_16';
public static $maxExecutionTime = 10;
private static $startTime = null;
private static $stages = array(
'RECIPIENT_READ' => '1',
'RECIPIENT_CLICK' => '2',
'RECIPIENT_UNSUB' => '3',
'POSTING_STATUS' => '4',
'POSTING_READ' => '5',
'POSTING_CLICK' => '6',
'POSTING_UNSUB' => '7',
'MAILING_SUBSCRIPTION' => '8',
'CONTACT_EMAIL_REGISTER' => '9',
'FINISH' => '',
);
public static function wasCompleted($stageCode = 'FINISH')
{
$currentValue = Option::get('sender', self::$optionName, '');
$stageValue = self::$stages[$stageCode];
if($currentValue === '')
{
$currentValue = '100';
}
if($stageValue === '')
{
$stageValue = '100';
}
if(intval($currentValue) >= intval($stageValue))
{
return true;
}
else
{
return false;
}
}
public static function setCompleted($stageCode = 'FINISH')
{
Option::set('sender', self::$optionName, self::$stages[$stageCode]);
}
public static function getCompletedPercent()
{
$currentValue = Option::get('sender', self::$optionName, '');
if($currentValue === '')
{
$currentValue = count(self::$stages);
}
$currentValue = intval($currentValue);
return array('CURRENT' => $currentValue, 'ALL' => count(self::$stages));
}
private static function isTimeUp()
{
if(self::$startTime === null)
{
self::$startTime = getmicrotime();
}
if(self::$maxExecutionTime > 0 && (getmicrotime() - self::$startTime) > self::$maxExecutionTime)
{
return true;
}
else
{
return false;
}
}
public static function getExecutionTime()
{
if(!self::$startTime)
{
return 0;
}
else
{
return getmicrotime() - self::$startTime;
}
}
public static function update()
{
if(self::wasCompleted())
{
return false;
}
$haveData = false;
// update reading counters of recipients
foreach(array('READ', 'CLICK', 'UNSUB') as $type)
{
if($haveData || self::wasCompleted('RECIPIENT_' . $type))
{
continue;
}
$haveData = self::updateRecipientReadCounters($type);
if(!$haveData)
{
self::setCompleted('RECIPIENT_' . $type);
}
}
// update status counters of posting
if(!$haveData && !self::wasCompleted('POSTING_STATUS'))
{
$haveData = self::updatePostingStatusCounters();
if(!$haveData)
{
self::setCompleted('POSTING_STATUS');
}
}
// update reading counters of posting
foreach(array('READ', 'CLICK', 'UNSUB') as $type)
{
if($haveData || self::wasCompleted('POSTING_' . $type))
{
continue;
}
$haveData = self::updatePostingReadCounters($type);
if(!$haveData)
{
self::setCompleted('POSTING_' . $type);
}
}
// update status counters of posting
if(!$haveData && !self::wasCompleted('MAILING_SUBSCRIPTION'))
{
$haveData = self::updateMailingSubscription();
if(!$haveData)
{
self::setCompleted('MAILING_SUBSCRIPTION');
}
}
// update contact email register
if(!$haveData && !self::wasCompleted('CONTACT_EMAIL_REGISTER'))
{
$haveData = self::updateContactEmailRegister();
if(!$haveData)
{
self::setCompleted('CONTACT_EMAIL_REGISTER');
}
}
// if all processed set done flag
if(!$haveData)
{
self::setCompleted();
}
return $haveData;
}
public static function updateRecipientReadCounters($type)
{
$params = array(
'select' => array('RECIPIENT_ID'),
'runtime' => array(
new \Bitrix\Main\Entity\ReferenceField(
'UPDATE_RECIPIENT',
'Bitrix\Sender\PostingRecipientTable',
array('=this.RECIPIENT_ID' => 'ref.ID')
)
),
'filter' => array(
'!UPDATE_RECIPIENT.ID' => null,
'=UPDATE_RECIPIENT.IS_' . $type => 'N',
),
'group' => array('RECIPIENT_ID')
);
$dataDb = null;
switch($type)
{
case 'READ':
$dataDb = \Bitrix\Sender\PostingReadTable::getList($params);
break;
case 'CLICK':
$dataDb = \Bitrix\Sender\PostingClickTable::getList($params);
break;
case 'UNSUB':
$dataDb = \Bitrix\Sender\PostingUnsubTable::getList($params);
break;
}
if(!$dataDb)
{
return false;
}
while($item = $dataDb->fetch())
{
if(self::isTimeUp())
{
return true;
}
\Bitrix\Sender\PostingRecipientTable::update(array('ID' => $item['RECIPIENT_ID']), array('IS_' . $type => 'Y'));
}
return false;
}
public static function updatePostingStatusCounters()
{
$lastPostingId = null;
$statusList = array();
$resultDb = \Bitrix\Sender\PostingRecipientTable::getList(array(
'select' => array('POSTING_ID', 'STATUS', 'CALC_COUNT'),
'filter' => array(
'!UPDATE_POSTING.ID' => null,
'!STATUS' => null,
'=UPDATE_POSTING.COUNT_SEND_ALL' => 0, // run only for postings with empty count field
'>CALC_COUNT' => 0 // run only if posting have recipients
),
'runtime' => array(
new \Bitrix\Main\Entity\ExpressionField('CALC_COUNT', 'COUNT(%s)', 'ID'),
new \Bitrix\Main\Entity\ReferenceField(
'UPDATE_POSTING',
'Bitrix\Sender\PostingTable',
array('=this.POSTING_ID' => 'ref.ID'),
array('join_type' => 'INNER')
),
),
'order' => array('CALC_COUNT' => 'DESC', 'POSTING_ID' => 'ASC'),
));
$stopRun = false;
while(!$stopRun)
{
if(self::isTimeUp())
{
return true;
}
$data = $resultDb->fetch();
// do update if last record or starts records for another posting
if(!$data || $lastPostingId != $data['POSTING_ID'])
{
// do update if it have fields for update
$updateFields = self::getPostingStatusUpdateFields($lastPostingId, $statusList);
if($updateFields)
{
\Bitrix\Sender\PostingTable::update(array('ID' => $lastPostingId), $updateFields);
}
$statusList = array();
}
if($data)
{
$lastPostingId = $data['POSTING_ID'];
$statusList[$data['STATUS']] = $data['CALC_COUNT'];
}
if(!$data)
{
$stopRun = true;
}
}
return false;
}
public static function updatePostingReadCounters($type)
{
$dataDb = \Bitrix\Sender\PostingRecipientTable::getList(array(
'select' => array(
'POSTING_ID',
'CNT'
),
'filter' => array(
'=UPDATE_POSTING.COUNT_' . $type => 0,
'>CNT' => 0,
'=IS_' . $type => 'Y'
),
'runtime' => array(
new \Bitrix\Main\Entity\ReferenceField(
'UPDATE_POSTING',
'Bitrix\Sender\PostingTable',
array('=this.POSTING_ID' => 'ref.ID'),
array('join_type' => 'INNER')
),
new \Bitrix\Main\Entity\ExpressionField('CNT', 'COUNT(%s)', 'ID')
),
'order' => array('CNT' => 'DESC', 'POSTING_ID' => 'ASC'),
));
while($item = $dataDb->fetch())
{
if(self::isTimeUp())
{
return true;
}
\Bitrix\Sender\PostingTable::update(array('ID' => $item['POSTING_ID']), array('COUNT_' . $type => $item['CNT']));
}
return false;
}
public static function updateMailingSubscription()
{
$dataDb = \Bitrix\Sender\PostingUnsubTable::getList(array(
'select' => array(
'CONTACT_ID' => 'POSTING_RECIPIENT.CONTACT_ID',
'MAILING_ID' => 'POSTING.MAILING_ID',
),
'filter' => array(),
'order' => array('ID' => 'ASC'),
));
while($data = $dataDb->fetch())
{
if(self::isTimeUp())
{
return true;
}
$primary = array('MAILING_ID' => $data['MAILING_ID'], 'CONTACT_ID' => $data['CONTACT_ID']);
$fields = array('IS_UNSUB' => 'Y');
$row = \Bitrix\Sender\MailingSubscriptionTable::getRowById($primary);
if(!$row)
{
$result = \Bitrix\Sender\MailingSubscriptionTable::add($fields + $primary);
$result->isSuccess();
}
}
return false;
}
public static function updateContactEmailRegister()
{
$query = null;
$connection = \Bitrix\Main\Application::getConnection();
switch(strtoupper($connection->getType()))
{
case 'MSSQL':
$query = "SELECT ID FROM b_sender_contact WHERE TYPE_ID=1 AND CODE LIKE '%[A-Z]%' COLLATE Latin1_General_BIN";
break;
case 'MYSQL':
$query = "SELECT ID FROM b_sender_contact WHERE TYPE_ID=1 AND CODE REGEXP BINARY '[A-Z]'";
break;
case 'ORACLE':
$query = "SELECT ID FROM b_sender_contact WHERE TYPE_ID=1 AND REGEXP_LIKE(CODE, '[A-Z]')";
break;
}
if($query)
{
$senderContactDb = $connection->query($query);
while($senderContact = $senderContactDb->fetch())
{
if(self::isTimeUp())
{
return true;
}
$connection->Query("UPDATE b_sender_contact SET CODE = LOWER(CODE) WHERE TYPE_ID=1 AND ID = " . intval($senderContact['ID']));
}
}
return false;
}
private static function getPostingStatusUpdateFields($postingId, $statusList)
{
if(!$postingId || count($statusList) == 0)
{
return null;
}
$postingUpdateFields = array('COUNT_SEND_ALL' => 0);
$map = \Bitrix\Sender\PostingTable::getRecipientStatusToPostingFieldMap();
foreach($map as $recipientStatus => $postingFieldName)
{
if(!array_key_exists($recipientStatus, $statusList))
{
continue;
}
else
{
$postingCountFieldValue = $statusList[$recipientStatus];
}
$postingUpdateFields['COUNT_SEND_ALL'] += $postingCountFieldValue;
$postingUpdateFields[$postingFieldName] = $postingCountFieldValue;
}
if($postingUpdateFields['COUNT_SEND_ALL'] == 0)
{
return null;
}
return $postingUpdateFields;
}
/**
* Index letters.
*
* @return string
*/
public static function updateRecipientsAgent()
{
$conn = Application::getConnection();
$hasData = false;
if ($conn->isTableExists('b_sender_posting_rcpnt_old'))
{
$limit = 1000;
$timer = new Runtime\Timer(Runtime\Env::getJobExecutionTimeout(), 100);
while (!$timer->isElapsed())
{
$hasData = true;
$sql = "INSERT IGNORE
INTO b_sender_posting_recipient
(
CONTACT_ID,
POSTING_ID,
STATUS,
USER_ID,
FIELDS,
ROOT_ID,
IS_READ,
IS_CLICK,
IS_UNSUB,
DATE_DENY,
DATE_SENT
)
SELECT
c.ID as CONTACT_ID,
ro2.POSTING_ID,
ro2.STATUS,
ro2.USER_ID,
ro2.FIELDS,
ro2.ROOT_ID,
ro2.IS_READ,
ro2.IS_CLICK,
ro2.IS_UNSUB,
ro2.DATE_DENY,
ro2.DATE_SENT
FROM
(
SELECT
ro.ID,
ro.POSTING_ID,
ro.STATUS,
ro.USER_ID,
ro.FIELDS,
ro.ROOT_ID,
ro.IS_READ,
ro.IS_CLICK,
ro.IS_UNSUB,
ro.DATE_DENY,
ro.EMAIL,
ro.DATE_SENT
FROM
b_sender_posting_rcpnt_old ro
order by
ro.ID ASC
limit $limit
) ro2,
b_sender_posting p,
b_sender_contact c
WHERE
ro2.POSTING_ID = p.ID
and c.TYPE_ID = 1
and c.CODE = ro2.EMAIL
order by ro2.ID ASC
limit $limit";
$conn->query($sql);
$conn->query("delete from b_sender_posting_rcpnt_old order by ID asc limit $limit");
if (!$conn->query('select ID from b_sender_posting_rcpnt_old limit 1')->fetch())
{
$hasData = false;
break;
}
}
}
if (!$hasData)
{
Application::getConnection()->query(
"DROP TABLE IF EXISTS b_sender_posting_rcpnt_old"
);
return '';
}
else
{
return '\Bitrix\Sender\Internals\CounterCalculation::updateRecipientsAgent();';
}
}
}