Your IP : 18.116.49.66


Current Path : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/catalog/lib/product/
Upload File :
Current File : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/catalog/lib/product/subscribemanager.php

<?php
namespace Bitrix\Catalog\Product;

use Bitrix\Catalog\ProductTable;
use Bitrix\Catalog\SubscribeAccessTable;
use Bitrix\Catalog\SubscribeTable;
use Bitrix\Main\Error;
use Bitrix\Main\ErrorCollection;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\Security\Random;
use Bitrix\Main\Event;
use Bitrix\Main\EventManager;
use Bitrix\Main\Entity;

Loc::loadMessages(__FILE__);

/**
 * Class SubscribeManager manages subscriptions.
 *
 **/
class SubscribeManager
{
	const ERROR_REQUIRED_PARAMATERS = 'ERROR_REQUIRED_PARAMATERS_12001';
	const ERROR_ADD_SUBSCRIBE = 'ERROR_ADD_SUBSCRIBE_12002';
	const ERROR_VALIDATE_FIELDS = 'ERROR_VALIDATE_FIELDS_12003';
	const ERROR_SUBSCRIBER_IDENTIFICATION = 'ERROR_SUBSCRIBER_IDENTIFICATION_12004';
	const ERROR_AUTHORIZATION = 'ERROR_AUTHORIZATION_12005';
	const ERROR_DELETE_SUBSCRIBE = 'ERROR_ADD_SUBSCRIBE_12006';
	const ERROR_ADD_SUBSCRIBE_ALREADY_EXISTS = 'ERROR_ADD_SUBSCRIBE_ALREADY_EXISTS_12007';
	const ERROR_ACTIVITY_CHANGE = 'ERROR_ACTIVITY_CHANGE_12008';
	const ERROR_UNSUBSCRIBE = 'ERROR_UNSUBSCRIBE_12009';

	/** @var  ErrorCollection */
	protected $errorCollection;
	/** @var integer */
	protected $userId = 0;
	/** @var bool|null  */
	protected $isAdmin = false;

	public $contactTypes = array();

	protected $fields = array();
	protected $listAvailableFields = array(
		'DATE_TO',
		'USER_CONTACT',
		'CONTACT_TYPE',
		'USER_ID',
		'ITEM_ID',
		'NEED_SENDING',
		'SITE_ID',
	);

	public function __construct()
	{
		$this->errorCollection = new ErrorCollection;

		$this->contactTypes = SubscribeTable::getContactTypes();

		global $USER;
		if(is_object($USER) && $USER->isAuthorized())
		{
			$this->isAdmin = $USER->isAdmin();
			$this->userId = $USER->getId();
		}
	}
	
	/**
	 * @return array An array containing Error objects.
	 */
	public function getErrors()
	{
		return $this->errorCollection->toArray();
	}

	/**
	 * The method creates a new subscription.
	 *
	 * @param array $subscribeData An array containing the data of a new subscription.
	 * @return bool|int
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Bitrix\Main\ArgumentNullException
	 * @throws \Exception
	 */
	public function addSubscribe(array $subscribeData)
	{
		$this->checkRequiredInputParams($subscribeData,
			array('USER_CONTACT', 'ITEM_ID', 'SITE_ID', 'CONTACT_TYPE'));
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		$resultObject = ProductTable::getList(array(
			'select' => array(
				'SUBSCRIBE',
				'USER_CONTACT' => 'Bitrix\Catalog\SubscribeTable:PRODUCT.USER_CONTACT',
				'CONTACT_TYPE' => 'Bitrix\Catalog\SubscribeTable:PRODUCT.CONTACT_TYPE',
				'DATE_TO' => 'Bitrix\Catalog\SubscribeTable:PRODUCT.DATE_TO',
			),
			'filter' => array(
				'=ID' => $subscribeData['ITEM_ID'],
			),
		));
		while($productSubscribeData = $resultObject->fetch())
		{
			if(!$this->checkDataBeforeSave($productSubscribeData, $subscribeData))
				break;
		}
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		$this->fields = array();
		foreach($subscribeData as $fieldId => $fieldValue)
		{
			if(in_array($fieldId, $this->listAvailableFields))
			{
				$this->fields[$fieldId] = $fieldValue;
			}
		}

		$this->validateFields();
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		$result = SubscribeTable::add($this->fields);
		if($result->isSuccess())
		{
			$this->setSessionOfSibscribedProducts($subscribeData['ITEM_ID']);
			return $result->getId();
		}
		else
		{
			foreach($result->getErrorMessages() as $errorMessage)
				$this->errorCollection->add(array(new Error($errorMessage, self::ERROR_ADD_SUBSCRIBE)));
			return false;
		}
	}

