Пишем сложный фильтр в 1С Битрикс

Для компонента просмотра статистики по прохождению тестов, мне нужно было реализовать фильтр результатов по самым неожиданным параметром. Самым неожиданным оказался поддомен, к которому относится тестируемый. Вы сейчас скажете, да что тут сложного...

Автор . Дата: 07.12.2014

Для компонента просмотра статистики по прохождению тестов, мне нужно было реализовать фильтр результатов по самым неожиданным параметром. Самым неожиданным оказался поддомен, к которому относится тестируемый. Вы сейчас скажете, да что тут сложного, там все просто, но спешу вас огорчить, все оказалось весьма запутанно.

Проблема оказалась в том, что пользователи напрямую не связаны с поддоменами сайта. Сами поддомены хранятся в инфоблоке. Города содержатся в другом инфоблоке, у которых есть свойство, в котором описаны поддомены, к которым они принадлежат. Магазины содержатся ещё в одном инфоблоке, и у них есть свойство, в котором описано, к каким городам они принадлежат. А уже у магазинов есть свойство, в котором описаны пользователи, которые принадлежат данному магазину. Чувствуете весь размах трагедии? Ну а теперь посмотрим, как же отфильтровал пользователей в такой длинной цепочке.

Входящим массивом для нас является multi select, в котором выбирают поддомены, пользователей которых нужно отобразить. Сначала проверяем, является ли массивом наша переменная:

    $arStoresPropsForSubdomain = array();
    if (is_array($_GET['subdomains']))
    {

Это нам нужно для того, чтобы определить, включен ли фильтр. Если там пусто, то мы не будем выполнять сложные запросы, и просто выберем всех пользователей прошедших тестирование. Затем мы выберем информацию по поддоменам, которые переданы в массиве $_GET['subdomain']:

        $arSubdomains = array();
        $rsData = CIBlockElement::GetList(array(), array('IBLOCK_ID' => 19, 'ID' => $_GET['subdomains']), false, false, array('ID', 'XML_ID'));
        while ($subdomain = $rsData->Fetch())
        {
            $arSubdomains[] = $subdomain;
        }

В функции CIBlockElement::GetList можно просто передать массив элементов, без каких-либо специальных обозначений. После этого мы выберем все города, которые принадлежат поддомену:

        $arCities = array();
        $rsData = CIBlockElement::GetList(array(), array('IBLOCK_ID' => 7), false, false, array('ID', 'XML_ID', 'NAME'));
        while ($city = $rsData->Fetch())
        {
            $dbStoresProp = CIBlockElement::GetProperty(7, $city['ID'], array(), array('CODE' => 'SUBDOMAIN'));

            while ($prop = $dbStoresProp->GetNext())
            {
                foreach ($arSubdomains as $subdomain)
                {
                    if ($prop['VALUE'] === $subdomain['XML_ID'])
                        $arCities[] = $city;
                }
            }
        }

Здесь мы выбираем все города, и свойства с кодом SUBDOMAIN. Затем мы проходимся по этим свойствам и смотрим, принадлежат ли эти города к какому-нибудь из выбранных поддоменов. Тоже самое делаем и для магазинов:

        $arStores = array();
        $rsData = CIBlockElement::GetList(array(), array('IBLOCK_ID' => 28), false, false, array('ID', 'NAME'));
        while ($store = $rsData->Fetch())
        {
            $dbStoresProp = CIBlockElement::GetProperty(28, $store['ID'], array(), array('CODE' => 'CITY'));

            while ($prop = $dbStoresProp->GetNext())
            {
                foreach ($arCities as $city)
                {
                    if ($prop['VALUE'] === $city['XML_ID'])
                    {
                        $arStores[] = $store;
                    }
                }
            }
        }

Мы получили массив, в котором находятся все магазины принадлежащие выбранным поддоменам. После этого мы получаем список пользователей, которые принадлежат к выбранным поддоменам:

        foreach ($arStores as $store)
        {
            $dbStoresProp = CIBlockElement::GetProperty(28, $store['ID'], array(), array("CODE" => "SHOP_ASSISTANT"));

            while ($prop = $dbStoresProp->GetNext())
            {
                $arStoresPropsForSubdomain[] = $prop['VALUE'];
            }
        }
    }

и закрываем самое первое условие. Теперь мы можем отфильтровать результаты теста. Для начала, выберем результаты теста:

    $rsData = CTestAttempt::GetList(array("ID" => "ASC"), array('TEST_ID' => $arTest['ID']));
    while ($arAttempt = $rsData->GetNext())
    {
        if (is_array($_GET['subdomains']))
        {
            foreach ($arStoresPropsForSubdomain as $arStoresPropForSubdomain)
            {
                if ($arStoresPropForSubdomain == $userId)
                {
                    $arTest['ASC_ATTEMPTS'][] = $arAttempt;
                }
            }
        }
        else
            $arTest['ASC_ATTEMPTS'][] = $arAttempt;
    }

Тут все просто: когда мы обрабатываем результаты теста, мы проверяем, находится ли испытуемый в массиве с списком пользователей из фильтра. Если такой пользователь найден, то добавляем результаты теста в массив, который будет потом выводить в шаблоне компонента.


comments powered by HyperComments