Your IP : 18.191.155.227


Current Path : /home/bitrix/ext_www/rk_shared_core/bitrix/modules/sale/lib/location/admin/
Upload File :
Current File : /home/bitrix/ext_www/rk_shared_core/bitrix/modules/sale/lib/location/admin/helper.php

<?
/**
 * This class is for internal use only, not a part of public API.
 * It can be changed at any time without notification.
 *
 * @access private
 */

namespace Bitrix\Sale\Location\Admin;

use Bitrix\Main;
use Bitrix\Main\Config;
use Bitrix\Main\Localization\Loc;
use Bitrix\Sale\Location;

abstract class Helper
{
	const DEBUG_MODE_OPT = 'location2_debug_mode';

	const IMPORT_PAGE_URL = 'sale_location_import.php';
	const REINDEX_PAGE_URL = 'sale_location_reindex.php';
	const MIGRATION_PAGE_URL = 'sale_location_migration.php';

	const LOCATION_LINK_DATA_CACHE_TAG = 'sale-location-data';

	#####################################
	#### Entity settings
	#####################################

	abstract public function getEntityRoadMap();

	public static function getEntityRoadCode()
	{
		return 'main';
	}

	// this should be overlapped for each ancestor
	public static function getColumns($page)
	{
		// in the middle of extension, should be like this:
		//return array_merge(parent::getColumns(), self::getMap());

		return self::getMap($page);
	}

	// get part of the whole field map for responsibility zone of the current entity
	// call this only with self::
	public static function getMap($page)
	{
		static $flds;

		if($flds == null)
			$flds = static::readMap(self::getEntityRoadCode(), $page);

		return $flds;
	}

	#####################################
	#### CRUD wrappers
	#####################################

	// columns shown in all grids
	public static function getListGridColumns()
	{
		$columns = static::getColumns('list');
		foreach($columns as &$col)
			$col['DEFAULT'] = true;

		return $columns;
	}

	// columns shown in all filters
	public static function getFilterColumns()
	{
		$columns = static::getColumns('list');
		foreach($columns as &$col)
			$col['DEFAULT'] = true;

		return $columns;
	}

	// columns shown in all forms
	public static function getDetailPageRows()
	{
		return static::getColumns('list');
	}

	// generalized filter to orm filter proxy
	public static function getParametersForList($proxed)
	{
		$columns = self::getMap('list'); // columns only for 'main' class

		$parameters = array();

		// filter
		$filter = array();
		if(is_array($proxed['FILTER']) && !empty($proxed['FILTER']))
		{
			foreach($columns as $code => $fld)
			{
				if($fld['data_type'] == 'integer' || $fld['data_type'] == 'float')
				{
					// range or list expected

					if(is_array($proxed['FILTER'][$code]))
					{
						if(strlen($proxed['FILTER'][$code]['FROM']) && strlen($proxed['FILTER'][$code]['TO'])) // range
						{
							$filter['><'.$code] = array($proxed['FILTER'][$code]['FROM'], $proxed['FILTER'][$code]['TO']);
						}
						elseif(strlen($proxed['FILTER'][$code]['FROM'])) // greather than
						{
							$filter['>='.$code] = $proxed['FILTER'][$code]['FROM'];
						}
						elseif(strlen($proxed['FILTER'][$code]['TO'])) // less than
						{
							$filter['<='.$code] = $proxed['FILTER'][$code]['TO'];
						}
					}
					elseif(strlen($proxed['FILTER'][$code]))
						$filter['='.$code] = (string) $proxed['FILTER'][$code];
				}
				else
				{
					if(strlen($proxed['FILTER'][$code]))
						$filter[static::getFilterModifier($fld['data_type']).$code] = $proxed['FILTER'][$code];
				}
			}
		}

		if(!empty($filter))
			$parameters['filter'] = $filter;

		// select
		foreach($columns as $code => $col)
			$parameters['select'][] = $code;

		// order
		if(is_array($proxed['ORDER']) && !empty($proxed['ORDER']))
			$parameters['order'] = $proxed['ORDER'];
		
		// nav (unused)
		if(($page = intval($proxed['NAV']['PAGE_NUM'])) && ($lop = intval($proxed['NAV']['LOP'])))
		{
			$roadMap = static::getEntityRoadMap();
			$road = $roadMap[self::getEntityRoadCode()]['name'];
			$class = $road.'Table';

			$count = $class::getList(array(
				'filter' => is_array($parameters['filter']) ? $parameters['filter'] : array(),
				'select' => array('CNT'),
				'runtime' => array(
					'CNT' => array(
						'data_type' => 'integer',
						'expression' => array(
							'count(%u)',
							'ID'
						)
					)
				)
			))->fetch();

			$bounds = Main\DB\Paginator::calculateQueryLimits($count['CNT'], $page, $lop);
			$parameters['offset'] = $bounds[0];
			$parameters['limit'] = $bounds[1];
		}

		return $parameters;
	}

