Быстрый пример из реального проекта.
Это код в component.php кастомного компонента. Пользователь попадает на него со своими текущими координатами и нужно показать рестораны с координатами в квадрате 5 на 5 км. Где центр это местоположение пользователя:
| Код |
|---|
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// TODO: все важные настройки уедут в options /local/modules/edavmig.mobileapp
use Bitrix\Main\Loader;
use Bitrix\Main\Config\Option;
// use Bitrix\Main\Engine\CurrentUser;
if (
!Loader::includeModule('iblock') ||
!Loader::includeModule('highloadblock')
) {
return;
}
// PARAMS - позже уедут в параметры компонента
$arParams['IBLOCK_ID'] = 4; // Рестораны
$arParams['HL_FOR_ATT_FOOD_TYPE'] = 7; // HL-блок Категории кухни
$arParams['FIND_REST_RADIUS'] = 5; // Радиус поиска ресторанов
$arParams['YANDEX_MAP_API_KEY'] = trim(
Option::get("fileman", "yandex_map_api_key")
);
// RESULTS
$arResult['RESTAURANTS'] = [];
$arResult['FILTER'] = [
'=IBLOCK_ID' => $arParams['IBLOCK_ID'], // Рестораны
];
// Проверяем наличие координат в $_REQUEST
if (
isset($_REQUEST['LAT'], $_REQUEST['LON']) &&
$_REQUEST['LAT'] !== '' && $_REQUEST['LON'] !== ''
) {
/*
Если пришли с координатами в $_REQUEST, находим
все рестораны, которые находятся в квадрате FIND_REST_RADIUS×FIND_REST_RADIUS км
с центром в точке $_REQUEST['LAT'] и $_REQUEST['LON'].
*/
$userLat = (float) $_REQUEST['LAT'];
$userLon = (float) $_REQUEST['LON'];
$squareSize = (float) $arParams['FIND_REST_RADIUS'];
// Вычисляем границы квадрата (1 градус широты ≈ 111 км)
$latDelta = $squareSize / 111;
$lonDelta = $squareSize / (111 * cos(deg2rad($userLat)));
// Применяем в фильтре, находим только рестораны внутри квадрата
$arResult['FILTER']['><PROPERTY_LAT'] = [$userLat - $latDelta, $userLat + $latDelta];
$arResult['FILTER']['><PROPERTY_LON'] = [$userLon - $lonDelta, $userLon + $lonDelta];
}
// Формируем рестораны =================================================================
$arFoodTypesFromHl = []; // Сборщик типов кухни для дальнейшего запроса в HL
$Restorants = CIBlockElement::GetList(
['NAME' => 'ASC'], // Сортировка по названию
$arResult['FILTER'],
false,
false,
['ID', 'NAME', 'DETAIL_PAGE_URL', 'PREVIEW_TEXT', 'PROPERTY_*']
);
while ($obRestaurant = $Restorants->GetNextElement()) {
$arFields = $obRestaurant->GetFields();
$arProps = $obRestaurant->GetProperties();
// Объединяем поля и свойства
$arResult['RESTAURANTS'][$arFields['ID']] = $arFields;
$arResult['RESTAURANTS'][$arFields['ID']]['PROPERTIES'] = $arProps;
// Формирование категорий для использования в фильтре
if (!empty($arProps['ATT_FOOD_TYPE']['VALUE']) && is_array($arProps['ATT_FOOD_TYPE']['VALUE'])) {
foreach ($arProps['ATT_FOOD_TYPE']['VALUE'] as $foodTypeXmlId) {
$arFoodTypesFromHl[] = $foodTypeXmlId;
}
}
}
// end Формируем рестораны ============================================================
/*
Формирование фильтра "Тип кухни" из HL-блока
UF_XML_ID содержится в свойстве-справочнике у ресторанов
*/
$arResult['FOOD_TYPES_FILTER'] = [];
$arFoodTypesFromHl = array_unique($arFoodTypesFromHl);
// Делаем запрос к HL только если есть что выбирать
if (!empty($arFoodTypesFromHl)) {
$hlBlock = Bitrix\Highloadblock\HighloadBlockTable::getById(
$arParams['HL_FOR_ATT_FOOD_TYPE']
)->fetch();
if ($hlBlock) {
$entityDataClass = Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlBlock)->getDataClass();
$arResult['FOOD_TYPES_FILTER'] = $entityDataClass::getList([
'filter' => [
'UF_XML_ID' => $arFoodTypesFromHl
],
'select' => [
'UF_NAME',
'UF_XML_ID',
'UF_FILE'
]
])->fetchAll();
}
}
// end Формирование фильтра "Тип кухни" из HL-блока =======================================
$this->IncludeComponentTemplate(); |
У ресторанов очень много свойств и постоянно появляются новые (проект в активной стадии разработки) - постоянно отслеживать новые свойства, вообще не с руки. С помощью GetNextElement() я уверен что они автоматом попадут в выборку