Your IP : 18.191.155.227
<?
/**
* 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)
{
}
}
}