	/*
	* $parameters: array of keys: FILTER (generalized), ID, OPERATION
	*/
	public static function performGridOperations($parameters)
	{
		$result = array(
			'sucess' => true,
			'errors' => array()
		);

		@set_time_limit(0);

		if(is_array($parameters['ID']) && !empty($parameters['ID']))
		{
			$parameters['ID'] = array_unique($parameters['ID']);
			foreach($parameters['ID'] as $id)
			{
				$res = static::delete($id);
				if(!$res['success'])
				{
					$result['success'] = false;
					$result['errors'] = array_merge($result['errors'], $res['errors']);
				}
			}
		}
		else if(is_array($parameters['FILTER'])) // filter can be empty
		{
			$entityClass = static::getEntityClass();
			$parameters = Helper::getParametersForList($parameters); // from generalized to orm

			$glParams = array('select' => array('ID'));

			if(is_array($parameters['filter']) && !empty($parameters['filter']))
				$glParams['filter'] = $parameters['filter'];

			$resItems = $entityClass::getList($glParams);

			while ($item = $resItems->fetch())
			{

				/* Locations have tree-style structure so
				 * we could have deleted some of them
				 * during previous iterations. Let's check this.
				*/
				if(!$entityClass::getById($item['ID'])->fetch())
					continue;
				/**/

				$res = static::delete($item['ID']);
				if(!$res['success'])
				{
					$result['success'] = false;
					$result['errors'] = array_merge($result['errors'], $res['errors']);
				}
			}
		}

		return $result;
	}

	// get data to display in a form
	public static function getFormData($id)
	{
		$parameters = static::proxyListRequest('detail');
		$parameters['filter']['='.static::getPrimaryFieldName()] = $id;

		$formData = static::getList($parameters)->fetch();

		if(!is_array($formData) || empty($formData))
			throw new Main\SystemException(Loc::getMessage('SALE_LOCATION_E_ITEM_NOT_FOUND'));

		return $formData;
	}

	public static function makeSafeDisplay(&$value, $code)
	{
		$columns = static::getColumns('');

		if(!empty($columns[$code]))
		{
			if(!strlen($value) && strlen($columns[$code]['default']))
				$value = $columns[$code]['default'];

			switch($columns[$code]['data_type'])
			{
				case 'integer':
					$value = intval($value);
					break;
				case 'float':
					$value = floatval($value);
					break;
				default:
					$value = htmlspecialcharsbx($value);
			}
		}
		else
			$value = htmlspecialcharsbx($value);

		return $value;
	}

	##############################################
	##############################################
	##############################################

	public static function validateUpdateRequest($data)
	{
		return array();
	}

	// this function could be much more complicated in the derivative classes
	public static function proxyUpdateRequest($data)
	{
		unset($data['ID']); // drop id if presents

		$proxed = array();
		$columns = static::getColumns('list');

		foreach($columns as $code => $void)
		{
			if(isset($data[$code]))
				$proxed[$code] = $data[$code];
		}

		return $proxed;
	}

	// an adapter from CAdminList + CAdminFilter to ORM getList() logic
	// deprecated: too strong relation with admin grid, replaced with getParametersForList
	public static function proxyListRequest($page)
	{
		global $by;
		global $order;

		$columns = self::getMap($page); // columns only for 'main' class

		$parameters = array('filter' => array());

		foreach($columns as $code => $col)
			$parameters['select'][] = $code;

		$filter = array();
		if(self::checkUseFilter())
		{
			foreach($columns as $code => $fld)
			{
				$from = 'find_'.$code.'_1';
				$to = 'find_'.$code.'_2';

				if($fld['data_type'] == 'integer' && (isset($GLOBALS[$from]) || isset($GLOBALS[$to])))
				{
					// range expected

					if(strlen($GLOBALS[$from]) && strlen($GLOBALS[$to])) // range
					{
						$filter['><'.$code] = array($GLOBALS[$from], $GLOBALS[$to]);
					}
					elseif(strlen($GLOBALS[$from])) // greather than
					{
						$filter['>='.$code] = $GLOBALS[$from];
					}
					elseif(strlen($GLOBALS[$to])) // less than
					{
						$filter['<='.$code] = $GLOBALS[$to];
					}
				}
				else
				{
					if(strlen($GLOBALS['find_'.$code]))
						$filter[static::getFilterModifier($fld['data_type']).$code] = $GLOBALS['find_'.$code];
				}
			}
		}

		if(!empty($filter))
			$parameters['filter'] = $filter;
		if(strlen($by))
		{
			$columns = static::getColumns($page); // check if that column really exists, for the whole extension hierarchy

			if(isset($columns[$by]))
				$parameters['order'] = array($by => isset($order) ? $order : 'asc');
		}

		return $parameters;
	}

	// crud over entity: add
	public static function add($data)
	{
		$success = true;
		$id = false;
		$entityClass = static::getEntityClass();

		$data = static::convertToArray($data);

		$data = static::proxyUpdateRequest($data);
		$errors = static::validateUpdateRequest($data);

		if(empty($errors))
		{
			$res = $entityClass::add($data);
			if(!$res->isSuccess())
			{
				$success = false;
				$errors = $res->getErrorMessages();
			}
			else
				$id = $res->getId();
		}
		else
			$success = false;

		return array(
			'success' => $success,
			'errors' => $errors,
			'id' => $id
		);
	}

	// crud over entity: update
	public static function update($primary, $data)
	{
		$success = true;
		$entityClass = static::getEntityClass();

		$data = static::convertToArray($data);
		$data = static::proxyUpdateRequest($data);
		$errors = static::validateUpdateRequest($data);

		if(empty($errors))
		{
			$res = $entityClass::update($primary, $data);
			if(!$res->isSuccess())
			{
				$success = false;
				$errors = $res->getErrorMessages();
			}
		}
		else
			$success = false;

		return array(
			'success' => $success,
			'errors' => $errors
		);
	}

	// crud over entity: delete
	public static function delete($primary)
	{
		$success = true;
		$errors = array();
		$entityClass = static::getEntityClass();

		$res = $entityClass::delete($primary);
		if(!$res->isSuccess())
		{
			$success = false;
			$errors = $res->getErrorMessages();
		}

		return array(
			'success' => $success,
			'errors' => $errors
		);
	}

	// function calculates limit and offset for sql select query, based on current request and session
	// variables, then forms fake old-style database result
	public static function getList($parameters = array(), $tableId = false, $navigation = 20, $params = array())
	{
		$entityClass = static::getEntityClass();

		$navNum = $GLOBALS['NavNum'] + 1;
		$unique = md5($GLOBALS['APPLICATION']->GetCurPage());
		$showAll = $_SESSION[$unique.'SESS_ALL_'.$navNum] || $_GET['SHOWALL_'.$navNum];

		if ($params["uiMode"])
		{
			$result = new \CSaleProxyAdminUiResult($parameters, $entityClass, $tableId);
		}
		elseif(ADMIN_SECTION === true && strlen($tableId))
		{
			$result = new \CSaleProxyAdminResult($parameters, $entityClass, $tableId); // being in admin and knowing table, do admin result api call
		}
		else
		{
			$result = new \CSaleProxyResult($parameters, $entityClass); // otherwise - public api call
		}

		if(!$showAll && $navigation !== false)
		{
			if($navigation === true)
			{
				$result->NavStart();
			}
			else
			{
				$result->NavStart($navigation);
			}
		}
		else
		{
			$result->NavStart();
		}

		// temporal fix
		$result->bShowAll = false;

		return $result;
	}

