Modules/devices/devices search inc php: различия между версиями

Материал из MajorDoMo инфо
(Заготовка)
 
(+ file devices_search.inc.php)
 
Строка 4: Строка 4:


<pre>
<pre>
Заготовка
<?php
/*
* @version 0.1 (wizard)
*/
// Глобальная переменная $session используется для хранения данных сессии.
global $session;
 
// Проверяем, является ли текущий объект панелью управления.
// Если это так, то устанавливаем флаг CONTROLPANEL в 1, что может быть использовано для определения,
// нужно ли отображать элементы управления панелью.
if ($this->owner->name == 'panel') {
    $out['CONTROLPANEL'] = 1;
}
 
// Инициализируем запрос с условием, что все записи должны быть выбраны.
// Значение "1" в SQL означает, что условие всегда истинно, и запрос будет выбирать все записи.
$qry = "1";
 
// Фильтры поиска.
// Здесь предполагается, что будут добавлены дополнительные условия для фильтрации результатов поиска.
 
// Получаем тип устройства из запроса.
// Функция gr('type') предположительно извлекает параметр 'type' из запроса.
$type = gr('type');
 
// Если тип устройства указан, добавляем его в запрос.
// Это позволяет фильтровать результаты поиска по типу устройства.
if ($type != '') {
    // Добавляем условие в запрос, чтобы выбрать только устройства с указанным типом.
    // Функция DBSafe($type) предположительно очищает входные данные от потенциально вредоносного кода.
    $qry .= " AND devices.TYPE='" . DBSafe($type) . "'";
    // Сохраняем тип устройства в массиве $out для дальнейшего использования.
    $out['TYPE'] = $type;
}
 
// Получаем ID местоположения из запроса.
// Функция gr('location_id') предположительно извлекает параметр 'location_id' из запроса.
$location_id = gr('location_id');
 
// Проверяем, указан ли параметр управления местоположениями.
// Если параметр равен 'manage_locations', перенаправляем пользователя на страницу управления местоположениями.
if ($location_id == 'manage_locations') {
    $this->redirect("?(panel:{action=locations})");
} elseif ($location_id) {
    // Если указан ID местоположения, добавляем его в запрос.
    // Приведение к типу int гарантирует, что ID будет числом, что необходимо для корректного SQL-запроса.
    $out['LOCATION_ID'] = (int)$location_id;
    // Добавляем условие в запрос, чтобы выбрать только устройства с указанным ID местоположения.
    $qry .= " AND devices.LOCATION_ID=" . $out['LOCATION_ID'];
}
 
// Получаем имя группы устройств из запроса.
// Функция gr('group_name') предположительно извлекает параметр 'group_name' из запроса.
$group_name = gr('group_name');
 
