Разработка SEO оптимизированных высокопроизводительных фронтенд приложений на базе 1С-Битрикс.

Кастомные фильтры и сортировки списка элементов инфоблоков в GraphQL API

Артем Житник

Артем Житник

Типовая ситуация - нужно получить список элементов инфоблока. Но этот список бесполезен, если его нельзя фильтровать и сортировать в рамках логики проекта. Пока писал модуль завис на этом вопросе. Если решать в лоб, можно передать через API параметр содержащий объект фильтров и сортировок, который на бекенде транслировать в соответствующие параметры CIblockElement::GetList. Мне показалось неоправданным давать такие широкие возможности пользователю API.

Кстати, CIblockElement::GetList пришлось использовать из-за того что в нем можно выполнять сложные условия, в частности по свойствам, каталогу и т.д. Изначально я хотел обойтись простым ElementTable.

Как реализовать функционал фильтрации? А что если дать возможность владельцу сайта самому определять что фильтровать, какими параметрами API при этом пользоваться? Менять код модуля не вариант, остается реализовать событие, что я и сделал.

Пример, нужно добавить фильтрацию по активности и тегу, а также сортировку по времени активности. В /local/php_interface/init.php добавляем код:

use Bitrix\Main\EventManager;
use Bitrix\Main\Event;
use GraphQL\Type\Definition\InputObjectType;
use Rbx\GraphQL\Type\{Iblock, Main};

EventManager::getInstance()->addEventHandler("rbx.graphql", "OnAddQueryFilter", [MyClass::class, "addCustomFilters"]);

class MyClass {

    public static function addCustomFilters(Event $event) {
        $params = $event->getParameters();
        if ($params["QUERY_TYPE_CLASS"] != Iblock\IblockType::class) {
            return;
        }

        return [
            "INPUT_ARGS" => [
                "filters" => new InputObjectType([
                    "name" => "FilterInput",
                    "fields" => [
                        "active" => [
                            "type" => Main\Types::boolean(),
                            "description" => "Активность"
                        ],
                        "tag" => [
                            "type" => Main\Types::string(),
                            "description" => "Тег"
                        ],
                    ]
                ]),
                "orders" => new InputObjectType([
                    "name" => "OrderInput",
                    "fields" => [
                        "byActiveFrom" => [
                            "type" => Main\Types::string(),
                            "description" => "Сортировать по времени активности"
                        ],
                    ]
                ]),
            ],
            "GETLIST_FILTERS" => function (array $args): array {
                $filter = [];
                if (isset($args["filters"])) {
                    if (isset($args["filters"]["active"])) {
                        $filter += [
                            "=ACTIVE" => $args["filters"]["active"] ? "Y" : "N",
                        ];
                    }
                    if (isset($args["filters"]["tag"])) {
                        $filter += [
                            "%TAGS" => $args["filters"]["tag"],
                        ];
                    }
                }

                return $filter;
            },
            "GETLIST_ORDERS" => function (array $args): array {
                $orders = [];
                if (isset($args["orders"])) {
                    $byActiveFrom = $args["orders"]["byActiveFrom"] ?? null;
                    if (in_array($byActiveFrom, ["ASC", "DESC"])) {
                        $orders += [
                            "ACTIVE_FROM" => $byActiveFrom,
                        ];
                    }
                }

                return $orders;
            }
        ];
    }

}

Здесь мы обрабатываем событие OnAddQueryFilter. Определяем входящие параметры API INPUT_ARGS, а также используем заданные пользователем значения этих параметров в подготовке параметров для CIblockElement::GetList.

Для запроса к API:

{
  iblock {
    blog {
      getElementList(filters: {active: true}, orders: {byActiveFrom: "ASC"}) {
        id
        activeFrom
        active
      }
    }
  }
}

Получим ответ:

{
  "data": {
    "iblock": {
      "blog": {
        "getElementList": [
          {
            "id": "33",
            "activeFrom": "2021-09-29T12:23:00+09:00",
            "active": true
          },
          {
            "id": "35",
            "activeFrom": "2021-09-30T15:10:12+09:00",
            "active": true
          },
          {
            "id": "36",
            "activeFrom": "2021-10-02T19:55:22+09:00",
            "active": true
          }         
        ]
      }
    }
  }
}

Таким образом можно реализовать любую логику необходимую в рамках проекта.

    GraphQL API модуль для Битрикс
    GraphQL
    Битрикс

©2022 ReactiveBx работает на «1С-Битрикс: Управление сайтом» и Next.js