403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sale/lib/compatible/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sale/lib/compatible/compatible.php
<?php

namespace Bitrix\Sale\Compatible;

use Bitrix\Main\Application;
use Bitrix\Main\DB;
use	Bitrix\Main\Entity,
	Bitrix\Main\Entity\Query,
	Bitrix\Main\Entity\Field,
	Bitrix\Main\Entity\ReferenceField,
	Bitrix\Main\Entity\ExpressionField,
	Bitrix\Main\SystemException;

use Bitrix\Sale\Compatible;

class AliasedQuery extends Query
{
	private $aliases = array();

	public function __construct($source)
	{
		parent::__construct($source);

		$aliases = &$this->aliases;

		/** @var Field $field */
		foreach ($this->getEntity()->getFields() as $field)
		{
			if (! $field instanceof ReferenceField)
			{
				$name = $field->getName();
				$aliases[$name] = $name;
			}
		}
	}

	public function getAliases()
	{
		return $this->aliases;
	}

	public function addAliases(array $aliases)
	{
		foreach ($aliases as $alias => $field)
		{
			$this->addAlias($alias, $field);
		}

		return $this;
	}

	public function addAlias($alias, $field = null)
	{
		if (($this->aliases[$alias] ?? false))
		{
			throw new SystemException("'$alias' already added", 0, __FILE__, __LINE__);
		}
		elseif (! $field)
		{
			$this->aliases[$alias] = $alias;
		}
		elseif (is_string($field) || (is_array($field) && $field['expression'])) // TODO Field support
		{
			$this->aliases[$alias] = $field;
		}
		else
		{
			throw new SystemException("invalid '$alias' type", 0, __FILE__, __LINE__);
		}

		return $this;
	}

	public function getAliasName($alias)
	{
		if (!isset($this->aliases[$alias]))
		{
			return null;
		}

		$field = $this->aliases[$alias];

		if (is_string($field))
		{
			return $field; // name
		}
		elseif (is_array($field)) // TODO Field support
		{
			$name = '__'.$alias.'_ALIAS__';
			$field['registered'] ??= false;
			if (!$field['registered'])
			{
				$field['registered'] = true;
				$this->registerRuntimeField($name, $field);
			}

			return $name;
		}

		throw new SystemException("invalid alias '$alias' type", 0, __FILE__, __LINE__);
	}

	public function addAliasSelect($alias)
	{
		return ($name = $this->getAliasName($alias))
			? $this->addSelect($name, $alias)
			: $this;
	}

	public function addAliasGroup($alias)
	{
		return ($name = $this->getAliasName($alias))
			? $this->addGroup($name)
			: $this;
	}

	public function addAliasOrder($alias, $order)
	{
		return ($name = $this->getAliasName($alias))
			? $this->addOrder($name, $order)
			: $this;
	}

	public function addAliasFilter($key, $value)
	{
		preg_match('/^([!%@<=>]{0,3})(.*)$/', $key, $matches);

		return ($name = $this->getAliasName($matches[2]))
			? $this->addFilter($matches[1].$name, $value)
			: $this;

		// TODO recursive filters maybe?
//		if (is_null($key) && is_array($value))
//		{
//			return ($filter = self::getAliasFilterRecursive($value))
//				? $this->addFilter(null, $filter)
//				: $this;
//		}
//		else
//		{
//			preg_match('/^([!%@<=>]{0,3})(.*)$/', $key, $matches);
//
//			$alias = $matches[2];
//
//			if (! ($name = $this->getAliasName($alias)))
//			{
//				if ($this->getEntity()->hasField($alias))
//					$name = $alias;
//				else
//					return $this;
//			}
//
//			$key = $matches[1].$name;
//			return parent::addFilter($key, $value);
//		}
	}

//	private function getAliasFilterRecursive(array $filter)
//	{
//		$resolved = array();
//
//		foreach ($filter as $key => $value)
//		{
//			if ($key === 'LOGIC')
//			{
//				$resolved['LOGIC'] = $value;
//			}
//			elseif (is_array($value))
//			{
//				$resolved []= self::getAliasFilterRecursive($value);
//			}
//			else
//			{
//				preg_match('/^([!%@<=>]{0,3})(.*)$/', $key, $matches);
//
//				$alias = $matches[2];
//
//				if (! ($name = $this->getAliasName($alias)))
//				{
//					if ($this->getEntity()->hasField($alias))
//						$name = $alias;
//					else
//						continue;
//				}
//
//				$key = $matches[1].$name;
//				$resolved[$key] = $value;
//			}
//		}
//
//		return $resolved;
//	}
}