// Проверяем, указан ли параметр управления группами.
// Если параметр равен 'manage_groups', перенаправляем пользователя на страницу управления группами.
if ($group_name == 'manage_groups') {
    $this->redirect("?view_mode=manage_groups");
} elseif ($group_name == 'is:archived') {
    // Если указан параметр архивированных устройств, добавляем его в запрос.
    // Это позволяет фильтровать результаты поиска, отображая только архивированные устройства.
    $qry .= " AND devices.ARCHIVED=1";
} elseif ($group_name == 'is:system') {
    // Если указан параметр системных устройств, добавляем его в запрос.
    // Это позволяет фильтровать результаты поиска, отображая только системные устройства.
    $qry .= " AND devices.SYSTEM_DEVICE=1";
} elseif ($group_name == 'is:inactive') {
    // Получаем имена объектов, которые не активны (например, устройства, не отвечающие на запросы).
    $object_names = getObjectsByProperty('alive');
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            // Проверяем, является ли объект активным.
            $val = getGlobal($object_names[$i].'.alive');
            if (!$val) {
                // Если объект не активен, добавляем его в список для фильтрации.
                $res_object_names[] = "'" . $object_names[$i] . "'";
            }
        }
        // Добавляем условие в запрос для фильтрации по именам неактивных объектов.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $res_object_names) . ")";
    } else {
        // Если список объектов пуст, добавляем условие, которое не позволит выбрать ни одного устройства.
        $qry .= " AND 0";
    }
} elseif ($group_name == 'is:battery') {
    // Получаем имена объектов, работающих от батареи.
    // Функция getObjectsByProperty('batteryOperated', 1) предположительно возвращает список объектов,
    // которые работают от батареи.
    $object_names = getObjectsByProperty('batteryOperated', 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // работающим от батареи.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        // Если список объектов пуст, добавляем условие, которое не позволит выбрать ни одного устройства.
        $qry .= " AND 0";
    }
} elseif ($group_name == 'is:battery_low') {
    // Получаем имена объектов с низким уровнем заряда батареи.
    // Функция getObjectsByProperty('batteryWarning', 1) предположительно возвращает список объектов,
    // у которых уровень заряда батареи низкий.
    $object_names = getObjectsByProperty('batteryWarning', 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // у которых уровень заряда батареи низкий.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        $qry .= " AND 0";
    }
} elseif ($group_name) {
    // Получаем имена объектов по имени группы.
    // Функция getObjectsByProperty('group' . $group_name, 1) предположительно возвращает список объектов,
    // соответствующих указанному имени группы.
    $object_names = getObjectsByProperty('group' . $group_name, 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // соответствующим указанному имени группы.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        $qry .= " AND 0";
    }
}
// Сохраняем имя группы устройств в массиве $out для дальнейшего использования.
$out['GROUP_NAME'] = $group_name;
 
// Если не указан параметр архивированных устройств, добавляем условие выбора неархивированных устройств.
// Это условие гарантирует, что в результатах поиска будут отображаться только устройства, которые не были помечены как архивированные.
if ($group_name != 'is:archived') {
    $qry .= " AND devices.ARCHIVED=0";
}
 
// QUERY READY//Запрос к базе данных готов к выполнению
// Глобальная переменная $save_qry используется для определения, следует ли сохранять текущий запрос или использовать сохраненный.
global $save_qry;
 
// Если установлено сохранение запроса, используем сохраненный запрос.
// Это может быть полезно для сохранения состояния фильтрации между различными запросами.
if ($save_qry) {
    $qry = $session->data['devices_qry'];
} else {
    // Иначе сохраняем текущий запрос в сессии для возможного использования в будущем.
    $session->data['devices_qry'] = $qry;
}
 
// Если запрос пуст, устанавливаем его как "1" для выбора всех записей.
// Это обеспечивает, что в любом случае будет выполнен запрос, даже если не было указано никаких фильтров.
if (!$qry) $qry = "1";
 
// Получаем общее количество устройств, не архивированных.
// Это делается для отображения общего количества доступных устройств в пользовательском интерфейсе.
$tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE devices.ARCHIVED!=1");
$out['TOTAL'] = (int)$tmp['TOTAL'];
 
$loc_title = '';
// Сортировка результатов по приоритету местоположения, названию местоположения, ID местоположения, типу устройства и названию устройства
$sortby_devices = "locations.PRIORITY DESC, locations.TITLE, devices.LOCATION_ID, devices.TYPE, devices.TITLE";
$out['SORTBY'] = $sortby_devices;
// РЕЗУЛЬТАТЫ ПОИСКА
// Выполняем SQL-запрос для получения результатов поиска устройств, включая информацию о местоположении каждого устройства.
// Запрос сортируется по заданным критериям сортировки.
$res = SQLSelect("SELECT devices.*, locations.TITLE as LOCATION_TITLE FROM devices LEFT JOIN locations ON devices.LOCATION_ID=locations.ID WHERE $qry ORDER BY " . $sortby_devices);
 
