U
U
UnderDog322022-01-31 17:38:48
1C-Bitrix
UnderDog32, 2022-01-31 17:38:48

How to write the last changes to a property in Bitrix?

There is a multiple property "changes" of type "string". It is necessary to add the value of this property for any change in the element, for example:

12/31/2021 17:32 (Anatoly Testovy): a change has been made in the "Processor manufacturer" field (AMD --> Intel).

Those. you need to enter the date and time of the change, the user, the old value, the new value.

I understand what needs to be done through OnIBlockElementUpdate - but it's not clear how to get the values ​​​​of fields and properties from the ar_wf_element and newFields arrays.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
R
Roman, 2022-01-31
@UnderDog32

You need to hang a handler on OnBeforeIBlockElementUpdate , because you cannot do CIBlockElement:Update() during OnIBlockElementUpdate (this will cause a cyclic call of the handler). With OnIBlockElementUpdate , the values ​​in changes will need to be written via SetPropertyValuesEx . Although with OnIBlockElementUpdate / SetPropertyValuesEx the option is quite working.
Example code with 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);
            }
        }
    }
}

The solution is so-so, because:
a) multiple property values
​​b) it will work ugly with values ​​from directories
c) hardcoded property IDs and their headers
d) the username is missing
But, as a start for adding features, I think
PS: Store product changes in the product itself, the idea is so-so, it’s better to have a separate table with quick reading and writing (HL-infblocks are fine) and make a custom output of the history in the admin panel in the product editing card

M
Maxim Tkachev, 2022-01-31
@Real_Farmer

PROPERTY_UF_ - all properties
$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'];
}
if you need to get values ​​from the list
$property_enums = CIBlockPropertyEnum::GetList([], array("IBLOCK_ID" => $el_fieds['IBLOCK_ID'], "CODE" => "SHILDIK"));

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question