final class CDBResult extends \CDBResult
{
	function compatibleNavQuery(Query $query, array $arNavStartParams) //, $bIgnoreErrors = false)
	{
		$cnt = $query->exec()->getSelectedRowsCount(); // TODO check groups

		global $DB;

		if(isset($arNavStartParams["SubstitutionFunction"]))
		{
			$arNavStartParams["SubstitutionFunction"]($this, $query->getLastQuery(), $cnt, $arNavStartParams);
			return null;
		}

		if(isset($arNavStartParams["bDescPageNumbering"]))
			$bDescPageNumbering = $arNavStartParams["bDescPageNumbering"];
		else
			$bDescPageNumbering = false;

		$this->InitNavStartVars($arNavStartParams);
		$this->NavRecordCount = $cnt;

		if($this->NavShowAll)
			$this->NavPageSize = $this->NavRecordCount;

		//calculate total pages depend on rows count. start with 1
		$this->NavPageCount = ($this->NavPageSize>0 ? floor($this->NavRecordCount/$this->NavPageSize) : 0);
		if($bDescPageNumbering)
		{
			$makeweight = 0;
			if($this->NavPageSize > 0)
				$makeweight = ($this->NavRecordCount % $this->NavPageSize);
			if($this->NavPageCount == 0 && $makeweight > 0)
				$this->NavPageCount = 1;

			//page number to display
			$this->calculatePageNumber($this->NavPageCount);

			//rows to skip
			$NavFirstRecordShow = 0;
			if($this->NavPageNomer != $this->NavPageCount)
				$NavFirstRecordShow += $makeweight;

			$NavFirstRecordShow += ($this->NavPageCount - $this->NavPageNomer) * $this->NavPageSize;
			$NavLastRecordShow = $makeweight + ($this->NavPageCount - $this->NavPageNomer + 1) * $this->NavPageSize;
		}
		else
		{
			if($this->NavPageSize > 0 && ($this->NavRecordCount % $this->NavPageSize > 0))
				$this->NavPageCount++;

			//calculate total pages depend on rows count. start with 1
			$this->calculatePageNumber(1, true, (bool)($arNavStartParams["checkOutOfRange"] ?? false));
			if ($this->NavPageNomer === null)
			{
				return null;
			}

			//rows to skip
			$NavFirstRecordShow = $this->NavPageSize*($this->NavPageNomer-1);
			$NavLastRecordShow = $this->NavPageSize*$this->NavPageNomer;
		}

		$NavAdditionalRecords = 0;
		if(is_set($arNavStartParams, "iNavAddRecords"))
			$NavAdditionalRecords = $arNavStartParams["iNavAddRecords"];

		if(!$this->NavShowAll)
		{
			$query->setOffset($NavFirstRecordShow);
			$query->setLimit($NavLastRecordShow - $NavFirstRecordShow + $NavAdditionalRecords);
		}

		$res_tmp = $query->exec(); //, $bIgnoreErrors);

//		// Return false on sql errors (if $bIgnoreErrors == true)
//		if ($bIgnoreErrors && ($res_tmp === false))
//			return false;

//		$this->result = $res_tmp->result;
		$this->DB = $DB;

		if($this->SqlTraceIndex)
			$start_time = microtime(true);

		$temp_arrray = array();
		$temp_arrray_add = array();
		$tmp_cnt = 0;

		while($ar = $res_tmp->fetch())
		{
			$tmp_cnt++;
			if (intval($NavLastRecordShow - $NavFirstRecordShow) > 0 && $tmp_cnt > ($NavLastRecordShow - $NavFirstRecordShow))
				$temp_arrray_add[] = $ar;
			else
				$temp_arrray[] = $ar;
		}

		if($this->SqlTraceIndex)
		{
			/** @noinspection PhpUndefinedVariableInspection */
			$exec_time = round(microtime(true) - $start_time, 10);
			$DB->addDebugTime($this->SqlTraceIndex, $exec_time);
			$DB->timeQuery += $exec_time;
		}

		$this->arResult = (!empty($temp_arrray)? $temp_arrray : false);
		$this->arResultAdd = (!empty($temp_arrray_add)? $temp_arrray_add : false);
		$this->nSelectedCount = $cnt;
		$this->bDescPageNumbering = $bDescPageNumbering;
		$this->bFromLimited = true;

		return null;
	}