// Проверяем, есть ли результаты поиска.
if (isset($res[0])) {
    //paging($res, 100, $out); // search result paging
    // Подсчитываем общее количество найденных устройств.
    $total = count($res);
    $out['TOTAL_FOUND'] = $total;
    // Обрабатываем каждый результат поиска.
    for ($i = 0; $i < $total; $i++) {
        // Если название местоположения изменилось, устанавливаем флаг NEW_LOCATION.
        if ($res[$i]['LOCATION_TITLE'] != $loc_title) {
            $res[$i]['NEW_LOCATION'] = 1;
            $loc_title = $res[$i]['LOCATION_TITLE'];
        }
        // Если у устройства есть связанный объект, обрабатываем его.
        if ($res[$i]['LINKED_OBJECT']) {
            // Обработка устройства в зависимости от его типа.
            if ($res[$i]['TYPE'] == 'camera' || $res[$i]['TYPE'] == 'mark') {
                $processed = $this->processDevice($res[$i]['ID'], 'list');
            } else {
                $processed = $this->processDevice($res[$i]['ID']);
            }
            // Добавляем HTML-представление устройства.
            $res[$i]['HTML'] = $processed['HTML'];
            // Получаем свойства связанного объекта.
            $object_rec = SQLSelectOne("SELECT ID FROM objects WHERE TITLE='" . $res[$i]['LINKED_OBJECT'] . "'");
            if ($object_rec['ID']) {
                $properties = SQLSelect("SELECT pvalues.*, properties.TITLE as PROPERTY FROM pvalues LEFT JOIN properties ON properties.ID=pvalues.PROPERTY_ID WHERE pvalues.OBJECT_ID=" . $object_rec['ID'] . " AND pvalues.LINKED_MODULES!='' ORDER BY UPDATED");
                $totalp = count($properties);
                if ($totalp > 0) {
                    // Обрабатываем свойства, связанные с модулями.
                    $linked_modules = array();
                    for ($ip = 0; $ip < $totalp; $ip++) {
                        $tmp = explode(',', $properties[$ip]['LINKED_MODULES']);
                        $tmp = array_map('trim', $tmp);
                        foreach ($tmp as $linked_module) {
                            $linked_modules[$linked_module] = array('OBJECT' => $res[$i]['LINKED_OBJECT'], 'PROPERTY' => $properties[$ip]['PROPERTY']);
                        }
                    }
                    foreach ($linked_modules as $k => $v) {
                        $v['MODULE'] = $k;
                        $res[$i]['LINKED_MODULES'][] = $v;
                    }
                }
            }
        }
        // Добавляем название типа устройства.
        $res[$i]['TYPE_TITLE'] = $this->device_types[$res[$i]['TYPE']]['TITLE'];
        // Получаем количество связанных устройств.
        $linked = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices_linked WHERE (DEVICE1_ID=" . $res[$i]['ID'] . " OR DEVICE2_ID=" . $res[$i]['ID'] . ")");
        if ($linked['TOTAL']) {
            $res[$i]['LINKED'] = $linked['TOTAL'];
        }
        // Получаем количество методов устройства.
        $methods = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM methods WHERE CODE!='' AND OBJECT_ID=".(int)$object_rec['ID']);
        if ($methods['TOTAL']) {
            $res[$i]['METHODS'] = $methods['TOTAL'];
        }
    }
    // Сохраняем результаты поиска в массиве $out.
    $out['RESULT'] = $res;
}
 
// Подготовка к формированию списка типов устройств.
$types = array();
 
// Формирование списка типов устройств
// Проходим по всем типам устройств, определенным в $this->device_types.
foreach ($this->device_types as $k => $v) {
    // Проверяем, установлено ли название для типа устройства.
    if (isset($v['TITLE'])) {
        // Создаем запись для типа устройства с его названием и именем.
        $type_rec = array('NAME' => $k, 'TITLE' => $v['TITLE']);
        // Выполняем запрос к базе данных для подсчета количества устройств данного типа, которые не архивированы.
        $tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE TYPE='" . $k . "' AND ARCHIVED!=1");
        // Сохраняем количество устройств в записи типа устройства.
        $type_rec['TOTAL'] = (int)$tmp['TOTAL'];
        // Если количество устройств больше нуля, добавляем запись типа устройства в список.
        if ($type_rec['TOTAL'] > 0) {
            $types[] = $type_rec;
        }
    }
}
// Сортируем список типов устройств по названию.
usort($types, function ($a, $b) {
    return strcmp($a["TITLE"], $b["TITLE"]);
});
// Сохраняем отсортированный список типов устройств в массиве $out.
$out['TYPES'] = $types;
 
