Your IP : 18.190.239.5


Current Path : /var/www/axolotl/data/www/axolotl.ru/www/bitrix/components/yandexpay.pay/purchase.rest/
Upload File :
Current File : /var/www/axolotl/data/www/axolotl.ru/www/bitrix/components/yandexpay.pay/purchase.rest/class.php

<?php

namespace YandexPay\Pay\Components;

use Bitrix\Main;
use Bitrix\Main\Localization\Loc;
use YandexPay\Pay\Logger;
use YandexPay\Pay\Psr;
use YandexPay\Pay\Trading\Action as TradingAction;

if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) { die(); }

Loc::loadMessages(__FILE__);

class PurchaseRest extends \CBitrixComponent
{
	private const HTTP_STATUS_400 = '400 Bad Request';
	private const HTTP_STATUS_403 = '403 Forbidden';
	private const HTTP_STATUS_404 = '404 Not Found';
	private const HTTP_STATUS_500 = '500 Internal server error';

	/** @var Psr\Log\LoggerInterface $logger */
	protected $logger;

	public function executeComponent()
	{
		try
		{
			$this->loadModules();
			$this->parseUrl();

			$path = $this->getActionPath();

			$this->bootLogger($path);

			$action = $this->resolveAction($path);
			$action->setLogger($this->logger);

			$action->passHttp($this->request);
			$action->bootstrap();

			$this->logRequest($this->request);

			$response = $action->process();

			$this->logResponse($response);
			$this->sendResponse($response);
		}
		catch (TradingAction\Rest\Exceptions\ActionNotImplemented $exception)
		{
			$response = $this->makeExceptionResponse($exception, static::HTTP_STATUS_404, [
				'reasonCode' => 'NOT_FOUND',
				'reason' => 'Action not found',
			]);

			$this->logResponse($response);
			$this->sendResponse($response);
		}
		catch (TradingAction\Rest\Exceptions\RequestAuthentication $exception)
		{
			$response = $this->makeExceptionResponse($exception, static::HTTP_STATUS_403, [
				'reasonCode' => 'FORBIDDEN',
			]);

			$this->logResponse($response, Psr\Log\LogLevel::CRITICAL);
			$this->sendResponse($response);
		}
		catch (TradingAction\Reference\Exceptions\DtoProperty $exception)
		{
			$response = $this->makeExceptionResponse($exception, static::HTTP_STATUS_400, [
				'reasonCode' => $exception->getParameter() ?: 'OTHER'
			]);

			$this->logResponse($response, Psr\Log\LogLevel::ERROR);
			$this->sendResponse($response);
		}
		catch (TradingAction\Reference\Exceptions\NotLog $exception)
		{
			$response = $this->makeExceptionResponse($exception, static::HTTP_STATUS_400);
			$this->sendResponse($response);
		}
		catch (\Throwable $exception)
		{
			$response = $this->makeExceptionResponse($exception, static::HTTP_STATUS_500);

			$this->logResponse($response, Psr\Log\LogLevel::ERROR);
			$this->sendResponse($response);
		}
	}

	protected function loadModules() : void
	{
		$moduleName = 'yandexpay.pay';

		if (!Main\Loader::includeModule($moduleName))
		{
			$message = $this->getLang('MODULE_NOT_INSTALLED', [ '#MODULE_ID#' => $moduleName ]);

			throw new Main\SystemException($message);
		}
	}

	protected function bootLogger(string $path) : void
	{
		$this->logger = new Logger\Logger();
		$this->logger->setUrl($path);
	}

	protected function parseUrl() : void
	{
		$url = $this->request->getRequestedPage();
		$url = $this->normalizeDirectory($url);
		[$left] = $this->sliceUrlSefFolder($url);
		[$left, $setupId] = $this->sliceUrlSetupId($left);

		$parameters = [
			'ACTION' => ltrim($left),
		];
		$parameters += array_filter([
			'SETUP_ID' => $setupId,
		]);

		$this->presetParameters($parameters);
	}

	protected function sliceUrlSefFolder(string $url) : array
	{
		$folder = $this->requireParameter('SEF_FOLDER');
		$folder = $this->normalizeDirectory($folder);

		if (mb_stripos($url, $folder) !== 0)
		{
			throw new Main\SystemException($this->getLang('REQUEST_OUTSIDE_SEF_FOLDER'));
		}

		$leftUrl = mb_substr($url, mb_strlen($folder));

		return [$leftUrl, $folder];
	}

	protected function sliceUrlSetupId(string $url) : array
	{
		if (!preg_match('#^/p(\d+)(/.*$|$)#', $url, $matches)) { return [$url, null]; }

		return [$matches[2], (int)$matches[1]];
	}

	protected function normalizeDirectory(string $path) : string
	{
		$result = Main\IO\Path::normalize($path);
		$result = preg_replace('#/index\.php$#', '', $result);

		if ($result !== '/')
		{
			$result = rtrim($result, '/');
		}

		return $result;
	}

	protected function resolveAction(string $path) : TradingAction\Rest\Reference\HttpAction
	{
		$router = new TradingAction\Rest\Router();

		return $router->getAction($path);
	}

	protected function getActionPath() : string
	{
		$action = (string)$this->requireParameter('ACTION');
		$action = ltrim($action, '/');

		if ($action === '')
		{
			$action = 'root';
		}

		return $action;
	}

	protected function makeExceptionResponse(\Throwable $exception, $status, array $overrides = []) : Main\Engine\Response\Json
	{
		$response = new Main\Engine\Response\Json($overrides + [
			'status' => 'fail',
			'reasonCode' => (string)($exception->getCode() ?: 'OTHER'),
			'reason' => $exception->getMessage(),
			'trace' => $exception->getTraceAsString(), // todo remove
		]);
		$response->setStatus($status);

		return $response;
	}

	protected function logRequest(Main\HttpRequest $request) : void
	{
 		if ($this->logger === null) { return; }

		$this->logger->debug(...(new Logger\Formatter\HttpRequest($request))->forLogger());
	}

	protected function logResponse(Main\HttpResponse $response, string $level = Psr\Log\LogLevel::DEBUG) : void
	{
 		if ($this->logger === null) { return; }

		$this->logger->log($level, ...(new Logger\Formatter\HttpResponse($response))->forLogger());
	}

	protected function sendResponse(Main\HttpResponse $response) : void
	{
		global $APPLICATION;

		/** @var Main\Application $app */
		$app = Main\Application::getInstance();

		$APPLICATION->RestartBuffer();
		$app->end(0, $response);
	}

	protected function getLang(string $code, $replace = null, $language = null): string
	{
		return Main\Localization\Loc::getMessage('YANDEX_PAY_PURCHASE_REST_' . $code, $replace, $language);
	}

	protected function getParameter(string $name)
	{
		return $this->arParams[$name] ?? null;
	}

	protected function requireParameter(string $name)
	{
		if (!isset($this->arParams[$name]))
		{
			$message = $this->getLang('PARAMETER_REQUIRED', [ '#NAME#' => $name ]);
			throw new Main\SystemException($message);
		}

		return $this->arParams[$name];
	}

	protected function presetParameters(array $values) : void
	{
		foreach ($values as $name => $value)
		{
			if (isset($this->arParams[$name])) { continue; }

			$this->arParams[$name] = $value;
		}
	}
}