	// FetchAdapter

	private $fetchAdapters = array();

	public function addFetchAdapter(FetchAdapter $adapter)
	{
		$this->fetchAdapters[] = $adapter;
	}

	function Fetch()
	{
		if ($row = parent::Fetch())
			foreach ($this->fetchAdapters as $adapter)
				$row = $adapter->adapt($row);

		return $row;
	}
}

interface FetchAdapter
{
	public function adapt(array $row);
}

class AggregateAdapter implements FetchAdapter
{
	private $aggregated = array();

	function __construct(array $aggregated)
	{
		$this->aggregated = $aggregated;
	}

	public function adapt(array $row)
	{
		foreach ($this->aggregated as $alias => $name)
		{
			$row[$name] = $row[$alias];
			unset ($row[$alias]);
		}

		return $row;
	}
}

class OrderQuery extends AliasedQuery
{
	private $counted, $grouped, $allSelected, $aggregated = array();

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

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

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

	public function aggregated()
	{
		return $this->aggregated ? true : false;
	}

	private function addAggregatedSelect($alias, $aggregate, $name = null)
	{
		$aggregateAlias = '__'.$aggregate.'_'.$alias.'_ALIAS__';
		$this->aggregated[$aggregateAlias] = $alias;

		return $this->addSelect(
			$name
				? new ExpressionField($aggregateAlias, $aggregate.'(%s)', $name)
				: new ExpressionField($aggregateAlias, $aggregate)
		);
	}

	public static function explodeFilterKey($key)
	{
		preg_match('/^([!+*]{0,1})([<=>@%~?]{0,2})(.*)$/', $key, $matches);

		return array(
			'modifier' => $matches[1], // can be ""
			'operator' => $matches[2], // can be ""
			'alias'    => $matches[3], // can be ""
		);
	}

	public function compatibleAddFilter($key, $value)
	{
		$keyMatch = static::explodeFilterKey($key);
		$modifier = $keyMatch['modifier'];
		$operator = $keyMatch['operator'];
		$alias    = $keyMatch['alias'   ];

		if (! $name = $this->getAliasName($alias))
			return $this;

		switch ($operator)
		{
			case  '':
			case '@': $operator = ($modifier === '*' ? '' : '=');
				break;

			case '~': $operator =  '';
				break;
			// default: with no changes
		}

		switch ($modifier)
		{
			case '*':
			case '' : return $this->addFilter($modifier.$operator.$name, $value);

			case '!': return $operator == '=' && $value
				? $this->addFilter(null, array('LOGIC' => 'OR', array('!='.$name => $value), array('='.$name => '')))
				: $this->addFilter($modifier.$operator.$name, $value);

			case '+': return $this->addFilter(null, array('LOGIC' => 'OR', array($operator.$name => $value), array('='.$name => '')));

			default : throw new SystemException("invalid modifier '$modifier'", 0, __FILE__, __LINE__);
		}
	}