// Получение списка местоположений
// Выполняем запрос к базе данных для получения списка местоположений.
$locations = SQLSelect("SELECT ID, TITLE FROM locations ORDER BY TITLE+0");
$total = count($locations);
// Получение количества устройств для каждого местоположения
// Проходим по всем местоположениям и выполняем запрос к базе данных для подсчета количества устройств в каждом местоположении.
for ($i = 0; $i < $total; $i++) {
    $tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE LOCATION_ID='" . $locations[$i]['ID'] . "'");
    // Сохраняем количество устройств в записи местоположения.
    $locations[$i]['TOTAL'] = (int)$tmp['TOTAL'];
}
// Сохраняем список местоположений с количеством устройств в массиве $out.
$out['LOCATIONS'] = $locations;
 
// Получение списка групп устройств
// Выполняем запрос к базе данных для получения списка групп устройств.
$groups = SQLSelect("SELECT * FROM devices_groups ORDER BY TITLE");
// Добавляем системные группы в список групп.
$groups[] = array('SYS_NAME' => 'Eco', 'TITLE' => LANG_DEVICES_GROUP_ECO);
$groups[] = array('SYS_NAME' => 'EcoOn', 'TITLE' => LANG_DEVICES_GROUP_ECO_ON);
$groups[] = array('SYS_NAME' => 'Sunrise', 'TITLE' => LANG_DEVICES_GROUP_SUNRISE);
$groups[] = array('SYS_NAME' => 'Sunset', 'TITLE' => LANG_DEVICES_GROUP_SUNSET);
$groups[] = array('SYS_NAME' => 'Night', 'TITLE' => LANG_DEVICES_GROUP_NIGHT);
// Сохраняем список групп устройств в массиве $out.
$out['GROUPS'] = $groups;
</pre>
</pre>

Текущая версия от 21:29, 3 апреля 2024


ᐂ В корневой раздел ᐃ В директорию расположения файла

<?php
/*
* @version 0.1 (wizard)
*/
// Глобальная переменная $session используется для хранения данных сессии.
global $session;

// Проверяем, является ли текущий объект панелью управления.
// Если это так, то устанавливаем флаг CONTROLPANEL в 1, что может быть использовано для определения,
// нужно ли отображать элементы управления панелью.
if ($this->owner->name == 'panel') {
    $out['CONTROLPANEL'] = 1;
}

// Инициализируем запрос с условием, что все записи должны быть выбраны.
// Значение "1" в SQL означает, что условие всегда истинно, и запрос будет выбирать все записи.
$qry = "1";

// Фильтры поиска.
// Здесь предполагается, что будут добавлены дополнительные условия для фильтрации результатов поиска.

// Получаем тип устройства из запроса.
// Функция gr('type') предположительно извлекает параметр 'type' из запроса.
$type = gr('type');

// Если тип устройства указан, добавляем его в запрос.
// Это позволяет фильтровать результаты поиска по типу устройства.
if ($type != '') {
    // Добавляем условие в запрос, чтобы выбрать только устройства с указанным типом.
    // Функция DBSafe($type) предположительно очищает входные данные от потенциально вредоносного кода.
    $qry .= " AND devices.TYPE='" . DBSafe($type) . "'";
    // Сохраняем тип устройства в массиве $out для дальнейшего использования.
    $out['TYPE'] = $type;
}

// Получаем ID местоположения из запроса.
// Функция gr('location_id') предположительно извлекает параметр 'location_id' из запроса.
$location_id = gr('location_id');

// Проверяем, указан ли параметр управления местоположениями.
// Если параметр равен 'manage_locations', перенаправляем пользователя на страницу управления местоположениями.
if ($location_id == 'manage_locations') {
    $this->redirect("?(panel:{action=locations})");
} elseif ($location_id) {
    // Если указан ID местоположения, добавляем его в запрос.
    // Приведение к типу int гарантирует, что ID будет числом, что необходимо для корректного SQL-запроса.
    $out['LOCATION_ID'] = (int)$location_id;
    // Добавляем условие в запрос, чтобы выбрать только устройства с указанным ID местоположения.
    $qry .= " AND devices.LOCATION_ID=" . $out['LOCATION_ID'];
}

// Получаем имя группы устройств из запроса.
// Функция gr('group_name') предположительно извлекает параметр 'group_name' из запроса.
$group_name = gr('group_name');

// Проверяем, указан ли параметр управления группами.
// Если параметр равен 'manage_groups', перенаправляем пользователя на страницу управления группами.
if ($group_name == 'manage_groups') {
    $this->redirect("?view_mode=manage_groups");
} elseif ($group_name == 'is:archived') {
    // Если указан параметр архивированных устройств, добавляем его в запрос.
    // Это позволяет фильтровать результаты поиска, отображая только архивированные устройства.
    $qry .= " AND devices.ARCHIVED=1";
} elseif ($group_name == 'is:system') {
    // Если указан параметр системных устройств, добавляем его в запрос.
    // Это позволяет фильтровать результаты поиска, отображая только системные устройства.
    $qry .= " AND devices.SYSTEM_DEVICE=1";
} elseif ($group_name == 'is:inactive') {
    // Получаем имена объектов, которые не активны (например, устройства, не отвечающие на запросы).
    $object_names = getObjectsByProperty('alive');
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            // Проверяем, является ли объект активным.
            $val = getGlobal($object_names[$i].'.alive');
            if (!$val) {
                // Если объект не активен, добавляем его в список для фильтрации.
                $res_object_names[] = "'" . $object_names[$i] . "'";
            }
        }
        // Добавляем условие в запрос для фильтрации по именам неактивных объектов.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $res_object_names) . ")";
    } else {
        // Если список объектов пуст, добавляем условие, которое не позволит выбрать ни одного устройства.
        $qry .= " AND 0";
    }
} elseif ($group_name == 'is:battery') {
    // Получаем имена объектов, работающих от батареи.
    // Функция getObjectsByProperty('batteryOperated', 1) предположительно возвращает список объектов,
    // которые работают от батареи.
    $object_names = getObjectsByProperty('batteryOperated', 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // работающим от батареи.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        // Если список объектов пуст, добавляем условие, которое не позволит выбрать ни одного устройства.
        $qry .= " AND 0";
    }
} elseif ($group_name == 'is:battery_low') {
    // Получаем имена объектов с низким уровнем заряда батареи.
    // Функция getObjectsByProperty('batteryWarning', 1) предположительно возвращает список объектов,
    // у которых уровень заряда батареи низкий.
    $object_names = getObjectsByProperty('batteryWarning', 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // у которых уровень заряда батареи низкий.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        $qry .= " AND 0";
    }
} elseif ($group_name) {
    // Получаем имена объектов по имени группы.
    // Функция getObjectsByProperty('group' . $group_name, 1) предположительно возвращает список объектов,
    // соответствующих указанному имени группы.
    $object_names = getObjectsByProperty('group' . $group_name, 1);
    if (!is_array($object_names)) {
        $object_names = array(0);
    }
    $total = count($object_names);
    if ($total > 0) {
        for ($i = 0; $i < $total; $i++) {
            $object_names[$i] = "'" . $object_names[$i] . "'";
        }
        // Добавляем имена объектов в запрос, чтобы фильтровать результаты поиска по объектам,
        // соответствующим указанному имени группы.
        $qry .= " AND devices.LINKED_OBJECT IN (" . implode(',', $object_names) . ")";
    } else {
        $qry .= " AND 0";
    }
}
// Сохраняем имя группы устройств в массиве $out для дальнейшего использования.
$out['GROUP_NAME'] = $group_name;

// Если не указан параметр архивированных устройств, добавляем условие выбора неархивированных устройств.
// Это условие гарантирует, что в результатах поиска будут отображаться только устройства, которые не были помечены как архивированные.
if ($group_name != 'is:archived') {
    $qry .= " AND devices.ARCHIVED=0";
}

// QUERY READY//Запрос к базе данных готов к выполнению
// Глобальная переменная $save_qry используется для определения, следует ли сохранять текущий запрос или использовать сохраненный.
global $save_qry;

