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)
60 $type = intval($type);
61 if(isset($typesFromDb[$type]))
66 return array_unique($result);
72 if(is_array($types) && !empty($types))
74 $typesFromDb = static::getTypesFromDb();
76 foreach($types as $type)
78 $type = intval($type);
79 if(isset($typesFromDb[$type]))
83 $result = array_unique($result);
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);
98 $langs = explode(
':', $langs);
102 foreach($langs as $lang)
104 if(isset($langsFromDb[$lang]))
109 return array_unique($result);
114 if(is_array($langs) && !empty($langs))
115 $langs = array_unique($langs);
120 if(is_array($langs) && !empty($langs))
122 $langsFromDb = static::getLangsFromDb();
124 foreach($langs as $lang)
126 if(isset($langsFromDb[$lang]))
130 $result = array_unique($result);
133 Option::set(
'sale', self::SALE_LOCATION_INDEXED_LANGUAGES_OPT, implode(
':', $result),
'');
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);
298 $dbConnection = Main\HttpApplication::getConnection();
299 $dbHelper = Main\HttpApplication::getConnection()->getSqlHelper();
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'].
"'"
324 $query[
'WHERE'][] = (
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']).
"'";
352 $map = Location\LocationTable::getMap();
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;
379 foreach($filter as $field => $params)
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'])
393 unset($filter[$field]);
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';
428 foreach($filter as $field => $params)
430 if($field !=
'NAME.NAME' && $field !=
'NAME.LANGUAGE_ID')
431 $field =
'L.'.$dbHelper->forSql($field);
433 $values = $params[
'VALUE'];
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
464 from ".Location\LocationTable::getTableName().
" L
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);
492 $dbConnection = Main\HttpApplication::getConnection();
493 $dbHelper = $dbConnection->getSqlHelper();
496 $locationTable = Location\LocationTable::getTableName();
497 $locationNameTable = Location\Name\LocationTable::getTableName();
498 $locationGroupTable = Location\GroupLocationTable::getTableName();
499 $locationSiteTable = Location\SiteLocationTable::getTableName();
500 $locationTypeTable = Location\TypeTable::getTableName();
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;
531 if (isset($filter[
'ID']))
533 if (is_array($filter[
'ID'][
'VALUE']))
535 $doFilterById =
true;
537 if (count($filter[
'ID'][
'VALUE']) === 1)
539 reset($filter[
'ID'][
'VALUE']);
540 $filterId = (int)current($filter[
'ID'][
'VALUE']);
544 $filterId = $filter[
'ID'][
'VALUE'];
547 elseif ((
int)$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;
605 $map = Location\LocationTable::getMap();
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))
658 $fields[
'NAME'] =
'LN.NAME';
662 $fields[$nameAlias] =
'LN.NAME';
665 $fields = array_merge($fields, array(
666 'L.LEFT_MARGIN' =>
'L.LEFT_MARGIN',
667 'L.RIGHT_MARGIN' =>
'L.RIGHT_MARGIN'
670 $groupFields = $fields;
673 foreach($parameters[
'select'] as $alias => $fld)
677 if((
string) $alias === (
string) intval($alias))
680 if(in_array($lFld, $fields))
683 $fields[$lFld] = $lFld;
688 if(isset($fields[$alias]))
691 $fields[$alias] = $lFld;
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)