	public static function convertToArray($data)
	{
		if(!is_array($data))
		{
			$converted = array();
			foreach($data as $key => $value)
				$converted[$key] = $value;

			$data = $converted;
		}

		foreach($data as &$value)
		{
			if(is_string($value))
				$value = trim($value);
		}

		return $data;
	}

	// deprecated: not optimal
	public static function getIdsByFilter($listFilter)
	{
		$ids = array();
		$entityClass = static::getEntityClass();

		$res = $entityClass::getList(array(
			'select' => array('ID'),
			'filter' => is_array($listFilter) ? $listFilter : array()
		));
		while($item = $res->fetch())
		{
			$ids[] = intval($item['ID']);
		}

		return $ids;
	}

	public static function getPrimaryFieldName()
	{
		$map = static::getEntityRoadMap();

		return strlen($map['main']['primaryFieldName']) ? $map['main']['primaryFieldName'] : 'ID';
	}

	// returns element name by it`s primary
	public static function getNameToDisplay($id)
	{
		if(!($id = intval($id)))
			return '';

		$entityClass = static::getEntityClass('main');

		$item = $entityClass::getById($id)->fetch();
		return $item['CODE'];
	}

	public static function getListUrl($parameters = array())
	{
		return self::getUrl(static::LIST_PAGE_URL, $parameters);
	}

	public static function getEditUrl($parameters = array())
	{
		return self::getUrl(static::EDIT_PAGE_URL, $parameters);
	}

	public static function getImportUrl()
	{
		return self::getUrl(static::IMPORT_PAGE_URL, array());
	}

	public static function getReindexUrl()
	{
		return self::getUrl(static::REINDEX_PAGE_URL, array());
	}

	public static function getMigrationUrl()
	{
		return self::getUrl(static::MIGRATION_PAGE_URL, array());
	}

	public static function getUrl($page, $parameters = array())
	{
		if(!is_array($parameters))
			$parameters = array();

		$parameters['lang'] = LANGUAGE_ID;

		$selfFolderUrl = (defined("SELF_FOLDER_URL") ? SELF_FOLDER_URL : "/bitrix/admin/");

		$packed = self::packUrlParameters($parameters);
		return $selfFolderUrl.$page.(strlen($packed) ? '?'.$packed : '');
	}

	#####################################
	#### Utilily methods for CRUD
	#####################################

	// deprecated: too strong relation with admin grid
	public static function checkUseFilter()
	{
		return $GLOBALS['filter'] == 'Y' && !$GLOBALS['del_filter'];
	}

	public static function readMap($entityRoadCode, $page = 'list')
	{
		$roads = static::getEntityRoadMap();
		$road = $roads[$entityRoadCode];

		if(!$road['name'])
			throw new Main\SystemException('Undefined entity name in entity map');

		if(!strlen($page))
			$page = 'list';

		$flds = array();
		$class = $road['name'].'Table';
		$excluded = $road['pages'][$page]['excludedColumns'];
		$included = $road['pages'][$page]['includedColumns'];

		$map = $class::getMap();
		if(is_array($road['additional']) && !empty($road['additional']))
			$map = array_merge($map, $road['additional']);

		foreach($map as $fldCode => $fldDesc)
		{
			if((strlen($fldDesc['title']) || $fldDesc['required'] || $fldDesc['primary'] || $fldCode == 'ID'))
			{
				if(is_array($excluded) && in_array($fldCode, $excluded))
					continue;

				if(is_array($included) && !in_array($fldCode, $included))
					continue;

				$fldDesc['title'] = strlen($fldDesc['title']) ? htmlspecialcharsbx($fldDesc['title']) : $fldCode;
				$fldDesc['ownerEntity'] = $road['name']; // map can be cumulative, from several entites, so we need to know who is an owner
				$flds[$fldCode] = $fldDesc;
			}
		}

		return $flds;
	}

