1

Свои условия в скидках Битрикса

В 1С-Битрикс:Управление сайтом (БУС) есть шикарный редактор условий для скидок. Он действительно очень крутой и гибкий. И всё там делается мышью, для простых людей.

Несколько примеров:

metla

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

Например, нужно применить скидку для пользователя, дополнительное поле которого равняется заданному значению.

Как это сделать?

discount

Там, где я стыдливо закрасил строку, должно быть UF_USER_FIELD.

Будем работать в /php_interface/init.php для упрощения примера. Но я бы поместил этот код в свой модуль, в отдельный файл.

Нам нужно сделать класс с родителем CCatalogCondCtrlComplex и определить в нем методы GetClassName, GetControlID. GetClassName — возвращает название класса, GetControlID — уникальный ID для наших условий.

class CatalogCondCtrlUserProps extends \CCatalogCondCtrlComplex
{
    public static function GetClassName()
    {
        return __CLASS__;
    }
    /**
     * @return string|array
     */
    public static function GetControlID()
    {
        return array('CondUser', 'CondUserDestinationStore');
    }
}

Отлично, база готова.

Следующим шагом, нужно описать метод, который отдает структуру со списком наших условий GetControlShow:

    public static function GetControlShow($arParams)
    {
        $arControls = static::GetControls();
        $arResult = array(
            'controlgroup' => true,
            'group' =>  false,
            'label' => 'Поля Пользователя',
            'showIn' => static::GetShowIn($arParams['SHOW_IN_GROUPS']),
            'children' => array()
        );
        foreach ($arControls as &$arOneControl)
        {
            $arResult['children'][] = array(
                'controlId' => $arOneControl['ID'],
                'group' => false,
                'label' => $arOneControl['LABEL'],
                'showIn' => static::GetShowIn($arParams['SHOW_IN_GROUPS']),
                'control' => array(
                    array(
                        'id' => 'prefix',
                        'type' => 'prefix',
                        'text' => $arOneControl['PREFIX']
                    ),
                    static::GetLogicAtom($arOneControl['LOGIC']),
                    static::GetValueAtom($arOneControl['JS_VALUE'])
                )
            );
        }
        if (isset($arOneControl))
            unset($arOneControl);

        return $arResult;
    }

    /**
     * @param bool|string $strControlID
     * @return bool|array
     */
    public static function GetControls($strControlID = false)
    {
        $arControlList = array(
            'CondUser' => array(
                'ID' => 'CondUser',
                'FIELD' => 'ID',
                'FIELD_TYPE' => 'int',
                'LABEL' => 'ID Пользователя',
                'PREFIX' => 'поле ID Пользователя',
                'LOGIC' => static::GetLogic(array(BT_COND_LOGIC_EQ, BT_COND_LOGIC_NOT_EQ)),
                'JS_VALUE' => array(
                    'type' => 'input'
                ),
                'PHP_VALUE' => ''
            ),
            'CondUserDestinationStore' => array(
                'ID' => 'CondUserDestinationStore',
                'FIELD' => ''UF_USER_FIELD',
                'FIELD_TYPE' => 'string',
                'LABEL' => 'UF_USER_FIELD Пользователя',
                'PREFIX' => 'поле 'UF_USER_FIELD Пользователя',
                'LOGIC' => static::GetLogic(array(BT_COND_LOGIC_EQ, BT_COND_LOGIC_NOT_EQ)),
                'JS_VALUE' => array(
                    'type' => 'input'
                ),
                'PHP_VALUE' => ''
            ),
        );

        foreach ($arControlList as &$control)
        {
            if (!isset($control['PARENT']))
                $control['PARENT'] = true;

            $control['EXIST_HANDLER'] = 'Y';

            $control['MODULE_ID'] = 'mymodule';

            $control['MULTIPLE'] = 'N';
            $control['GROUP'] = 'N';
        }
        unset($control);

        if ($strControlID === false)
        {
            return $arControlList;
        }
        elseif (isset($arControlList[$strControlID]))
        {
            return $arControlList[$strControlID];
        }
        else
        {
            return false;
        }
    }

В этой функции мы создаем массив с описанием наших условий. В данном случае мы создаем группу «Поля пользователя» и заполняем ее информацией об условиях, которые мы получаем в функции GetControls. В GetControls мы описываем 2 условия: «ID пользователя» и «UF_USER_FIELD Пользователя».

Осталось 2 метода Generate и ApplyValues.

Метод Generate нужен, чтобы сгенерировать строковое представление условия. А ApplyValues, судя по названию, отвечает за подстановку конкретных значений в момент исполнения в строковое представление условия.

Магия происходит в строке

$strField = "\\CatalogCondCtrlUserProps::checkUserField('{$arControl['FIELD']}', '{$arLogic['OP'][$arControl['MULTIPLE']]}', '{$arValues['value']}')";

Здесь мы указываем, что в момент исполнения условия нужно вызвать функцию нашего класса checkUserField. Сама функция выглядит следующим образом:

    public static function checkUserField($strUserField, $strCond, $strValue)
    {
        global $USER;
        $arUser = $USER->GetByID($USER->GetID())->Fetch();

        $field = $arUser[$strUserField];

        return str_replace(array('#FIELD#', '#VALUE#'), array($field, $strValue), $strCond);
    }

На вход мы получаем условие в строковом виде, условие (у нас «меньше», «равно» или «больше») и значение условия (в нашем случае код поля пользователя ID или UF_USER_FIELD). Функция расставляет поля по местам, тем самым подготавливает условия к eval’у. Возвращаемое значение в момент исполнения примет вид примерно такой: «1 = 1». Это выражение отдается в механизмом условий Битрикса.

И под конец этого текста, а в коде первым делом. Самое главное, подключаем наш класс к обработке события OnCondCatControlBuildList модуля catalog:

AddEventHandler("catalog", "OnCondCatControlBuildList", Array("CatalogCondCtrlUserProps", "GetControlDescr"));

Функция GetControlDescr реализована у родителя нашего класса, так что вмешиваться в ее работу не нужно.

Напоследок, рекомендую заглянуть в код в файле /bitrix/modules/catalog/general/catalog_cond.php. В этом файле реализованы штатные условия. На базе этого кода был написан и весь код наших кастомных условий.

Ссылки по теме:

  • https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=42&LESSON_ID=5355&LESSON_PATH=3912.5040.5355
  • http://olegorestov.ru/this/discount_contolrs/
  • Весь код:

    One Comment

    1. Здравствуйте!
      Ваш код не работает

    Добавить комментарий

    Ваш e-mail не будет опубликован. Обязательные поля помечены *