Your IP : 3.148.210.23


Current Path : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/disk/lib/internals/
Upload File :
Current File : /var/www/axolotl/data/www/yar.axolotls.ru/bitrix/modules/disk/lib/internals/basecomponent.php

<?php

namespace Bitrix\Disk\Internals;

use Bitrix\Disk\Driver;
use Bitrix\Disk\Internals\Engine\Contract\SidePanelWrappable;
use Bitrix\Disk\Internals\Error\Error;
use Bitrix\Disk\Internals\Error\ErrorCollection;
use Bitrix\Disk\UrlManager;
use Bitrix\Main\Errorable;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Web\Json;
use Bitrix\Main\Config;
use Exception;

Loc::loadMessages(__FILE__);

abstract class BaseComponent extends \CBitrixComponent implements Errorable
{
	const ERROR_REQUIRED_PARAMETER = 'DISK_BASE_COMPONENT_22001';

	const STATUS_SUCCESS = 'success';
	const STATUS_DENIED  = 'denied';
	const STATUS_ERROR   = 'error';

	/** @var  string */
	protected $actionPrefix = 'action';
	/** @var  string */
	protected $action;
	/** @var  array */
	protected $actionDescription;
	/** @var  string */
	protected $realActionName;
	/** @var  ErrorCollection */
	protected $errorCollection;
	/** @var \CAllMain|\CMain */
	protected $application;
	protected $componentId = '';
	protected static $alreadyWrappedForSidepanel = false;

	public function __construct($component = null)
	{
		parent::__construct($component);
		if(!$this->componentId)
		{
			$this->componentId = $this->isAjaxRequest()? randString(7) : $this->randString();
		}

		$this->errorCollection = new ErrorCollection();

		global $APPLICATION;
		$this->application = $APPLICATION;
	}

	final protected function restartBuffer()
	{
		global $APPLICATION;
		$APPLICATION->restartBuffer();
	}

	protected function sendResponse($response)
	{
		$this->restartBuffer();

		echo $response;

		$this->end();
	}

	protected function sendJsonResponse($response)
	{
		$this->restartBuffer();

		header('Content-Type:application/json; charset=UTF-8');
		echo Json::encode($response);

		$this->end();
	}

	protected function sendJsonErrorResponse()
	{
		$errors = array();
		foreach($this->getErrors() as $error)
		{
			/** @var Error $error */
			$errors[] = array(
				'message' => $error->getMessage(),
				'code' => $error->getCode(),
			);
		}
		unset($error);
		$this->sendJsonResponse(array(
			'status' => self::STATUS_ERROR,
			'errors' => $errors,
		));
	}

	protected function sendJsonSuccessResponse(array $response = array())
	{
		$response['status'] = self::STATUS_SUCCESS;
		$this->sendJsonResponse($response);
	}

	protected function sendJsonAccessDeniedResponse($message = '')
	{
		$this->sendJsonResponse(array(
			'status' => self::STATUS_DENIED,
			'message' => $message,
		));
	}

	protected function showAccessDenied()
	{
		ShowError(Loc::getMessage('DISK_BASE_COMPONENT_ERROR_ACCESS_DENIED'));

		$this->end(false);
	}

	protected function end($terminate = true)
	{
		Diag::getInstance()->logDebugInfo($this->getName());

		if($terminate)
		{
			/** @noinspection PhpUndefinedClassInspection */
			\CMain::finalActions();
			die;
		}
	}

	public static function encodeUrn($urn)
	{
		return Driver::getInstance()->getUrlManager()->encodeUrn($urn);
	}

	public function hasErrors()
	{
		return $this->errorCollection->hasErrors();
	}

	public function getErrors()
	{
		return $this->errorCollection->toArray();
	}

	public function getErrorByCode($code)
	{
		return $this->errorCollection->getErrorByCode($code);
	}

	public function getComponentId()
	{
		return $this->componentId;
	}

	protected function wrapAsSidepanelContent()
	{
		if (self::$alreadyWrappedForSidepanel)
		{
			return false;
		}

		if (
			$this instanceof SidePanelWrappable &&
			($this->request->get('IFRAME') === 'Y' || $this->request->getPost('IFRAME') === 'Y')
		)
		{
			self::$alreadyWrappedForSidepanel = true;

			global $APPLICATION;
			$APPLICATION->IncludeComponent(
				'bitrix:disk.sidepanel.wrapper',
				"",
				array(
					'POPUP_COMPONENT_NAME' => $this->getName(),
					'POPUP_COMPONENT_TEMPLATE_NAME' => "",
					'POPUP_COMPONENT_PARAMS' => $this->arParams,
				)
			);

			return true;
		}

		return false;
	}

	public function isWrappedAsSidepanelContent()
	{
		return self::$alreadyWrappedForSidepanel;
	}

	public function executeComponent()
	{
		try
		{
			if ($this->wrapAsSidepanelContent())
			{
				return;
			}

			Diag::getInstance()->collectDebugInfo($this->componentId, $this->getName());

			$this->resolveAction();
			$this->checkAction();

			$this->checkRequiredModules();
			$this->prepareParams();

			if($this->processBeforeAction($this->getAction()) !== false)
			{
				$this->runAction();
			}

			Diag::getInstance()->logDebugInfo($this->componentId, $this->getName());
		}
		catch(Exception $e)
		{
			$this->runProcessingExceptionComponent($e);
		}
	}

	/**
	 * @return UrlManager
	 */
	protected function getUrlManager()
	{
		return Driver::getInstance()->getUrlManager()->setComponent($this);
	}

	private function setProcessToDefaultAction()
	{
		//Attention! we must accept GET, POST queries on default action for rendering component.
		//And we must never modify data in default action. It will be error.
		$this->realActionName = 'default';
		$this->setAction($this->realActionName, array(
			'method' => array('GET', 'POST'),
			'name' => 'default',
			'check_csrf_token' => false,
		));
	}

	protected function resolveAction()
	{
		$listOfActions = $this->normalizeListOfAction($this->listActions());

		$this->realActionName = null;
		//todo? action prefix? Url Manager?
		$action = $this->arParams[$this->actionPrefix]?: $this->request->getQuery($this->actionPrefix);
		if($action && is_string($action) && isset($listOfActions[strtolower($action)]))
		{
			$this->realActionName = strtolower($action);
		}

		if(!$this->realActionName || $this->realActionName == 'default')
		{
			$this->setProcessToDefaultAction();
			return $this;
		}

		$description = $listOfActions[$this->realActionName];
		if(!in_array($this->request->getRequestMethod(), $description['method']))
		{
			$this->setProcessToDefaultAction();
		}
		else
		{
			$this->setAction($description['name'], $description);
		}

		return $this;
	}

	//todo refactor BaseComponent + Controller normalizeListOfAction, resolveAction.
	//you can use composition in BaseComponent
	protected function normalizeListOfAction(array $listOfActions)
	{
		$normalized = array();
		foreach($listOfActions as $action => $description)
		{
			if(!is_string($action))
			{
				$normalized[$description] = $this->normalizeActionDescription($description, $description);
			}
			else
			{
				$normalized[$action] = $this->normalizeActionDescription($action, $description);
			}
		}
		unset($action, $description);

		return array_change_key_case($normalized, CASE_LOWER);
	}

	protected function normalizeActionDescription($action, $description)
	{
		if(!is_array($description))
		{
			$description = array(
				'method' => array('GET'),
				'name' => $description,
				'check_csrf_token' => false,
			);
		}
		if(empty($description['name']))
		{
			$description['name'] = $action;
		}

		return $description;
	}

	protected function listActions()
	{
		return array();
	}

	protected function checkRequiredModules()
	{
		return $this;
	}

	protected function prepareParams()
	{
		return $this;
	}

	protected function runAction()
	{
		$binder = new Engine\Binder(
			$this,
			'processAction' . $this->getAction(),
			array($this->request->getPostList(), $this->request->getQueryList())
		);

		return $binder->invoke();
	}

	/**
	 * @return string
	 */
	protected function getAction()
	{
		return $this->action;
	}

	/**
	 * @return array
	 */
	protected function getActionDescription()
	{
		return $this->actionDescription;
	}

	/**
	 * @param string $action
	 * @param array  $description
	 * @return $this
	 */
	protected function setAction($action, array $description)
	{
		$this->action = $action;
		$this->actionDescription = $description;

		return $this;
	}

	abstract protected function processActionDefault();

	/**
	 * @param array $inputParams
	 * @param array $required
	 * @return bool
	 */
	protected function checkRequiredInputParams(array $inputParams, array $required)
	{
		foreach ($required as $item)
		{
			if(!isset($inputParams[$item]) || (!$inputParams[$item] && !(is_string($inputParams[$item]) && strlen($inputParams[$item]))))
			{
				$this->errorCollection->add(array(new Error(Loc::getMessage('DISK_BASE_COMPONENT_ERROR_REQUIRED_PARAMETER', array('#PARAM#' => $item)), self::ERROR_REQUIRED_PARAMETER)));
				return false;
			}
		}

		return true;
	}

	protected function checkRequiredPostParams(array $required)
	{
		$params = array();
		foreach($required as $item)
		{
			$params[$item] = $this->request->getPost($item);
		}
		unset($item);

		return $this->checkRequiredInputParams($params, $required);
	}

	protected function checkRequiredGetParams(array $required)
	{
		$params = array();
		foreach($required as $item)
		{
			$params[$item] = $this->request->getQuery($item);
		}
		unset($item);

		return $this->checkRequiredInputParams($params, $required);
	}

	protected function checkRequiredFilesParams(array $required)
	{
		$params = array();
		foreach($required as $item)
		{
			$params[$item] = $this->request->getFile($item);
		}
		unset($item);

		return $this->checkRequiredInputParams($params, $required);
	}

	/**
	 * Common operations before run action.
	 * @param string $actionName Action name which will be run.
	 * @return bool If method will return false, then action will not execute.
	 */
	protected function processBeforeAction($actionName)
	{
		return true;
	}

	/**
	 * @param Exception $e
	 * @throws \Exception
	 */
	protected function runProcessingExceptionComponent(Exception $e)
	{
		if($this->isAjaxRequest())
		{
			$this->sendJsonResponse(array(
				'status' => static::STATUS_ERROR,
				'message' => $e->getMessage(),
			));
		}
		else
		{
			$exceptionHandling = Config\Configuration::getValue("exception_handling");
			if($exceptionHandling["debug"])
			{
				throw $e;
			}
		}
	}

	/**
	 * Returns whether this is an AJAX (XMLHttpRequest) request.
	 * @return boolean
	 */
	protected function isAjaxRequest()
	{
		return $this->request->isAjaxRequest();
	}

	protected function checkAction()
	{
		if($this->errorCollection->hasErrors())
		{
			$this->sendJsonErrorResponse();
		}
		$description = $this->getActionDescription();

		//if does not exist check_csrf_token we have to check csrf for only POST method.
		if($description['check_csrf_token'] === true || ($this->request->isPost() && !isset($description['check_csrf_token'])))
		{
			if(!check_bitrix_sessid())
			{
				if($this->isAjaxRequest())
				{
					$this->sendJsonAccessDeniedResponse('Wrong csrf token');
				}
				else
				{
					$this->showAccessDenied();
				}
			}
		}
	}

	/**
	 * @internal
	 * @deprecated
	 * @return \CAllMain|\CMain
	 */
	protected function getApplication()
	{
		return $this->application;
	}

	/**
	 * @return array|bool|\CAllUser|\CUser
	 */
	protected function getUser()
	{
		global $USER;
		return $USER;
	}
}