// Если установлено сохранение запроса, используем сохраненный запрос.
// Это может быть полезно для сохранения состояния фильтрации между различными запросами.
if ($save_qry) {
    $qry = $session->data['devices_qry'];
} else {
    // Иначе сохраняем текущий запрос в сессии для возможного использования в будущем.
    $session->data['devices_qry'] = $qry;
}

// Если запрос пуст, устанавливаем его как "1" для выбора всех записей.
// Это обеспечивает, что в любом случае будет выполнен запрос, даже если не было указано никаких фильтров.
if (!$qry) $qry = "1";

// Получаем общее количество устройств, не архивированных.
// Это делается для отображения общего количества доступных устройств в пользовательском интерфейсе.
$tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE devices.ARCHIVED!=1");
$out['TOTAL'] = (int)$tmp['TOTAL'];

$loc_title = '';
// Сортировка результатов по приоритету местоположения, названию местоположения, ID местоположения, типу устройства и названию устройства
$sortby_devices = "locations.PRIORITY DESC, locations.TITLE, devices.LOCATION_ID, devices.TYPE, devices.TITLE";
$out['SORTBY'] = $sortby_devices;
// РЕЗУЛЬТАТЫ ПОИСКА
// Выполняем SQL-запрос для получения результатов поиска устройств, включая информацию о местоположении каждого устройства.
// Запрос сортируется по заданным критериям сортировки.
$res = SQLSelect("SELECT devices.*, locations.TITLE as LOCATION_TITLE FROM devices LEFT JOIN locations ON devices.LOCATION_ID=locations.ID WHERE $qry ORDER BY " . $sortby_devices);

// Проверяем, есть ли результаты поиска.
if (isset($res[0])) {
    //paging($res, 100, $out); // search result paging
    // Подсчитываем общее количество найденных устройств.
    $total = count($res);
    $out['TOTAL_FOUND'] = $total;
    // Обрабатываем каждый результат поиска.
    for ($i = 0; $i < $total; $i++) {
        // Если название местоположения изменилось, устанавливаем флаг NEW_LOCATION.
        if ($res[$i]['LOCATION_TITLE'] != $loc_title) {
            $res[$i]['NEW_LOCATION'] = 1;
            $loc_title = $res[$i]['LOCATION_TITLE'];
        }
        // Если у устройства есть связанный объект, обрабатываем его.
        if ($res[$i]['LINKED_OBJECT']) {
            // Обработка устройства в зависимости от его типа.
            if ($res[$i]['TYPE'] == 'camera' || $res[$i]['TYPE'] == 'mark') {
                $processed = $this->processDevice($res[$i]['ID'], 'list');
            } else {
                $processed = $this->processDevice($res[$i]['ID']);
            }
            // Добавляем HTML-представление устройства.
            $res[$i]['HTML'] = $processed['HTML'];
            // Получаем свойства связанного объекта.
            $object_rec = SQLSelectOne("SELECT ID FROM objects WHERE TITLE='" . $res[$i]['LINKED_OBJECT'] . "'");
            if ($object_rec['ID']) {
                $properties = SQLSelect("SELECT pvalues.*, properties.TITLE as PROPERTY FROM pvalues LEFT JOIN properties ON properties.ID=pvalues.PROPERTY_ID WHERE pvalues.OBJECT_ID=" . $object_rec['ID'] . " AND pvalues.LINKED_MODULES!='' ORDER BY UPDATED");
                $totalp = count($properties);
                if ($totalp > 0) {
                    // Обрабатываем свойства, связанные с модулями.
                    $linked_modules = array();
                    for ($ip = 0; $ip < $totalp; $ip++) {
                        $tmp = explode(',', $properties[$ip]['LINKED_MODULES']);
                        $tmp = array_map('trim', $tmp);
                        foreach ($tmp as $linked_module) {
                            $linked_modules[$linked_module] = array('OBJECT' => $res[$i]['LINKED_OBJECT'], 'PROPERTY' => $properties[$ip]['PROPERTY']);
                        }
                    }
                    foreach ($linked_modules as $k => $v) {
                        $v['MODULE'] = $k;
                        $res[$i]['LINKED_MODULES'][] = $v;
                    }
                }
            }
        }
        // Добавляем название типа устройства.
        $res[$i]['TYPE_TITLE'] = $this->device_types[$res[$i]['TYPE']]['TITLE'];
        // Получаем количество связанных устройств.
        $linked = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices_linked WHERE (DEVICE1_ID=" . $res[$i]['ID'] . " OR DEVICE2_ID=" . $res[$i]['ID'] . ")");
        if ($linked['TOTAL']) {
            $res[$i]['LINKED'] = $linked['TOTAL'];
        }
        // Получаем количество методов устройства.
        $methods = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM methods WHERE CODE!='' AND OBJECT_ID=".(int)$object_rec['ID']);
        if ($methods['TOTAL']) {
            $res[$i]['METHODS'] = $methods['TOTAL'];
        }
    }
    // Сохраняем результаты поиска в массиве $out.
    $out['RESULT'] = $res;
}

