Your IP : 18.225.92.235
<?php
namespace Bitrix\MessageService;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ArgumentTypeException;
use Bitrix\Main\ORM\Data\AddResult;
use Bitrix\Main\Error;
use Bitrix\Main;
use Bitrix\Main\Type\DateTime;
use Bitrix\MessageService\Integration\Pull;
use Bitrix\MessageService\Internal\Entity\MessageTable;
use Bitrix\MessageService\Restriction\RestrictionManager;
use Bitrix\MessageService\Sender\Result;
Loc::loadMessages(__FILE__);
class Message
{
public const EVENT_MESSAGE_UPDATED = 'messageUpdated';
protected $id;
/** @var Sender\Base $sender */
protected $sender;
/** @var string $type */
protected $type;
/** @var int $authorId */
protected $authorId = 0;
/** @var string $from */
protected $from;
/** @var string $to */
protected $to;
/** @var array $headers */
protected $headers = array();
/** @var string $body */
protected $body;
protected $statusId;
protected $externalStatus;
protected ?Error $error = null;
protected bool $checkRestrictions = false;
/**
* Message constructor.
* @param Sender\Base|null $sender
*/
public function __construct(Sender\Base $sender = null)
{
if ($sender)
{
$this->setSender($sender);
}
}
public static function loadById(int $id): ?Message
{
$fields = MessageTable::getRowById($id);
if (!$fields)
{
return null;
}
$instance = new static();
$instance->setFields($fields);
return $instance;
}
public static function loadByExternalId(string $senderId, string $externalId, ?string $from = null): ?Message
{
$fields = MessageTable::getByExternalId($senderId, $externalId, $from)->fetch();
if (!$fields)
{
return null;
}
$instance = new static();
$instance->setFields($fields);
return $instance;
}
/**
* @param array $fields
* @param Sender\Base|null $sender
* @return Message
*/
public static function createFromFields(array $fields, Sender\Base $sender = null): Message
{
$message = new static($sender);
$message->setFields($fields);
return $message;
}
public static function getFieldsById($messageId)
{
$iterator = Internal\Entity\MessageTable::getById($messageId);
return $iterator->fetch();
}
/**
* @param string $type
* @return Message
* @throws ArgumentTypeException
*/
public function setType(string $type): Message
{
if (!MessageType::isSupported($type))
{
throw new ArgumentTypeException('Unsupported message type');
}
$this->type = $type;
return $this;
}
/**
* @return string
*/
public function getType(): string
{
return $this->type;
}
public function checkFields(): Main\Result
{
$result = new Main\Result();
$sender = $this->getSender();
$from = $this->getFrom();
if (!$sender)
{
$result->addError(new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_SENDER')));
}
elseif (!$sender->canUse())
{
$result->addError(new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_SENDER_CAN_USE')));
}
elseif ($sender->getType() !== $this->getType())
{
$result->addError(new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_TYPE')));
}
elseif (!$from || !$sender->isCorrectFrom($from))
{
$result->addError(new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_FROM')));
}
return $result;
}
/**
* @return AddResult Created Message result.
*/
public function send(): Main\Result
{
global $USER;
$checkResult = $this->checkFields();
if (!$checkResult->isSuccess())
{
$result = new AddResult();
$result->addErrors($checkResult->getErrors());
return $result;
}
if ($this->checkRestrictions)
{
$restrictionManager = new RestrictionManager($this);
if (!$restrictionManager->isCanSendMessage())
{
return (new Main\Result())->addError(
new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_RESTRICTION'))
);
}
}
$sender = $this->getSender();
$headers = $this->getHeaders();
$result = Internal\Entity\MessageTable::add([
'TYPE' => $this->getType(),
'SENDER_ID' => $sender->getId(),
'AUTHOR_ID' => $this->getAuthorId(),
'MESSAGE_FROM' => $this->getFrom(),
'MESSAGE_TO' => $this->getTo(),
'MESSAGE_HEADERS' => count($headers) > 0 ? $headers : null,
'MESSAGE_BODY' => $this->getBody(),
'CLUSTER_GROUP' => defined('BX_CLUSTER_GROUP') ? BX_CLUSTER_GROUP : null
]);
if ($result->isSuccess())
{
$this->id = $result->getId();
if (Main\Config\Option::get('messageservice', 'event_log_message_send', 'N') === 'Y')
{
$userId = $USER instanceof \CUser ? $USER->getId() : 0;
\CEventLog::Log('INFO', 'MESSAGE_SEND', 'messageservice', $userId, $this->getTo());
}
}
return $result;
}
public function sendDirectly(): Result\SendMessage
{
global $USER;
$checkResult = $this->checkFields();
if (!$checkResult->isSuccess())
{
$result = new Result\SendMessage();
return $result->addErrors($checkResult->getErrors());
}
if ($this->checkRestrictions)
{
$restrictionManager = new RestrictionManager($this);
if (!$restrictionManager->isCanSendMessage())
{
return (new Result\SendMessage)->addError(
new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_RESTRICTION'))
);
}
}
$sender = $this->getSender();
if (!Sender\Limitation::checkDailyLimit($sender->getId(), $this->getFrom()))
{
$result = new Result\SendMessage();
$result->addError(new Error(Loc::getMessage('MESSAGESERVICE_MESSAGE_ERROR_LIMITATION')));
$result->setStatus(MessageStatus::DEFERRED);
return $result;
}
$headers = $this->getHeaders();
$messageFields = [
'TYPE' => $this->getType(),
'SENDER_ID' => $sender->getId(),
'AUTHOR_ID' => $this->getAuthorId(),
'MESSAGE_FROM' => $this->getFrom(),
'MESSAGE_TO' => $this->getTo(),
'MESSAGE_HEADERS' => count($headers) > 0 ? $headers : null,
'MESSAGE_BODY' => $this->getBody(),
'CLUSTER_GROUP' => defined('BX_CLUSTER_GROUP') ? BX_CLUSTER_GROUP : null
];
$sender->setSocketTimeout(5);
$sender->setStreamTimeout(15);
$result = $sender->sendMessage($messageFields);
$messageFields['DATE_EXEC'] = new DateTime();
$messageFields['SUCCESS_EXEC'] = $result->isSuccess() ? 'Y' : 'N';
if ($result->getExternalId() !== null)
{
$messageFields['EXTERNAL_ID'] = $result->getExternalId();
}
if ($result->getStatus() !== null)
{
$messageFields['STATUS_ID'] = $result->getStatus();
}
$addResult = Internal\Entity\MessageTable::add($messageFields);
if (!$addResult->isSuccess())
{
$result->addErrors($addResult->getErrors());
$result->setStatus(MessageStatus::ERROR);
return $result;
}
$this->id = $addResult->getId();
$result->setId($this->id);
if (Main\Config\Option::get('messageservice', 'event_log_message_send', 'N') === 'Y')
{
$userId = $USER instanceof \CUser ? $USER->getId() : 0;
\CEventLog::Log('INFO', 'MESSAGE_SEND', 'messageservice', $userId, $this->getTo());
}
return $result;
}
/**
* @return mixed
*/
public function getFrom()
{
return $this->from;
}
/**
* @param mixed $from
* @return $this
*/
public function setFrom($from): Message
{
$this->from = (string)$from;
return $this;
}
/**
* @return mixed
*/
public function getBody()
{
return $this->body;
}
/**
* @param mixed $body
* @return $this
*/
public function setBody($body): Message
{
$this->body = (string)$body;
return $this;
}
/**
* @return mixed
*/
public function getTo()
{
return $this->to;
}
/**
* @param mixed $to
* @return $this
*/
public function setTo($to): Message
{
$this->to = (string)$to;
return $this;
}
/**
* @return Sender\Base|null
*/
public function getSender(): ?Sender\Base
{
return $this->sender;
}
/**
* @param Sender\Base $sender
* @return $this
*/
public function setSender(Sender\Base $sender)
{
$this->sender = $sender;
return $this;
}
/**
* @param array $headers
* @return Message
*/
public function setHeaders(array $headers): Message
{
$this->headers = $headers;
return $this;
}
/**
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @param int $authorId
* @return Message
*/
public function setAuthorId(int $authorId): Message
{
$this->authorId = $authorId;
return $this;
}
/**
* @return int
*/
public function getAuthorId()
{
return $this->authorId;
}
/**
* @return Error|null
*/
public function getError(): ?Error
{
return $this->error;
}
/**
* @param Error $error
* @return Message
*/
public function setError(Error $error): self
{
$this->error = $error;
return $this;
}
public function getStatusId()
{
return $this->statusId;
}
public function update(array $fields): bool
{
$updateResult = MessageTable::update($this->id, $fields);
if (!$updateResult->isSuccess())
{
return false;
}
$this->setFields($fields);
// events
$eventFields = array_merge(['ID' => $this->id], $fields);
Main\EventManager::getInstance()->send(new Main\Event(
'messageservice',
static::EVENT_MESSAGE_UPDATED,
$eventFields)
);
Pull::onMessagesUpdate([$eventFields]);
return true;
}
public function updateWithSendResult(Result\SendMessage $result, DateTime $nextExec): void
{
$toUpdate = ['SUCCESS_EXEC' => 'E', 'DATE_EXEC' => new DateTime()];
if ($result->isSuccess())
{
$toUpdate['SUCCESS_EXEC'] = 'Y';
if ($result->getExternalId() !== null)
{
$toUpdate['EXTERNAL_ID'] = $result->getExternalId();
}
if ($result->getStatus() !== null)
{
$toUpdate['STATUS_ID'] = $result->getStatus();
}
}
elseif ($result->getStatus() === MessageStatus::DEFERRED)
{
$toUpdate = array(
'SUCCESS_EXEC' => 'N',
'NEXT_EXEC' => $nextExec,
'STATUS_ID' => MessageStatus::DEFERRED
);
}
else
{
$toUpdate['STATUS_ID'] = MessageStatus::ERROR;
}
$errors = $result->getErrorMessages();
if ($errors)
{
$toUpdate['EXEC_ERROR'] = implode(PHP_EOL, $errors);
}
$this->update($toUpdate);
}
public function updateStatusByExternalStatus(string $externalStatus): bool
{
$newInternalStatus = $this->sender::resolveStatus($externalStatus);
$isUpdateSuccess = MessageTable::updateMessageStatuses(
$this->id,
$newInternalStatus,
$externalStatus
);
if (!$isUpdateSuccess)
{
return false;
}
$this->statusId = $newInternalStatus;
// events
$eventFields = ['ID' => $this->id, 'STATUS_ID' => $this->statusId];
Main\EventManager::getInstance()->send(new Main\Event(
'messageservice',
static::EVENT_MESSAGE_UPDATED,
$eventFields)
);
Pull::onMessagesUpdate([$eventFields]);
return true;
}
public function updateStatus(int $newStatusId): bool
{
$updateResult = MessageTable::updateStatusId($this->id, $newStatusId);
if (!$updateResult)
{
return false;
}
$this->statusId = $newStatusId;
// events
$eventFields = ['ID' => $this->id, 'STATUS_ID' => $this->statusId];
Main\EventManager::getInstance()->send(new Main\Event(
'messageservice',
static::EVENT_MESSAGE_UPDATED,
$eventFields)
);
Pull::onMessagesUpdate([$eventFields]);
return true;
}
private function setFields(array $fields): void
{
if (!$this->sender && isset($fields['SENDER_ID']))
{
$sender = Sender\SmsManager::getSenderById($fields['SENDER_ID']);
if ($sender)
{
$this->setSender($sender);
}
}
if (isset($fields['ID']))
{
$this->id = (int)$fields['ID'];
}
if (isset($fields['TYPE']))
{
$this->setType($fields['TYPE']);
}
if (isset($fields['AUTHOR_ID']))
{
$this->setAuthorId((int)$fields['AUTHOR_ID']);
}
if (isset($fields['MESSAGE_FROM']))
{
$this->setFrom($fields['MESSAGE_FROM']);
}
if (isset($fields['MESSAGE_TO']))
{
$this->setTo($fields['MESSAGE_TO']);
}
if (
isset($fields['MESSAGE_TEMPLATE'])
&& $this->sender->isConfigurable()
&& $this->sender->isTemplatesBased()
)
{
$fields['MESSAGE_HEADERS'] = is_array($fields['MESSAGE_HEADERS']) ? $fields['MESSAGE_HEADERS'] : [];
$fields['MESSAGE_HEADERS']['template'] = $this->sender->prepareTemplate($fields['MESSAGE_TEMPLATE']);
}
if (isset($fields['MESSAGE_HEADERS']) && is_array($fields['MESSAGE_HEADERS']))
{
$this->setHeaders($fields['MESSAGE_HEADERS']);
}
if (isset($fields['MESSAGE_BODY']))
{
$messageBody = $this->sender
? $this->sender->prepareMessageBodyForSave($fields['MESSAGE_BODY'])
: $fields['MESSAGE_BODY']
;
$this->setBody($messageBody);
}
if (isset($fields['STATUS_ID']))
{
$this->statusId = $fields['STATUS_ID'];
}
if (isset($fields['EXTERNAL_STATUS']))
{
$this->externalStatus = $fields['EXTERNAL_STATUS'];
}
}
/**
* @param bool $checkRestrictions
*/
public function setCheckRestrictions(bool $checkRestrictions): void
{
$this->checkRestrictions = $checkRestrictions;
}
}