В 1С-Битрикс:Управление сайтом (БУС) есть шикарный редактор условий для скидок. Он действительно очень крутой и гибкий. И всё там делается мышью, для простых людей.
Несколько примеров:
Но, как это обычно бывает в реальной жизни, бывают случаи когда не хватает имеющихся в редакторе условий.
Например, нужно применить скидку для пользователя, дополнительное поле которого равняется заданному значению.
Как это сделать?
Там, где я стыдливо закрасил строку, должно быть 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. В этом файле реализованы штатные условия. На базе этого кода был написан и весь код наших кастомных условий.
Ссылки по теме:
Весь код:
Здравствуйте!
Ваш код не работает