	protected static function getFilterModifier($type)
	{
		return $type == 'string' ? '?' : '=';
	}

	protected static function packUrlParameters($parameters = array())
	{
		$params = array();
		foreach($parameters as $param => $value)
		{
			if(strlen($value))
			{
				if(strpos($param, '=') === 0)
				{
					// value goes as-is, unsafe
					$param = substr($param, 1);
				}
				else
					$value = urlencode($value);

				$params[] = urlencode($param).'='.$value;
			}
		}

		return implode('&', $params);
	}

	protected static function getEntityClass($code = '')
	{
		$entityRoad = static::getEntityRoadMap();
		$entityName = $entityRoad[strlen($code) ? $code : self::getEntityRoadCode()]['name'];

		if(!$entityName)
			throw new Main\SystemException('Undefined entity name in helper');

		return $entityName.'Table';
	}

	public static function getWidgetAppearance()
	{
		$appearance = Config\Option::get("sale", "sale_location_selector_appearance");

		if(!strlen($appearance) || !in_array($appearance, array('search', 'steps')))
			return 'steps';

		return $appearance;
	}

	protected static function normalizeList($list, $expectNumeric = true)
	{
		$list = array_unique(array_values($list));
		foreach($list as $i => $id)
		{
			if($expectNumeric)
			{
				if(intval($id) != $id)
					unset($list[$i]);

				$list[$i] = intval($id);
				if(!$list[$i])
					unset($list[$i]);
			}
			else
			{
				if(!strlen($list[$i]))
					unset($list[$i]);
			}
		}

		return $list;
	}

	// proxy between $_REQUEST and resulting array to save links between entites and locations
	public static function prepareLinksForSaving($connectorClass, $links)
	{
		$useIds = !$connectorClass::getUseCodes();
		$useGroups = $connectorClass::getUseGroups();
		$l = $connectorClass::DB_LOCATION_FLAG;
		$g = $connectorClass::DB_GROUP_FLAG;

		if(isset($links[$l]))
		{
			if(is_string($links[$l]))
				$links[$l] = explode(':', $links[$l]);
		}
		else
			$links[$l] = array();

		$links[$l] = self::normalizeList($links[$l], $useIds);

		if(!$useGroups)
			unset($links[$g]);
		else
		{
			if(isset($links[$g]))
			{
				if(is_string($links[$g]))
					$links[$g] = explode(':', $links[$g]);
			}
			else
				$links[$g] = array();

			$links[$g] = self::normalizeList($links[$g], $useIds);
		}

		return $links;
	}

	public static function resetLocationsForEntity($entityId, $locations, $entityName, $expectCodes = false)
	{
		$locList = array();

		if(is_array($locations) && !empty($locations))
		{
			foreach($locations as $loc)
			{
				if($loc['LOCATION_TYPE'] == 'L')
					$locList[Location\Connector::DB_LOCATION_FLAG][] = $loc['LOCATION_ID'];
				elseif($loc['LOCATION_TYPE'] == 'G')
					$locList[Location\Connector::DB_GROUP_FLAG][] = $loc['LOCATION_ID'];
			}
		}

		$entityClass = $entityName.'Table';

		try
		{
			if(!empty($locList) && !$expectCodes)
			{
				$locList[Location\Connector::DB_LOCATION_FLAG] = $entityClass::normalizeLocationList($locList[Location\Connector::DB_LOCATION_FLAG]);

				$gf = Location\Connector::DB_GROUP_FLAG;
				if(!empty($locList[$gf]))
				{
					$groupCodes = array();
					$locList[$gf] = array_flip($locList[$gf]);
					// here we must get codes by ids for groups. There will be no thousands of groups, so we can do the following:
					$res = Location\GroupTable::getList(array('select' => array('ID', 'CODE')));
					while($item = $res->fetch())
					{
						if(isset($locList[$gf][$item['ID']]))
							$groupCodes[$item['CODE']] = 1;
					}

					$locList[$gf] = array_keys($groupCodes);
				}
			}

			$entityClass::resetMultipleForOwner($entityId, $locList);
		}
		catch(Exception $e)
		{
		}
	}
}