// Подготовка к формированию списка типов устройств.
$types = array();

// Формирование списка типов устройств
// Проходим по всем типам устройств, определенным в $this->device_types.
foreach ($this->device_types as $k => $v) {
    // Проверяем, установлено ли название для типа устройства.
    if (isset($v['TITLE'])) {
        // Создаем запись для типа устройства с его названием и именем.
        $type_rec = array('NAME' => $k, 'TITLE' => $v['TITLE']);
        // Выполняем запрос к базе данных для подсчета количества устройств данного типа, которые не архивированы.
        $tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE TYPE='" . $k . "' AND ARCHIVED!=1");
        // Сохраняем количество устройств в записи типа устройства.
        $type_rec['TOTAL'] = (int)$tmp['TOTAL'];
        // Если количество устройств больше нуля, добавляем запись типа устройства в список.
        if ($type_rec['TOTAL'] > 0) {
            $types[] = $type_rec;
        }
    }
}
// Сортируем список типов устройств по названию.
usort($types, function ($a, $b) {
    return strcmp($a["TITLE"], $b["TITLE"]);
});
// Сохраняем отсортированный список типов устройств в массиве $out.
$out['TYPES'] = $types;

// Получение списка местоположений
// Выполняем запрос к базе данных для получения списка местоположений.
$locations = SQLSelect("SELECT ID, TITLE FROM locations ORDER BY TITLE+0");
$total = count($locations);
// Получение количества устройств для каждого местоположения
// Проходим по всем местоположениям и выполняем запрос к базе данных для подсчета количества устройств в каждом местоположении.
for ($i = 0; $i < $total; $i++) {
    $tmp = SQLSelectOne("SELECT COUNT(*) AS TOTAL FROM devices WHERE LOCATION_ID='" . $locations[$i]['ID'] . "'");
    // Сохраняем количество устройств в записи местоположения.
    $locations[$i]['TOTAL'] = (int)$tmp['TOTAL'];
}
// Сохраняем список местоположений с количеством устройств в массиве $out.
$out['LOCATIONS'] = $locations;

// Получение списка групп устройств
// Выполняем запрос к базе данных для получения списка групп устройств.
$groups = SQLSelect("SELECT * FROM devices_groups ORDER BY TITLE");
// Добавляем системные группы в список групп.
$groups[] = array('SYS_NAME' => 'Eco', 'TITLE' => LANG_DEVICES_GROUP_ECO);
$groups[] = array('SYS_NAME' => 'EcoOn', 'TITLE' => LANG_DEVICES_GROUP_ECO_ON);
$groups[] = array('SYS_NAME' => 'Sunrise', 'TITLE' => LANG_DEVICES_GROUP_SUNRISE);
$groups[] = array('SYS_NAME' => 'Sunset', 'TITLE' => LANG_DEVICES_GROUP_SUNSET);
$groups[] = array('SYS_NAME' => 'Night', 'TITLE' => LANG_DEVICES_GROUP_NIGHT);
// Сохраняем список групп устройств в массиве $out.
$out['GROUPS'] = $groups;