@UnderDog32

Как в Битриксе записать последние изменения в свойство?

Имеется множественное свойство "changes" тип "строка". Необходимо при любом изменении элемента, добавлять значение этого свойства, например:

31.12.2021 17:32 (Анатолий Тестовый): внесено изменение в поле "Производитель процессора" (AMD --> Intel).

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

Я так понимаю, что нужно делать через OnIBlockElementUpdate - но не понятно, как получить из массивов ar_wf_element и newFields значения полей и свойств.
  • Вопрос задан
  • 901 просмотр
Решения вопроса 1
@r_zaycev
Нужно навешать обработчик на OnBeforeIBlockElementUpdate, потому что при OnIBlockElementUpdate нельзя делать CIBlockElement:Update() (это вызовет циклический вызов обработчика). При OnIBlockElementUpdate значения в changes нужно будет писать через SetPropertyValuesEx. Хотя с OnIBlockElementUpdate/SetPropertyValuesEx вариант вполне рабочий.

Примерный код с OnBeforeIBlockElementUpdate:

<?php

AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", ["MyClass", "OnBeforeIBlockElementUpdateHandler"]);

class MyClass {
    public static function OnBeforeIBlockElementUpdateHandler(&$arFields)
    {
        if ($arFields['IBLOCK_ID'] == 1) { // Проверяем на нужный ИБ
            $userId = $arFields["MODIFIED_BY"];
            $propValues = $arFields["PROPERTY_VALUES"];
            $propMap = [ // Массив полей, за которым следим в виде ID св-ва => тайтл
                8 => "Some prop",
            ];
            $changesPropId = 9; // ID свойства changes

            $resOldElem = CIBlockElement::GetList(
                [],
                ["IBLOCK_ID" => $arFields["IBLOCK_ID"], "ID" => $arFields["ID"]],
                false,
                false,
                array_map(function($propId) {
                    return "PROPERTY_{$propId}";
                }, array_keys($propMap))
            )->Fetch();

            $newChanges = [];

            foreach ($propMap as $propId => $propTitle) {
                $propValueKey = "PROPERTY_{$propId}_VALUE";
                $oldPropValue = $resOldElem[$propValueKey];
                $newPropValue = $propValues[$propId][array_key_first($propValues[$propId])]["VALUE"]; // Для множественных свойств нужна своя логика обработки

                if ($oldPropValue != $newPropValue) { // Если значение из справочника, то его надо разыменовать, достать значение из ИБ/Хайлоад ИБ
                    $newChanges[] = "Юзер {$userId} изменил {$propTitle}: {$oldPropValue} -> {$newPropValue}";
                }
            }

            if (!empty($newChanges)) {
                $arFields['PROPERTY_VALUES'][$changesPropId] = array_merge($arFields['PROPERTY_VALUES'][$changesPropId], $newChanges);
            }
        }
    }
}


Решение так себе, потому что:
a) множественных значений свойств
b) некрасиво сработает со значениями из справочников
c) захардкоженные ID свойств и их заголовки
d) не достает имя пользователя

Но, как старт для запила фичи дает, я думаю

PS: Хранить изменения товара в самом товаре так себе идея, лучше завести отдельную таблицу с быстрым чтением и записью (HL-инфблоки подойдут) и сделать кастомный вывод истории в админке в карточке редактирования товара
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Real_Fermer
@Real_Fermer
Программист PHP
PROPERTY_UF_ - все свойства

$fields=['ID','ACTIVE',''PROPERTY_UF_*'];
$obElem = CIBlockElement::GetList(array(), $filter, false, false, $fields);
while ($arElem = $obElem->GetNext()) {
$elem[]=$arElem;
$SHILDIK_NAME = $arElem['PROPERTY_UF_ACTION_SHILDIK_VALUE'];
}

если нужно получить значения из списка

$property_enums = CIBlockPropertyEnum::GetList([], array("IBLOCK_ID" => $el_fieds['IBLOCK_ID'], "CODE" => "SHILDIK"));
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы