Your IP : 3.135.220.239


Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/engine/
Upload File :
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/modules/main/lib/engine/configurator.php

<?php

namespace Bitrix\Main\Engine;

use Bitrix\Main\Annotations\AnnotationReader;
use Bitrix\Main\Engine\Contract\Controllerable;
use Bitrix\Main\Event;
use Bitrix\Main\EventResult;
use Bitrix\Main\SystemException;

final class Configurator
{
	const EVENT_ON_BUILD_ACTIONS = 'onBuildActions';

	const MODE_ANNOTATIONS = 0x0001;

	protected $mode = 0;

	/**
	 * Configurator constructor.
	 */
	public function __construct()
	{
	}

	public function getConfigurationByAnnotations(array $annotations)
	{
		$configuration = null;
		if (empty($annotations))
		{
			return $configuration;
		}

		if (isset($annotations['Action']) || array_key_exists('Action', $annotations))
		{
			$configuration = array(
				'prefilters' => array(),
				'postfilters' => array(),
			);

			if (isset($annotations['Action']['method']))
			{
				if (!is_array($annotations['Action']['method']))
				{
					$annotations['Action']['method'] = array($annotations['Action']['method']);
				}

				$configuration['prefilters'][] = new ActionFilter\HttpMethod($annotations['Action']['method']);
			}

			if (isset($annotations['Action']['csrf']) && is_bool($annotations['Action']['csrf']))
			{
				$configuration['prefilters'][] = new ActionFilter\Csrf($annotations['Action']['csrf']);
			}

			if (!$configuration && !isset($configuration['postfilters']))
			{
				$configuration['postfilters'] = array();
			}
		}

		return $configuration;
	}

	public function getConfigurationByController(Controller $controller)
	{
		$newConfiguration = $this->onBuildConfigurationOfActions($controller);
		$configuration = $controller->configureActions() ? : array();

		if ($this->mode & self::MODE_ANNOTATIONS)
		{
			$annotationReader = new AnnotationReader();

			$lengthSuffix = mb_strlen(Controllerable::METHOD_ACTION_SUFFIX);
			$reflectionClass = new \ReflectionClass($controller);
			foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method)
			{
				if (!$method->isPublic())
				{
					continue;
				}

				$probablySuffix = mb_substr($method->getName(), -$lengthSuffix);
				if ($probablySuffix !== Controllerable::METHOD_ACTION_SUFFIX)
				{
					continue;
				}

				$actionName = mb_substr($method, 0, -$lengthSuffix);
				if ($this->isExists($configuration, $actionName))
				{
					//we have already config and don't have to grab annotations
					continue;
				}

				$annotations = $annotationReader->getMethodAnnotations($method);
				if (!$this->checkReflectionMethodAsAction($method, $annotations))
				{
					continue;
				}

				$configuration[$actionName] = $this->getConfigurationByAnnotations($annotations);
			}
		}

		$configuration = array_merge($newConfiguration, $configuration);
		$configuration = $this->wrapClosure($configuration);

		$this->checkConfigurations($configuration);

		return $configuration;
	}

	private function isExists(array $configuration, $actionName)
	{
		$listOfActions = array_change_key_case($configuration, CASE_LOWER);
		$actionName = mb_strtolower($actionName);

		return isset($listOfActions[$actionName]);
	}

	private function checkReflectionMethodAsAction(\ReflectionMethod $reflectionMethod, array $annotations = null)
	{
		if (!$reflectionMethod->isPublic())
		{
			return false;
		}

		if ($annotations === null)
		{
			$annotationReader = new AnnotationReader();
			$annotations = $annotationReader->getMethodAnnotations($reflectionMethod);
		}

		if (!is_array($annotations) || !array_key_exists('Action', $annotations))
		{
			return false;
		}

		return true;
	}

	private function onBuildConfigurationOfActions(Controller $controller)
	{
		//todo set name of the controller in event name? or use filter?
		$event = new Event(
			'main',
			static::EVENT_ON_BUILD_ACTIONS,
			array(
				'controller' => $controller,
			)
		);
		$event->send($this);

		$newConfiguration = array();
		foreach ($event->getResults() as $eventResult)
		{
			if ($eventResult->getType() != EventResult::SUCCESS)
			{
				continue;
			}

			$parameters = $eventResult->getParameters();
			if (isset($parameters['extraActions']) && is_array($parameters['extraActions']))
			{
				//configuration in $this->configureActions() has more priority then configuration which was provided by event
				$newConfiguration = array_merge($newConfiguration, $parameters['extraActions']);
			}
		}

		return $newConfiguration;
	}

	public function wrapFiltersClosure(array $filters)
	{
		foreach ($filters as $i => $filter)
		{
			if (!($filter instanceof \Closure))
			{
				continue;
			}

			$filters[$i] = new ActionFilter\ClosureWrapper($filter);
		}

		return $filters;
	}

	private function wrapClosure(array $configurations)
	{
		foreach ($configurations as $actionName => $configuration)
		{
			if (!empty($configuration['prefilters']))
			{
				$configurations[$actionName]['prefilters'] = $this->wrapFiltersClosure($configuration['prefilters']);
			}

			if (!empty($configuration['+prefilters']))
			{
				$configurations[$actionName]['+prefilters'] = $this->wrapFiltersClosure($configuration['+prefilters']);
			}

			if (!empty($configuration['postfilters']))
			{
				$configurations[$actionName]['postfilters'] = $this->wrapFiltersClosure($configuration['postfilters']);
			}

			if (!empty($configuration['+postfilters']))
			{
				$configurations[$actionName]['+postfilters'] = $this->wrapFiltersClosure($configuration['+postfilters']);
			}
		}

		return $configurations;
	}

	private function checkConfigurations(array $configurations)
	{
		foreach ($configurations as $actionName => $configuration)
		{
			if (!is_string($actionName))
			{
				throw new SystemException('Invalid configuration of actions. Action has to be string');
			}

			if (!is_array($configuration))
			{
				throw new SystemException('Invalid configuration of actions. Configuration has to be array');
			}

			if (!empty($configuration['prefilters']))
			{
				$this->checkFilters($configuration['prefilters']);
			}

			if (!empty($configuration['postfilters']))
			{
				$this->checkFilters($configuration['postfilters']);
			}
		}
	}

	private function checkFilters(array $filters)
	{
		foreach ($filters as $filter)
		{
			if (!($filter instanceof ActionFilter\Base))
			{
				throw new SystemException('Filter has to be subclass of ' . ActionFilter\Base::className());
			}
		}
	}

}