Наш блог
Показать рубрики

Добавление в результат поиска 1С-Битрикс неактивных элементов инфоблока

Назад к списку статей
Добавление в результат поиска 1С-Битрикс неактивных элементов инфоблока
В этом посте мы рассмотрим как заставить 1С-Битрикс искать по неактивным товарам и предложениям. По умолчанию в поисковый индекс сайта из модуля "Информационные блоки" попадают только активные элементы. Мы столкнулись с задачей сделать так, чтоб пользователь мог найти в поиске магазина также и неактивные товары, так как такие товары отображались на сайте и их можно было купить, а флаг активности использовался нестандартно.

Приступив к выполнению задачи, было обнаружено, что при индексации инфоблоков в коде ядра жестко прописан фильтр по активным товарам и нет никакой настройки чтоб это отключить. Но был найден способ как это обойти без кастомизации файлов ядра с использованием обработчиков событий.

Решение

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

По поводу индексации в документации написано:

Для того, чтобы модуль был переиндексирован, он должен предоставить соответствующий метод, который должен быть зарегистрирован в системе событий как обработчик события OnReIndex модуля "search".

Перейдя в установочный класс модуля iblock мы увидим регистрацию этого обработчика:

RegisterModuleDependences(
    "search",
    "OnReindex",
    "iblock",
    "CIBlock",
    "OnSearchReindex"
);

Нам нужно его отменить. Для этого мы регистрируем обработчик события OnBeforeProlog, в котором мы отменим стандартный обработчик переиндексации и подключим свой. Вот так:


    Файл init.php

    AddEventHandler(
        "main",
        "OnBeforeProlog",
        "changeIblockReindexHandler"
    );

    /**
     * Disables standard reindex function for Iblock module and registers custom functions
     */
    function changeIblockReindexHandler()
    {
        UnRegisterModuleDependences(
            "search",
            "OnReindex",
            "iblock",
            "CIBlock",
            "OnSearchReindex"
        );
        RegisterModuleDependences(
            "search",
            "OnReindex",
            "iblock",
            "\\Epages\\Search\\CustomReindex",
            "OnSearchReindex"
        );
    }

В этой функции мы регистрируем свой обработчик, который есть методом класса, наследуемым от CIBlock. Этот метод полностью копирует код метода CIBlock::OnSearchReindex, только в выборке по элементам удален фильтр по активности. Вот оригинальный запрос:


    $strSql =
        "SELECT BE.ID, BE.NAME, BE.TAGS, ".
        "	".$DB->DateToCharFunction("BE.ACTIVE_FROM")." as DATE_FROM, ".
        "	".$DB->DateToCharFunction("BE.ACTIVE_TO")." as DATE_TO, ".
        "	".$DB->DateToCharFunction("BE.TIMESTAMP_X")." as LAST_MODIFIED, ".
        "	BE.PREVIEW_TEXT_TYPE, BE.PREVIEW_TEXT, ".
        "	BE.DETAIL_TEXT_TYPE, BE.DETAIL_TEXT, ".
        "	BE.XML_ID as EXTERNAL_ID, BE.CODE, ".
        "	BE.IBLOCK_SECTION_ID ".
        "FROM b_iblock_element BE ".
        "WHERE BE.IBLOCK_ID=".$IBLOCK_ID." ".
        "	AND BE.ACTIVE='Y' ".
        CIBlockElement::WF_GetSqlLimit("BE.", "N").
        $strNSFilter2.
        "ORDER BY BE.ID ";

В замененном запросе уделена строка AND BE.ACTIVE='Y'. Далее нужно переиндексировать модуль инфоблоков и в поиске будут видны неактивные товары.

Полезные ссылки

Полный код кастомизированного класса


namespace Epages\Search;

use \CIBlock;
use \CIBlockElement;
use \CSearch;
use \CIBlockProperty;
use \COption;
use \CIBlockElementRights;
use \CIBlockSectionRights;

/**
 * Class CustomReindex
 * @package Epages\Search
 */
class CustomReindex extends CIBlock
{
    /**
     * Difference from original method - deactivated elements added into reindexing
     * See select from b_iblock_element table block
     *
     * @param array  $NS
     * @param null   $oCallback
     * @param string $callback_method
     * @return array|bool|string
     */
    function OnSearchReindex($NS=Array(), $oCallback=NULL, $callback_method="")
    {
        /** @global CUserTypeManager $USER_FIELD_MANAGER */
        global $USER_FIELD_MANAGER;
        /** $global CDatabase $DB */
        global $DB;

        $strNSJoin1 = "";
        $strNSFilter1 = "";
        $strNSFilter2 = "";
        $strNSFilter3 = "";
        $arResult = Array();
        if($NS["MODULE"]=="iblock" && strlen($NS["ID"])>0)
        {
            $arrTmp = explode(".", $NS["ID"]);
            $strNSFilter1 = " AND B.ID>=".IntVal($arrTmp[0])." ";
            if(substr($arrTmp[1], 0, 1)!='S')
            {
                $strNSFilter2 = " AND BE.ID>".IntVal($arrTmp[1])." ";
            }
            else
            {
                $strNSFilter2 = false;
                $strNSFilter3 = " AND BS.ID>".IntVal(substr($arrTmp[1], 1))." ";
            }
        }
        if($NS["SITE_ID"]!="")
        {
            $strNSJoin1 .= " INNER JOIN b_iblock_site BS ON BS.IBLOCK_ID=B.ID ";
            $strNSFilter1 .= " AND BS.SITE_ID='".$DB->ForSQL($NS["SITE_ID"])."' ";
        }
        $strSql = "
			SELECT B.ID, B.IBLOCK_TYPE_ID, B.INDEX_ELEMENT, B.INDEX_SECTION, B.RIGHTS_MODE,
				B.IBLOCK_TYPE_ID, B.CODE as IBLOCK_CODE, B.XML_ID as IBLOCK_EXTERNAL_ID,
				B.SOCNET_GROUP_ID
			FROM b_iblock B
			".$strNSJoin1."
			WHERE B.ACTIVE = 'Y'
				AND (B.INDEX_ELEMENT='Y' OR B.INDEX_SECTION='Y')
				".$strNSFilter1."
			ORDER BY B.ID
		";

        $dbrIBlock = $DB->Query($strSql);
        while($arIBlock = $dbrIBlock->Fetch())
        {
            $IBLOCK_ID = $arIBlock["ID"];

            $arGroups = Array();

            $strSql =
                "SELECT GROUP_ID ".
                "FROM b_iblock_group ".
                "WHERE IBLOCK_ID= ".$IBLOCK_ID." ".
                "	AND PERMISSION>='R' ".
                "	AND GROUP_ID>1 ".
                "ORDER BY GROUP_ID";

            $dbrIBlockGroup = $DB->Query($strSql);
            while($arIBlockGroup = $dbrIBlockGroup->Fetch())
            {
                $arGroups[] = $arIBlockGroup["GROUP_ID"];
                if($arIBlockGroup["GROUP_ID"]==2) break;
            }

            $arSITE = Array();
            $strSql =
                "SELECT SITE_ID ".
                "FROM b_iblock_site ".
                "WHERE IBLOCK_ID= ".$IBLOCK_ID;

            $dbrIBlockSite = $DB->Query($strSql);
            while($arIBlockSite = $dbrIBlockSite->Fetch())
                $arSITE[] = $arIBlockSite["SITE_ID"];

            if($arIBlock["INDEX_ELEMENT"]=='Y' && ($strNSFilter2 !== false))
            {
                $strSql =
                    "SELECT BE.ID, BE.NAME, BE.TAGS, ".
                    "	".$DB->DateToCharFunction("BE.ACTIVE_FROM")." as DATE_FROM, ".
                    "	".$DB->DateToCharFunction("BE.ACTIVE_TO")." as DATE_TO, ".
                    "	".$DB->DateToCharFunction("BE.TIMESTAMP_X")." as LAST_MODIFIED, ".
                    "	BE.PREVIEW_TEXT_TYPE, BE.PREVIEW_TEXT, ".
                    "	BE.DETAIL_TEXT_TYPE, BE.DETAIL_TEXT, ".
                    "	BE.XML_ID as EXTERNAL_ID, BE.CODE, ".
                    "	BE.IBLOCK_SECTION_ID ".
                    "FROM b_iblock_element BE ".
                    "WHERE BE.IBLOCK_ID=".$IBLOCK_ID." ".
                    CIBlockElement::WF_GetSqlLimit("BE.", "N").
                    $strNSFilter2.
                    "ORDER BY BE.ID ";

                //For MySQL we have to solve client out of memory
                //problem by limiting the query
                if($DB->type=="MYSQL")
                {
                    $limit = 1000;
                    $strSql .= " LIMIT ".$limit;
                }
                else
                {
                    $limit = false;
                }

                $dbrIBlockElement = $DB->Query($strSql);
                while($arIBlockElement = $dbrIBlockElement->Fetch())
                {
                    $DETAIL_URL =
                        "=ID=".$arIBlockElement["ID"].
                        "&EXTERNAL_ID=".$arIBlockElement["EXTERNAL_ID"].
                        "&CODE=".$arIBlockElement["CODE"].
                        "&IBLOCK_SECTION_ID=".$arIBlockElement["IBLOCK_SECTION_ID"].
                        "&IBLOCK_TYPE_ID=".$arIBlock["IBLOCK_TYPE_ID"].
                        "&IBLOCK_ID=".$IBLOCK_ID.
                        "&IBLOCK_CODE=".$arIBlock["IBLOCK_CODE"].
                        "&IBLOCK_EXTERNAL_ID=".$arIBlock["IBLOCK_EXTERNAL_ID"];

                    $BODY =
                        ($arIBlockElement["PREVIEW_TEXT_TYPE"]=="html" ?
                            CSearch::KillTags($arIBlockElement["PREVIEW_TEXT"]) :
                            $arIBlockElement["PREVIEW_TEXT"]
                        )."\r\n".
                        ($arIBlockElement["DETAIL_TEXT_TYPE"]=="html" ?
                            CSearch::KillTags($arIBlockElement["DETAIL_TEXT"]) :
                            $arIBlockElement["DETAIL_TEXT"]
                        );

                    $dbrProperties = CIBlockElement::GetProperty($IBLOCK_ID, $arIBlockElement["ID"], "sort", "asc", array("ACTIVE"=>"Y", "SEARCHABLE"=>"Y"));
                    while($arProperties = $dbrProperties->Fetch())
                    {
                        $BODY .= "\r\n";

                        if(strlen($arProperties["USER_TYPE"]) > 0)
                            $UserType = CIBlockProperty::GetUserType($arProperties["USER_TYPE"]);
                        else
                            $UserType = array();

                        if(array_key_exists("GetSearchContent", $UserType))
                        {
                            $BODY .= CSearch::KillTags(
                                call_user_func_array($UserType["GetSearchContent"],
                                    array(
                                        $arProperties,
                                        array("VALUE" => $arProperties["VALUE"]),
                                        array(),
                                    )
                                )
                            );
                        }
                        elseif(array_key_exists("GetPublicViewHTML", $UserType))
                        {
                            $BODY .= CSearch::KillTags(
                                call_user_func_array($UserType["GetPublicViewHTML"],
                                    array(
                                        $arProperties,
                                        array("VALUE" => $arProperties["VALUE"]),
                                        array(),
                                    )
                                )
                            );
                        }
                        elseif($arProperties["PROPERTY_TYPE"]=='L')
                        {
                            $BODY .= $arProperties["VALUE_ENUM"];
                        }
                        elseif($arProperties["PROPERTY_TYPE"]=='F')
                        {
                            $arFile = CIBlockElement::__GetFileContent($arProperties["VALUE"]);
                            if(is_array($arFile))
                            {
                                $BODY .= $arFile["CONTENT"];
                                $arIBlockElement["TAGS"] .= ",".$arFile["PROPERTIES"][COption::GetOptionString("search", "page_tag_property")];
                            }
                        }
                        else
                        {
                            $BODY .= $arProperties["VALUE"];
                        }
                    }

                    if($arIBlock["RIGHTS_MODE"] !== "E")
                        $arPermissions = $arGroups;
                    else
                    {
                        $obElementRights = new CIBlockElementRights($IBLOCK_ID, $arIBlockElement["ID"]);
                        $arPermissions = $obElementRights->GetGroups(array("element_read"));
                    }

                    $Result = array(
                        "ID" => $arIBlockElement["ID"],
                        "LAST_MODIFIED" => (strlen($arIBlockElement["DATE_FROM"])>0? $arIBlockElement["DATE_FROM"]: $arIBlockElement["LAST_MODIFIED"]),
                        "TITLE" => $arIBlockElement["NAME"],
                        "BODY" => $BODY,
                        "TAGS" => $arIBlockElement["TAGS"],
                        "SITE_ID" => $arSITE,
                        "PARAM1" => $arIBlock["IBLOCK_TYPE_ID"],
                        "PARAM2" => $IBLOCK_ID,
                        "DATE_FROM" => (strlen($arIBlockElement["DATE_FROM"])>0? $arIBlockElement["DATE_FROM"] : false),
                        "DATE_TO" => (strlen($arIBlockElement["DATE_TO"])>0? $arIBlockElement["DATE_TO"] : false),
                        "PERMISSIONS" => $arPermissions,
                        "URL" => $DETAIL_URL
                    );

                    if ($arIBlock["SOCNET_GROUP_ID"] > 0)
                        $Result["PARAMS"] = array(
                            "socnet_group" => $arIBlock["SOCNET_GROUP_ID"],
                        );

                    if($oCallback)
                    {
                        $res = call_user_func(array($oCallback, $callback_method), $Result);
                        if(!$res)
                            return $IBLOCK_ID.".".$arIBlockElement["ID"];
                    }
                    else
                    {
                        $arResult[] = $Result;
                    }

                    if($limit !== false)
                    {
                        $limit--;
                        if($limit <= 0)
                            return $IBLOCK_ID.".".$arIBlockElement["ID"];
                    }
                }
            }

            if($arIBlock["INDEX_SECTION"]=='Y')
            {
                $strSql =
                    "SELECT BS.ID, BS.NAME, ".
                    "	".$DB->DateToCharFunction("BS.TIMESTAMP_X")." as LAST_MODIFIED, ".
                    "	BS.DESCRIPTION_TYPE, BS.DESCRIPTION, BS.XML_ID as EXTERNAL_ID, BS.CODE, ".
                    "	BS.IBLOCK_ID ".
                    "FROM b_iblock_section BS ".
                    "WHERE BS.IBLOCK_ID=".$IBLOCK_ID." ".
                    "	AND BS.GLOBAL_ACTIVE='Y' ".
                    $strNSFilter3.
                    "ORDER BY BS.ID ";

                $dbrIBlockSection = $DB->Query($strSql);
                while($arIBlockSection = $dbrIBlockSection->Fetch())
                {
                    $DETAIL_URL =
                        "=ID=".$arIBlockSection["ID"].
                        "&EXTERNAL_ID=".$arIBlockSection["EXTERNAL_ID"].
                        "&CODE=".$arIBlockSection["CODE"].
                        "&IBLOCK_TYPE_ID=".$arIBlock["IBLOCK_TYPE_ID"].
                        "&IBLOCK_ID=".$arIBlockSection["IBLOCK_ID"].
                        "&IBLOCK_CODE=".$arIBlock["IBLOCK_CODE"].
                        "&IBLOCK_EXTERNAL_ID=".$arIBlock["IBLOCK_EXTERNAL_ID"];
                    $BODY =
                        ($arIBlockSection["DESCRIPTION_TYPE"]=="html" ?
                            CSearch::KillTags($arIBlockSection["DESCRIPTION"])
                            :
                            $arIBlockSection["DESCRIPTION"]
                        );
                    $BODY .= $USER_FIELD_MANAGER->OnSearchIndex("IBLOCK_".$arIBlockSection["IBLOCK_ID"]."_SECTION", $arIBlockSection["ID"]);

                    if($arIBlock["RIGHTS_MODE"] !== "E")
                        $arPermissions = $arGroups;
                    else
                    {
                        $obSectionRights = new CIBlockSectionRights($IBLOCK_ID, $arIBlockSection["ID"]);
                        $arPermissions = $obSectionRights->GetGroups(array("section_read"));
                    }

                    $Result = Array(
                        "ID" => "S".$arIBlockSection["ID"],
                        "LAST_MODIFIED" => $arIBlockSection["LAST_MODIFIED"],
                        "TITLE" => $arIBlockSection["NAME"],
                        "BODY" => $BODY,
                        "SITE_ID" => $arSITE,
                        "PARAM1" => $arIBlock["IBLOCK_TYPE_ID"],
                        "PARAM2" => $IBLOCK_ID,
                        "PERMISSIONS" => $arPermissions,
                        "URL" => $DETAIL_URL,
                    );

                    if ($arIBlock["SOCNET_GROUP_ID"] > 0)
                        $Result["PARAMS"] = array(
                            "socnet_group" => $arIBlock["SOCNET_GROUP_ID"],
                        );

                    if($oCallback)
                    {
                        $res = call_user_func(array($oCallback, $callback_method), $Result);
                        if(!$res)
                            return $IBLOCK_ID.".S".$arIBlockSection["ID"];
                    }
                    else
                    {
                        $arResult[] = $Result;
                    }
                }
            }
            $strNSFilter2="";
            $strNSFilter3="";
        }

        if($oCallback)
            return false;

        return $arResult;
    }
}
Назад к списку статей
Подпишись на наш блог: