8namespace Bitrix\Sale\Location\Search;
12use Bitrix\Main\Localization\Loc;
13use Bitrix\Main\Config\Option;
15use Bitrix\Sale\Location;
16use Bitrix\Sale\Location\Util\Assert;
18Loc::loadMessages(__FILE__);
32 return Option::get(
'sale', self::SALE_LOCATION_INDEX_VALID_OPT,
'',
'') ==
'Y';
37 Option::set(
'sale', self::SALE_LOCATION_INDEX_VALID_OPT,
'Y',
'');
42 Option::set(
'sale', self::SALE_LOCATION_INDEX_VALID_OPT,
'N',
'');
47 $types = Option::get(
'sale', self::SALE_LOCATION_INDEXED_TYPES_OPT,
'',
'');
48 $typesFromDb = static::getTypesFromDb();
51 return array_keys($typesFromDb);
53 $types = explode(
':', $types);
58 foreach($types as
$type)
61 if(isset($typesFromDb[
$type]))
72 if(is_array($types) && !empty($types))
74 $typesFromDb = static::getTypesFromDb();
76 foreach($types as
$type)
79 if(isset($typesFromDb[
$type]))
86 Option::set(
'sale', self::SALE_LOCATION_INDEXED_TYPES_OPT, implode(
':',
$result),
'');
91 $langs = Option::get(
'sale', self::SALE_LOCATION_INDEXED_LANGUAGES_OPT,
'',
'');
92 $langsFromDb = static::getLangsFromDb();
95 return array_keys($langsFromDb);
104 if(isset($langsFromDb[
$lang]))
122 $langsFromDb = static::getLangsFromDb();
126 if(isset($langsFromDb[
$lang]))
133 Option::set(
'sale', self::SALE_LOCATION_INDEXED_LANGUAGES_OPT, implode(
':',
$result),
'');
138 $langsFromDb =
array();
140 while($item =
$res->fetch())
141 $langsFromDb[$item[
'ID']] =
true;
148 $typesFromDb =
array();
149 $res = Location\TypeTable::getList(
array(
'select' =>
array(
'ID')));
150 while($item =
$res->fetch())
151 $typesFromDb[intval($item[
'ID'])] =
true;
164 $behaviour = [
'FALLBACK_TO_NOINDEX_ON_NOTFOUND' =>
true,
'USE_INDEX' =>
true,
'USE_ORM' =>
true]
170 Assert::expectArray($parameters,
'$parameters');
172 if(!is_array($behaviour))
173 $behaviour =
array();
174 if(!isset($behaviour[
'FALLBACK_TO_NOINDEX_ON_NOTFOUND']))
175 $behaviour[
'FALLBACK_TO_NOINDEX_ON_NOTFOUND'] =
true;
176 if(!isset($behaviour[
'USE_INDEX']))
177 $behaviour[
'USE_INDEX'] =
true;
178 if(!isset($behaviour[
'USE_ORM']))
179 $behaviour[
'USE_ORM'] =
true;
181 if(!isset($parameters[
'select']))
182 $parameters[
'select'] =
array(
'ID');
184 Assert::expectArray($parameters[
'select'],
'$parameters[select]');
186 if(isset($parameters[
'filter']))
188 Assert::expectArray($parameters[
'filter'],
'$parameters[filter]');
192 if(isset($parameters[
'filter'][
'PHRASE']) || isset($parameters[
'filter'][
'=PHRASE']))
194 $key = isset($parameters[
'filter'][
'PHRASE']) ?
'PHRASE' :
'=PHRASE';
196 $parameters[
'filter'][
$key] = Assert::expectStringNotNull($parameters[
'filter'][
$key],
'$parameters[filter]['.
$key.
']');
197 $parameters[
'filter'][
$key] = str_replace(
'%',
'', $parameters[
'filter'][
$key]);
200 if(isset($parameters[
'filter'][
'SITE_ID']) || isset($parameters[
'filter'][
'=SITE_ID']))
202 $key = isset($parameters[
'filter'][
'SITE_ID']) ?
'SITE_ID' :
'=SITE_ID';
203 $parameters[
'filter'][
$key] = Assert::expectStringNotNull($parameters[
'filter'][
$key],
'$parameters[filter]['.
$key.
']');
206 unset($parameters[
'filter'][
$key]);
210 if(isset($parameters[
'limit']))
211 $parameters[
'limit'] = Assert::expectIntegerNonNegative($parameters[
'limit'],
'$parameters[limit]');
212 if(isset($parameters[
'offset']))
213 $parameters[
'offset'] = Assert::expectIntegerNonNegative($parameters[
'offset'],
'$parameters[offset]');
218 (isset($parameters[
'filter'][
'PHRASE']) || isset($parameters[
'filter'][
'SITE_ID']) || isset($parameters[
'filter'][
'=PHRASE']) || isset($parameters[
'filter'][
'=SITE_ID']))
220 $behaviour[
'USE_ORM'] ===
false
223 if(static::checkIndexValid() && $behaviour[
'USE_INDEX'])
225 $result = static::findUsingIndex($parameters);
226 if(!$behaviour[
'FALLBACK_TO_NOINDEX_ON_NOTFOUND'])
232 $temporalBuffer =
array();
233 while($item =
$result->fetch())
235 $temporalBuffer[] = $item;
238 if(empty($temporalBuffer))
240 return static::findNoIndex($parameters);
250 return static::findNoIndex($parameters);
255 return Location\LocationTable::getList($parameters);
265 foreach(
$filter as $field => $value)
268 preg_match(
"#^(=?)(.+)#", $field, $found);
279 if(!isset(static::$allowedOperations[$op]))
282 $fieldParsed = $found[2];
284 $parsed[$fieldParsed] =
array(
285 'OP' => $op <>
''? $op :
'=',
301 $filter = static::parseFilter($parameters[
'filter']);
303 $filterByPhrase = isset(
$filter[
'PHRASE']) && mb_strlen(
$filter[
'PHRASE'][
'VALUE']);
310 $firstBound = array_shift($bounds);
312 foreach($bounds as $bound)
314 $query[
'JOIN'][] =
" inner join ".ChainTable::getTableName().
" A".
$k.
" on A.LOCATION_ID = A".
$k.
".LOCATION_ID and (
316 ".($bound[
'INF'] == $bound[
'SUP']
317 ?
" A".$k.
".POSITION = '".$bound[
'INF'].
"'"
318 :
" A".$k.
".POSITION >= '".$bound[
'INF'].
"' and A".
$k.
".POSITION <= '".$bound[
'SUP'].
"'"
325 $firstBound[
'INF'] == $firstBound[
'SUP']
326 ?
" A.POSITION = '".$firstBound[
'INF'].
"'"
327 :
" A.POSITION >= '".$firstBound[
'INF'].
"' and A.POSITION <= '".$firstBound[
'SUP'].
"'"
331 $mainTableJoinCondition =
'A.LOCATION_ID';
335 $mainTableJoinCondition =
'L.ID';
340 isset(
$filter[
'SITE_ID'][
'VALUE'])
341 && is_string(
$filter[
'SITE_ID'][
'VALUE'])
342 &&
$filter[
'SITE_ID'][
'VALUE'] !==
''
346 $query[
'JOIN'][] =
"inner join ".SiteLinkTable::getTableName().
" SL on SL.LOCATION_ID = ".$mainTableJoinCondition.
" and SL.SITE_ID = '".$dbHelper->forSql(
$filter[
'SITE_ID'][
'VALUE']).
"'";
353 $nameRequired =
false;
354 $locationRequired =
false;
356 if(is_array($parameters[
'select']))
358 foreach($parameters[
'select'] as $alias => $field)
360 if($field ==
'NAME.NAME' || $field ==
'NAME.LANGUAGE_ID')
362 $nameRequired =
true;
367 !isset(
$map[$field]) ||
368 !in_array(
$map[$field][
'data_type'],
array(
'integer',
'string',
'float',
'boolean')) ||
369 isset(
$map[$field][
'expression'])
372 unset($parameters[
'select'][$alias]);
375 $locationRequired =
true;
381 if($field ==
'NAME.NAME' || $field ==
'NAME.LANGUAGE_ID')
383 $nameRequired =
true;
388 !isset(
$map[$field]) ||
389 !in_array(
$map[$field][
'data_type'],
array(
'integer',
'string',
'float',
'boolean')) ||
390 isset(
$map[$field][
'expression'])
396 $locationRequired =
true;
401 if($locationRequired && $filterByPhrase)
402 $query[
'JOIN'][] =
"inner join ".Location\LocationTable::getTableName().
" L on A.LOCATION_ID = L.ID";
405 $query[
'JOIN'][] =
"inner join ".Location\Name\LocationTable::getTableName().
" NAME on NAME.LOCATION_ID = ".$mainTableJoinCondition;
408 if(is_array($parameters[
'select']))
411 foreach($parameters[
'select'] as $alias => $field)
413 if($field !=
'NAME.NAME' && $field !=
'NAME.LANGUAGE_ID')
414 $field =
'L.'.$dbHelper->forSql($field);
416 if((
string) $alias === (
string) intval($alias))
419 $select[] = $field.
' as '.$dbHelper->forSql($alias);
422 $sqlSelect = implode(
', ',
$select);
425 $sqlSelect = $mainTableJoinCondition.
' as ID';
430 if($field !=
'NAME.NAME' && $field !=
'NAME.LANGUAGE_ID')
431 $field =
'L.'.$dbHelper->forSql($field);
435 if(!is_array($values))
436 $values =
array($values);
438 foreach($values as $value)
439 $query[
'WHERE'][] = $field.
' '.
$params[
'OP'].
" '".$dbHelper->forSql($value).
"'";
445 select ".($dbConnection->getType() !=
'mysql' ?
'' :
'distinct').
"
446 ".$sqlSelect.(\Bitrix\Sale\Location\DB\Helper::needSelectFieldsInOrderByWhenDistinct() ?
', A.RELEVANCY' :
'').
"
450 ".implode(
' ',
$query[
'JOIN']).
"
452 ".(!empty(
$query[
'WHERE']) ?
'where ' :
'').implode(
' and ',
$query[
'WHERE']).
"
454 order by A.RELEVANCY asc
466 ".implode(
' ',
$query[
'JOIN']).
"
468 ".(!empty(
$query[
'WHERE']) ?
'where ' :
'').implode(
' and ',
$query[
'WHERE']).
"
472 $offset = (int)($parameters[
'offset'] ?? 0);
473 $limit = (int)($parameters[
'limit'] ?? 0);
477 $sql = $dbHelper->getTopSql($sql, $limit, $offset);
480 return $dbConnection->query($sql);
493 $dbHelper = $dbConnection->getSqlHelper();
506 $filter = static::parseFilter($parameters[
'filter']);
508 $doFilterBySite =
false;
509 $hasLocLinks =
false;
510 $hasGrpLinks =
false;
511 if ((
$filter[
'SITE_ID'][
'VALUE'] ??
'') !==
'')
513 $filterSite = $dbHelper->forSql(mb_substr(
$filter[
'SITE_ID'][
'VALUE'], 0, 2));
517 $doFilterBySite =
true;
520 $doFilterByName =
false;
522 $phrase = (string)(
$filter[
'PHRASE'][
'VALUE'] ??
'');
525 $doFilterByName =
true;
526 $filterName = $dbHelper->forSql(mb_strtoupper($phrase));
529 $doFilterById =
false;
533 if (is_array(
$filter[
'ID'][
'VALUE']))
535 $doFilterById =
true;
540 $filterId = (int)current(
$filter[
'ID'][
'VALUE']);
544 $filterId =
$filter[
'ID'][
'VALUE'];
549 $doFilterById =
true;
550 $filterId = (int)
$filter[
'ID'][
'VALUE'];
554 $doFilterByCode =
false;
556 $codeValue = (int)(
$filter[
'CODE'][
'VALUE'] ?? 0);
559 $doFilterByCode =
true;
560 $filterCode = $dbHelper->forSql((
string)$codeValue);
564 if ((
$filter[
'NAME.LANGUAGE_ID'][
'VALUE'] ??
'') !==
'')
566 $filterLang = $dbHelper->forSql(mb_substr((
string)
$filter[
'NAME.LANGUAGE_ID'][
'VALUE'], 0, 2));
570 $filterLang = LANGUAGE_ID;
573 $doFilterByCountry =
false;
574 $filterCountryId = 0;
575 if (isset(
$filter[
'COUNTRY_ID']) && (
int)
$filter[
'COUNTRY_ID'][
'VALUE'] >= 0)
577 $doFilterByCountry =
true;
578 $filterCountryId = (int)
$filter[
'COUNTRY_ID'][
'VALUE'];
581 $doFilterByParent =
false;
583 if (isset(
$filter[
'PARENT_ID']) && (
int)
$filter[
'PARENT_ID'][
'VALUE'] >= 0)
585 $doFilterByParent =
true;
586 $filterParentId = (int)
$filter[
'PARENT_ID'][
'VALUE'];
589 $doFilterByType =
false;
591 if ((
int)(
$filter[
'TYPE_ID'][
'VALUE'] ?? 0))
593 $doFilterByType =
true;
594 $filterTypeId = (int)
$filter[
'TYPE_ID'][
'VALUE'];
598 $parameters[
'select'] ??= [];
599 if(!is_array($parameters[
'select']))
601 $parameters[
'select'] = [];
604 $doCountChildren =
false;
613 foreach($parameters[
'select'] as $alias => $field)
615 if ($field ===
'CHILD_CNT')
617 $doCountChildren =
true;
620 if ($field ===
'NAME.NAME')
626 if (!isset(
$map[$field]))
631 !isset($allowTypes[
$map[$field][
'data_type']])
632 || isset(
$map[$field][
'expression'])
639 unset($parameters[
'select'][$alias]);
651 'L.CODE' =>
'L.CODE',
652 'L.SORT' =>
'L.SORT',
653 'LT_SORT' =>
'LT.DISPLAY_SORT'
656 if($nameAlias ===
false || !preg_match(
'#^[a-zA-Z0-9]+$#', $nameAlias))
662 $fields[$nameAlias] =
'LN.NAME';
666 'L.LEFT_MARGIN' =>
'L.LEFT_MARGIN',
667 'L.RIGHT_MARGIN' =>
'L.RIGHT_MARGIN'
673 foreach($parameters[
'select'] as $alias => $fld)
677 if((
string) $alias === (
string) intval($alias))
695 $groupFields[$lFld] = $lFld;
698 if ($doCountChildren)
700 $fields[
'CHILD_CNT'] =
'COUNT(LC.ID)';
705 foreach (
$fields as $alias => $fld)
710 $selectSql[] = $fld.
' as '.$alias;
713 $selectSql = implode(
', ', $selectSql);
715 $groupSql = implode(
', ', $groupFields);
717 $mainSql =
"select {$selectSql}
718 from {$locationTable} L
719 inner join {$locationNameTable} LN on L.ID = LN.LOCATION_ID
720 inner join {$locationTypeTable} LT on L.TYPE_ID = LT.ID ".
722 ($doCountChildren ?
"
723 left join {$locationTable} LC on L.ID = LC.PARENT_ID
726 %SITE_FILTER_CONDITION%
730 %MAIN_FILTER_CONDITION%
737 $where[] =
"LN.LANGUAGE_ID = '" . $filterLang .
"'";
739 if ($doFilterByCountry)
741 $where[] =
"L.COUNTRY_ID = " . $filterCountryId .
" ";
744 if ($doFilterByParent)
746 $where[] =
"L.PARENT_ID = " . $filterParentId .
" ";
751 if(is_array($filterId))
753 foreach($filterId as $idx => $id)
755 $filterId[$idx] = (int)$id;
758 $where[] =
"L.ID IN (".implode(
',', $filterId).
")";
762 $where[] =
"L.ID = ".$filterId;
768 $where[] =
"L.CODE = '".$filterCode.
"'";
773 $where[] =
"L.TYPE_ID = '" . $filterTypeId .
"'";
778 $where[] =
"LN.NAME_UPPER like '" . $filterName .
"%'";
781 $mainSql = str_replace(
'%MAIN_FILTER_CONDITION%', implode(
' and ', $where), $mainSql);
782 $needDistinct =
false;
784 $artificialNav =
false;
788 $sql = str_replace(
'%SITE_FILTER_CONDITION%',
'', $mainSql);
795 $sql[] = str_replace(
'%SITE_FILTER_CONDITION%',
"
797 inner join {$locationTable} L2 on L2.LEFT_MARGIN <= L.LEFT_MARGIN and L2.RIGHT_MARGIN >= L.RIGHT_MARGIN
798 inner join {$locationSiteTable} LS2 on L2.ID = LS2.LOCATION_ID and LS2.LOCATION_TYPE = 'L' and LS2.SITE_ID = '{$filterSite}'
804 $sql[] = str_replace(
'%SITE_FILTER_CONDITION%',
"
806 inner join {$locationTable} L2 on L2.LEFT_MARGIN <= L.LEFT_MARGIN and L2.RIGHT_MARGIN >= L.RIGHT_MARGIN
807 inner join {$locationGroupTable} LG on LG.LOCATION_ID = L2.ID
808 inner join {$locationSiteTable} LS2 on LG.LOCATION_GROUP_ID = LS2.LOCATION_ID and LS2.LOCATION_TYPE = 'G' and LS2.SITE_ID = '{$filterSite}'
819 $needDistinct =
true;
827 $sql = ($cnt > 1 ?
'(' :
'').implode(
') union (', $sql).($cnt > 1 ?
')' :
'');
831 $sql = str_replace(
'%GROUP_BY%', $needDistinct || $doCountChildren ?
"group by {$groupSql}" :
'', $sql);
833 $parameters[
'order'] ??=
null;
834 if (!is_array($parameters[
'order']))
836 $sql .=
" order by 3, 4 asc, 5";
841 if (isset($parameters[
'order'][
'NAME.NAME']))
843 $sql .=
" order by 5 " . ($parameters[
'order'][
'NAME.NAME'] ==
'asc' ?
'asc' :
'desc');
847 $offset = (int)($parameters[
'offset'] ?? 0);
848 $limit = (int)($parameters[
'limit'] ?? 0);
852 if ($dbConnection->getType() ==
'mssql')
856 $artificialNav =
true;
860 $sql = $dbHelper->getTopSql($sql, $limit, $offset);
864 $res = $dbConnection->query($sql);
870 while($item =
$res->fetch())
877 if(
$i >= $offset + $limit)
static getConnection($name="")
static getList(array $parameters=array())
static checkLinkUsage($entityPrimary, $linkType=self::DB_LOCATION_FLAG)
static checkLinkUsageAny($entityPrimary)
static getIndexedLanguages()
static parseFilter($filter)
static findNoIndex($parameters)
const SALE_LOCATION_INDEXED_TYPES_OPT
const SALE_LOCATION_INDEXED_LANGUAGES_OPT
const SALE_LOCATION_INDEX_VALID_OPT
static setIndexedTypes($types=array())
static setIndexedLanguages($langs=array())
static $allowedOperations
static find( $parameters, $behaviour=['FALLBACK_TO_NOINDEX_ON_NOTFOUND'=> true, 'USE_INDEX'=> true, 'USE_ORM'=> true])
static findUsingIndex($parameters)
static checkTableExists()
static getBoundsForPhrase($phrase)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!defined('SITE_ID')) $lang
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
if(empty($signedUserToken)) $key
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']