	/**
	 * The method removes a lot of subscriptions received subscribeId list with the account permissions.
	 *
	 * @param array $listSubscribeId List subscribe id.
	 * @param integer $itemId If this parameter is passed, cleaned write to the session.
	 * @return bool
	 * @throws \Exception
	 */
	public function deleteManySubscriptions(array $listSubscribeId, $itemId = 0)
	{
		foreach($listSubscribeId as $subscribeId)
		{
			if($this->checkAccessToSubscription($subscribeId))
			{
				$result = SubscribeTable::delete($subscribeId);
				if(!$result->isSuccess())
				{
					foreach($result->getErrorMessages() as $errorMessage)
						$this->errorCollection->add(array(new Error($errorMessage, self::ERROR_DELETE_SUBSCRIBE)));
					return false;
				}
			}
			else
			{
				$this->errorCollection->add(array(new Error(
					Loc::getMessage('ERROR_ACCESS_DENIDE_DELETE_SUBSCRIBE'), self::ERROR_DELETE_SUBSCRIBE)));
				return false;
			}
		}

		if(!empty($_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'][$itemId]))
		{
			unset($_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'][$itemId]);
		}

		return true;
	}

	/**
	 * The method checks the access to subscription by using the userId or token.
	 * Administrators subscription is always available.
	 *
	 * @param integer $subscribeId Subscribe id.
	 * @return bool
	 * @throws \Bitrix\Main\ArgumentException
	 */
	public function checkAccessToSubscription($subscribeId)
	{
		if($this->isAdmin)
		{
			return true;
		}

		$resultObject = SubscribeTable::getList(array(
			'select' => array(
				'USER_ID',
				'TOKEN' => 'Bitrix\Catalog\SubscribeAccessTable:SUBSCRIBE.TOKEN',
			),
			'filter' => array('=ID' => intval($subscribeId)),
		));
		if($subscribeData = $resultObject->fetch())
		{
			if($this->userId)
			{
				if($subscribeData['USER_ID'] == $this->userId)
				{
					return true;
				}
			}
			else
			{
				if(isset($_SESSION['SUBSCRIBE_PRODUCT']['TOKEN'])
					&& $subscribeData['TOKEN'] == $_SESSION['SUBSCRIBE_PRODUCT']['TOKEN'])
				{
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * The method begins the process of identification of the anonymous subscriber.
	 *
	 * @param array $subscriberData An array containing the data necessary for identification.
	 * @param bool $sendLetter Marker, checks whether to send a letter.
	 * @return bool
	 * @throws \Bitrix\Main\ArgumentNullException
	 */
	public function runSubscriberIdentification(array $subscriberData, $sendLetter = true)
	{
		$this->checkRequiredInputParams($subscriberData,
			array('contactType', 'userContact', 'siteId'));
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		$currentContactType = $this->contactTypes[$subscriberData['contactType']];
		if(!preg_match($currentContactType['RULE'], $subscriberData['userContact']))
		{
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_SUBSCRIBE_ENTRY_CONFIRMATION_CODE'), self::ERROR_SUBSCRIBER_IDENTIFICATION)));
			return false;
		}

		$token = Random::getString(6);

		try
		{
			SubscribeAccessTable::clearOldRows();
			$accessRow = SubscribeAccessTable::getRow(
				array(
					'select' => array('ID'),
					'filter' => array('=USER_CONTACT' => $subscriberData['userContact'])
				)
			);
			if($accessRow['ID'])
			{
				$result = SubscribeAccessTable::update($accessRow['ID'], array(
					'DATE_FROM' => new DateTime(),
					'TOKEN' => $token
				));
			}
			else
			{
				$result = SubscribeAccessTable::add(array(
					'DATE_FROM' => new DateTime(),
					'USER_CONTACT' => $subscriberData['userContact'],
					'TOKEN' => $token
				));
			}
			if(!$result)
			{
				$this->errorCollection->add(array(new Error(
					Loc::getMessage('ERROR_SUBSCRIBE_ENTRY_CONFIRMATION_CODE'), self::ERROR_SUBSCRIBER_IDENTIFICATION)));
			}
		}
		catch(\Exception $errorObject)
		{
			$this->errorCollection->add(array(new Error($errorObject->getMessage())));
		}

		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		if(!$sendLetter)
		{
			return true;
		}

		/* Preparation of data for the mail template */
		$dataSendToNotice = array();
		$listSubscribesUrl = \CHTTP::URN2URI('/personal/subscribe/');
		$dataSendToNotice[$subscriberData['contactType']][$subscriberData['userContact']][] = array(
			'EVENT_NAME' => 'CATALOG_PRODUCT_SUBSCRIBE_LIST_CONFIRM',
			'EMAIL_TO' => $subscriberData['userContact'],
			'SITE_ID' => $subscriberData['siteId'],
			'USER_NAME' => Loc::getMessage('EMAIL_TEMPLATE_USER_NAME'),
			'TOKEN' => $token,
			'LIST_SUBSCRIBES' => $listSubscribesUrl,
			'TOKEN_URL' => \CHTTP::urlAddParams($listSubscribesUrl, array('accessCodeVerification' => 'Y',
				'userContact' => $subscriberData['userContact'], 'subscribeToken' => $token)),
			'URL_PARAMETERS' => \CHTTP::urlAddParams('', array('accessCodeVerification' => 'Y',
				'userContact' => $subscriberData['userContact'], 'subscribeToken' => $token))
		);

		foreach($this->contactTypes as $typeId => $typeData)
		{
			$eventKey = EventManager::getInstance()
				->addEventHandler('catalog', 'OnSubscribeSubmit', $typeData['HANDLER']);

			$event = new Event('catalog', 'OnSubscribeSubmit', $dataSendToNotice[$typeId]);
			$event->send();

			EventManager::getInstance()->removeEventHandler('catalog', 'OnSubscribeSubmit', $eventKey);
		}

		return true;
	}

	/**
	 * The method authenticates an anonymous subscriber.
	 *
	 * @param array $authorizationData The authentication information.
	 * @return bool
	 */
	public function authorizeSubscriber(array $authorizationData)
	{
		$this->checkRequiredInputParams($authorizationData, array('userContact', 'subscribeToken'));
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		try
		{
			SubscribeAccessTable::clearOldRows();
			$accessRow = SubscribeAccessTable::getRow(
				array(
					'select' => array('ID'),
					'filter' => array(
						'TOKEN' => $authorizationData['subscribeToken'],
						'USER_CONTACT' => $authorizationData['userContact']
					)
				)
			);

			if(!$accessRow['ID'])
			{
				$this->errorCollection->add(array(new Error(
					Loc::getMessage('ERROR_AUTHORIZATION_ACCESS_ROW_NOT_FOUND'), self::ERROR_AUTHORIZATION)));
				return false;
			}

			$_SESSION['SUBSCRIBE_PRODUCT'] = array(
				'TOKEN' => $authorizationData['subscribeToken'],
				'USER_CONTACT' => $authorizationData['userContact']
			);
		}
		catch(\Exception $errorObject)
		{
			$this->errorCollection->add(array(new Error($errorObject->getMessage())));
		}

		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		return true;
	}

	/**
	 * Method unsubscribe subscribers with fixed input data.
	 * 
	 * @param array $data Input data.
	 * @return bool
	 * @throws \Bitrix\Main\ArgumentException
	 * @throws \Exception
	 */
	public function unSubscribe(array $data)
	{
		$this->checkRequiredInputParams($data, array('unSubscribe', 'userContact', 'subscribeId', 'productId'));
		if(!$this->errorCollection->isEmpty())
		{
			return false;
		}

		$subscribe = SubscribeTable::getList(array(
			'select' => array('CNT'),
			'filter' => array(
				'=ID' => intval($data['subscribeId']),
				'=ITEM_ID' => intval($data['productId']),
				'=USER_CONTACT' => $data['userContact'],
			),
			'runtime' => array(new Entity\ExpressionField('CNT', 'COUNT(*)'))
		))->fetch();
		if(intval($subscribe['CNT']))
		{
			SubscribeTable::delete($data['subscribeId']);
		}
		else
		{
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_UNSUBSCRIBE_ALREADY_UNSUBSCRIBE'), self::ERROR_UNSUBSCRIBE)));
			return false;
		}

		return true;
	}

	/**
	 * The method activates the subscription clearing a field DATE_TO or writing the subscription term.
	 *
	 * @param array $listSubscribeId List subscribe id.
	 * @param int $timePeriod Subscription period in seconds.
	 * @return bool
	 * @throws \Exception
	 */
	public function activateSubscription(array $listSubscribeId, $timePeriod = 0)
	{
		if($timePeriod)
		{
			$fields = array('DATE_TO' => DateTime::createFromTimestamp(time() + intval($timePeriod)));
		}
		else
		{
			$fields = array('DATE_TO' => false);
		}

		foreach($listSubscribeId as $subscribeId)
		{
			$result = SubscribeTable::update($subscribeId, $fields);
			if(!$result->isSuccess())
			{
				foreach($result->getErrorMessages() as $errorMessage)
					$this->errorCollection->add(array(new Error($errorMessage, self::ERROR_ACTIVITY_CHANGE)));
				return false;
			}
		}

		return true;
	}

	/**
	 * The method deactivates the subscription by writing the current date.
	 *
	 * @param array $listSubscribeId List subscribe id.
	 * @return bool
	 * @throws \Exception
	 */
	public function deactivateSubscription(array $listSubscribeId)
	{
		foreach($listSubscribeId as $subscribeId)
		{
			$result = SubscribeTable::update($subscribeId, array('DATE_TO' => new DateTime()));
			if(!$result->isSuccess())
			{
				foreach($result->getErrorMessages() as $errorMessage)
					$this->errorCollection->add(array(new Error($errorMessage, self::ERROR_ACTIVITY_CHANGE)));
				return false;
			}
		}

		return true;
	}

	/**
	 * The method checks the subscription activity field value DATE_TO.
	 *
	 * @param mixed $dateTo An empty value or an instance DateTime.
	 * @return bool
	 */
	public function checkSubscriptionActivity($dateTo)
	{
		if($dateTo)
		{
			if($dateTo instanceof DateTime && $dateTo->getTimestamp() > time())
			{
				return true;
			}
			return false;
		}
		else
		{
			return true;
		}
	}

	/**
	 * Write product id to the session to check that the user has subscribed.
	 *
	 * @param integer $itemId Product id.
	 * @return void
	 */
	public function setSessionOfSibscribedProducts($itemId)
	{
		$itemId = intval($itemId);
		if(!empty($_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'])
			&& is_array($_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID']))
		{
			$_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'][$itemId] = true;
		}
		else
		{
			if(empty($_SESSION['SUBSCRIBE_PRODUCT']))
				$_SESSION['SUBSCRIBE_PRODUCT'] = array();

			$_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'] = array();
			$_SESSION['SUBSCRIBE_PRODUCT']['LIST_PRODUCT_ID'][$itemId] = true;
		}
	}

	private function checkDataBeforeSave($productSubscribeData, array $subscribeData)
	{
		if(!$productSubscribeData || !is_array($productSubscribeData))
		{
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_PRODUCT_NOT_FOUND'), self::ERROR_ADD_SUBSCRIBE)));
			return false;
		}
		if(!SubscribeTable::checkPermissionSubscribe($productSubscribeData['SUBSCRIBE']))
		{
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_SUBSCRIBE_DENIED'), self::ERROR_ADD_SUBSCRIBE)));
			return false;
		}
		if(!array_key_exists($subscribeData['CONTACT_TYPE'], $this->contactTypes))
		{
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_CONTACT_TYPE'), self::ERROR_ADD_SUBSCRIBE)));
			return false;
		}
		if($productSubscribeData['USER_CONTACT'] == $subscribeData['USER_CONTACT']
			&& $productSubscribeData['DATE_TO'] == null)
		{
			$this->setSessionOfSibscribedProducts($subscribeData['ITEM_ID']);
			$this->errorCollection->add(array(new Error(
				Loc::getMessage('ERROR_SUBSCRIBE_ALREADY_EXISTS'), self::ERROR_ADD_SUBSCRIBE_ALREADY_EXISTS)));
			return false;
		}
		return true;
	}

	private function validateFields()
	{
		foreach($this->fields as $fieldId => $fieldValue)
		{
			switch($fieldId)
			{
				case 'DATE_TO':
					if(!($fieldValue instanceof DateTime) ||
						($fieldValue instanceof DateTime && $fieldValue->getTimestamp() < time()))
					{
						$this->errorCollection->add(array(new Error(Loc::getMessage('ERROR_VALIDATE_FIELDS',
							array('#FIELD#' => $fieldId)), self::ERROR_VALIDATE_FIELDS)));
					}
					break;
				case 'USER_CONTACT':
					$currentContactType = $this->contactTypes[$this->fields['CONTACT_TYPE']];
					if(!preg_match($currentContactType['RULE'], $fieldValue))
					{
						$this->errorCollection->add(array(new Error(Loc::getMessage('ERROR_VALIDATE_FIELDS',
							array('#FIELD#' => $fieldId)), self::ERROR_VALIDATE_FIELDS)));
					}
					break;
			}
		}
	}

	private function checkRequiredInputParams(array $inputParams, array $requiredParams)
	{
		foreach ($requiredParams as $param)
		{
			if(!isset($inputParams[$param]) || (!$inputParams[$param] &&
				!(is_string($inputParams[$param]) && strlen($inputParams[$param]))))
			{
				$this->errorCollection->add(array(new Error(Loc::getMessage('ERROR_REQUIRED_PARAMATERS',
					array('#PARAM#' => $param)), self::ERROR_REQUIRED_PARAMATERS)));
				return false;
			}
		}
		return true;
	}
}