	protected function mapLocationRuntimeField($field, $asFilter = false)
	{
		return $field;
	}

	public function prepare(array $order, array $filter, $group, array $select)
	{
		// Do not remove!!!
//		file_put_contents('/var/www/log'
//			, spl_object_hash($this)."\n"
//			. 'Order: '.print_r($order,true)
//			. 'Filter: '.print_r($filter,true)
//			. 'Group: '.print_r($group,true)
//			. 'Select: '.print_r($select,true)
//			."\n\n\n"
//			, FILE_APPEND);

		static $aggregates = array('COUNT'=>1, 'AVG'=>1, 'MIN'=>1, 'MAX'=>1, 'SUM'=>1);

		foreach ($filter as $key => $value)
		{
			$key = $this->mapLocationRuntimeField($key, true);

			$this->compatibleAddFilter($key, $value);
		}

		if (is_array($group))
		{
			if (empty($group))
			{
				$this->counted = true;
				return;
			}
			else
			{
				foreach ($group as $key => $alias)
				{
					if ($name = $this->getAliasName($alias))
					{
						if (is_string($key) && ($aggregate = mb_strtoupper($key)) && $aggregates[$aggregate])
						{
							$this->addAggregatedSelect($alias, $aggregate, $name);
						}
						else
						{
							$this->grouped = true;
							$this->addGroup($name);
							$this->addSelect($name, $alias);
						}
					}
				}

				if ($this->grouped)
				{
					$this->addAggregatedSelect('CNT', 'COUNT(*)');
					// TODO Maybe? "COUNT(%%_DISTINCT_%% ".$arFields[$arFieldsKeys[0]]["FIELD"].") as CNT ";
				}
			}
		}
		else
		{
			if (empty($select) || $select == array('*'))
			{
				$this->allSelected = true;

				foreach ($this->getAliases() as $alias => $field)
				{
					$field = $this->mapLocationRuntimeField($field);

					$this->addAliasSelect($alias);
				}
			}
			else
			{
				foreach ($select as $key => $alias)
				{
					$alias = $this->mapLocationRuntimeField($alias);

					if ($name = $this->getAliasName($alias))
					{
						if (is_string($key) && ($aggregate = mb_strtoupper($key)) && $aggregates[$aggregate])
						{
							$this->addAggregatedSelect($alias, $aggregate, $name);
						}
						else
						{
							$this->addSelect($name, $alias);
						}
					}
				}
			}
		}

		foreach ($order as $alias => $value)
		{
			$alias = $this->mapLocationRuntimeField($alias);

			$this->addAliasOrder($alias, $value);
		}
	}

	public function getSelectNamesAssoc()
	{
		$names = array();

		foreach ($this->getSelect() as $k => $v)
		{
			if (is_numeric($k))
			{
				if ($v instanceof Field)
					$names[$v->getName()] = true;
				else
					throw new SystemException("invalid", 0, __FILE__, __LINE__);
			}
			else
			{
				$names[$k] = true;
			}
		}

		return $names;
	}

	protected function prepareCompatibleRows(array $rows)
	{
		return $rows;
	}

	public function compatibleExec(CDBResult $result, $navStart)
	{
		if ($this->aggregated)
		{
			$result->addFetchAdapter(new AggregateAdapter($this->aggregated));
		}

		if (!empty($navStart) && is_array($navStart))
		{
			if (!empty($navStart['nTopCount']))
			{
				$this->setLimit($navStart['nTopCount']);
			}
			else
			{
				$result->compatibleNavQuery($this, $navStart);
				return $result;
			}
		}

		$rows = $this->exec()->fetchAll();
		$rows = $this->prepareCompatibleRows($rows);
		$result->InitFromArray($rows);

		return $result;
	}
}

class OrderPropertyValuesQuery extends OrderQuery
{
	/**
	 * @param array $rows
	 * @return array
	 */
	protected function prepareCompatibleRows(array $rows)
	{
		$locationIds = [];
		foreach ($rows as $key => $row)
		{
			if ($row['TYPE'] === 'LOCATION' && !empty($row['VALUE']))
			{
				if (is_array($row['VALUE']))
				{
					$locationIds = array_merge($locationIds, $row['VALUE']);
				}
				else
				{
					$locationIds[] = $row['VALUE'];
				}
			}
		}

		if (!empty($locationIds))
		{
			$locationMap = [];
			$locationRaw = \Bitrix\Sale\Location\LocationTable::getList([
				'filter' => ['=CODE' => $locationIds],
				'select' => ['ID', 'CODE']
			]);
			while ($location = $locationRaw->fetch())
			{
				$locationMap[$location['CODE']] = $location['ID'];
			}
		}

		foreach ($rows as &$row)
		{
			if (isset($row['VALUE']))
			{
				if ($row['TYPE'] === 'LOCATION' && !empty($row['VALUE']))
				{
					if (is_array($row['VALUE']))
					{
						foreach ($row['VALUE'] as &$valueItem)
						{
							$valueItem = $locationMap[$valueItem];
						}
					}
					else
					{
						$row['VALUE'] = $locationMap[$row['VALUE']];
					}
				}

				$row['PROXY_VALUE'] = $row['VALUE'];
				if (is_array($row['VALUE']))
				{
					$row['PROXY_VALUE'] = serialize($row['VALUE']);
				}
				unset($row['VALUE']);
			}
		}

		return $rows;
	}
}

class OrderQueryLocation extends OrderQuery
{
	protected $locationFieldMap = array();

	public function addLocationRuntimeField($fieldName, $ref = false)
	{
		if((string) $fieldName == '')
			return false;


		$this->registerRuntimeField(
			'LOCATION',
			array(
				'data_type' => '\Bitrix\Sale\Location\LocationTable',
				'reference' => array(
					'=this.'.$fieldName => 'ref.CODE'
				),
				'join_type' => 'left'
			)
		);

		$fieldType = "CHAR";
		/** @var DB\Connection $connection */
		$connection = Application::getConnection();
		if ($connection instanceof DB\MssqlConnection)
		{
			$fieldType = "VARCHAR";
		}
		elseif($connection instanceof DB\OracleConnection)
		{
			$fieldType = "VARCHAR2";
		}

		$this->registerRuntimeField(
			'PROXY_'.$fieldName.'_LINK',
			array(
				'data_type' => 'string',
				'expression' => array(
					"CASE WHEN %s = 'LOCATION' THEN CAST(%s AS ".$fieldType."(500)) ELSE %s END",
					($ref !== false ? $ref.'.' : '').'TYPE',
					'LOCATION.ID',
					$fieldName
				)
			)
		);

		$this->addAliases(array(
			$fieldName.'_ORIG'   => $fieldName,
			'PROXY_'.$fieldName  => 'PROXY_'.$fieldName.'_LINK'
		));

		$this->locationFieldMap[$fieldName] = true;
	}

	protected function mapLocationRuntimeField($field, $asFilter = false)
	{
		if($asFilter)
		{
			$parsed = static::explodeFilterKey($field);

			if (isset($this->locationFieldMap[$parsed['alias']]))
			{
				return $parsed['modifier'].$parsed['operator'].'PROXY_'.$parsed['alias'];
			}
			else
			{
				return $field;
			}
		}
		else
		{
			if (isset($this->locationFieldMap[$field]))
			{
				return 'PROXY_'.$field;
			}
			else
			{
				return $field;
			}
		}
	}
}

final class Test
{
	static function assertLastQuery($name, $query)
	{
		$lastQuery = Query::getLastQuery();
		return $query == $lastQuery ? "ok\n" : "\n$name - Assert Last Query Failed!\nExpected:\n($query)\nGiven:\n($lastQuery)\n\n";
	}

	static function run()
	{
		foreach (glob($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/sale/lib/compatible/tests/*.test.php') as $filename)
		{
			include $filename;
		}
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit