Y
Y
Yuriy2021-04-02 13:54:52
1C-Bitrix
Yuriy, 2021-04-02 13:54:52

Bitrix property change CIBlockElement::SetPropertyValuesEx?

Tell me, have you encountered such a problem with writing values ​​for properties of the STRING type, but it is possible that LIST has the same problem, in general, this problem concerns exactly the values ​​\u200b\u200bof which STRING

The whole problem boils down to the fact that in the CIBlockElement::SetPropertyValuesEx method the array ["CODE"= >"Value"] to add, change property value and manage other fields of type VALUE_ENUM, VALUE_NUM is not possible from this method, tried like this ["CODE"=["VALUE"=>Value, "VALUE_ENUM"=>0, "VALUE_NUM "=>0]] does not perceive, well, it's understandable because in the CIBlockElement::SetPropertyValuesEx method, only VALUE and DESCRIPTION can be defined in $PROPERTY_VALUES, and VALUE_ENUM, VALUE_NUM are taken from VALUE

and that's actually what the problem is, all values ​​from VALUE are converted to intval() and if you look at what intval() actually does in the php docks, you will see this

intval ( mixed $value , int $base = 10 ) : int

// Замечание:
// Если base равно 0, основание системы счисления определяется форматом value:
// если строка включает префикс "0x" (или "0X"), основание выбирается равным 16 (шестнадцатеричным);
// иначе, если строка начинается с "0", основание равно 8 (восьмеричное);
// иначе, основание выбирается равным 10 (десятеричным).


So we get an error in the base record if we pass a string that starts with a number and ends with a character.
for example, we want to write the value of the property Article with the value 20008404080S, which will make CIBlockElement::SetPropertyValuesEx
to VALUE it will write the string 20008404080S
to VALUE_ENUM it will write the number given from the string 20008404080S => 20008404080 in
between, the field in the VALUE_ENUM database has 10 characters, and we are trying to write 11 for which we rightly get an Out of range error

, but what happens in the SetPropertyValuesEx method itself

$maxValuesLen = $DB->type=="MYSQL"?1024:0;
            $strSqlValues = "";
            foreach($properties as $property_id=>$values)
            {
                foreach($values as $value)
                {
                    if($value["VALUE"] <> '')
                    {
                        $strSqlValues .= ",\n(".
                            $property_id.", ".
                            $ELEMENT_ID.", ".
                            "'".$DB->ForSQL($value["VALUE"])."', ".
                            intval($value["VALUE"]).", ".
                            CIBlock::roundDB($value["VALUE"]).", ".
                            ($value["DESCRIPTION"] <> ''? "'".$DB->ForSQL($value["DESCRIPTION"])."'" : "null")." ".
                        ")";
                    }
                    if(mb_strlen($strSqlValues) > $maxValuesLen)
                    {
                        $DB->Query($strSqlPrefix.mb_substr($strSqlValues, 2));
                        $strSqlValues = "";
                    }
                }
            }


as we see VALUE_ENUM and VALUE_NUM

"'".$DB->ForSQL($value["VALUE"])."', ".
                            intval($value["VALUE"]).", ".
                            CIBlock::roundDB($value["VALUE"]).", ".

are written without checking for a match VALUE

So the question is how to add a property value of type STRING and write to VALUE_ENUM=> NULL and VALUE_NUM=>0 ?

UPD1. I chose this solution, we inherit from the CIBlockElement class and change the SetPropertyValuesEx method to the code we need

class CIBlockElementModify extends CIBlockElement
{
  public static function SetPropertyValuesEx($ELEMENT_ID, $IBLOCK_ID, $PROPERTY_VALUES, $FLAGS=array())
  {

...

$maxValuesLen = $DB->type=="MYSQL"?1024:0;
      $strSqlValues = "";
      foreach($properties as $property_id=>$values)
      {
        foreach($values as $value)
        {
          if($value["VALUE"] <> '')
          {
            $strSqlValues .= ",\n(".
              $property_id.", ".
              $ELEMENT_ID.", ".
              "'".$DB->ForSQL($value["VALUE"])."', ".
              (intval($value["VALUE"])===$value["VALUE"]?intval($value["VALUE"]):'null').", ".
              (intval($value["VALUE"])===$value["VALUE"]?CIBlock::roundDB($value["VALUE"]):0).", ".
              ($value["DESCRIPTION"] <> ''? "'".$DB->ForSQL($value["DESCRIPTION"])."'" : "null")." ".
            ")";
          }


change to this, if with intval the values ​​​​are the same in type, then we write as it was, if not, we set null and 0 for VALUE_ENUM and VALUE_NUM

(intval($value["VALUE"])===$value["VALUE"] ?intval($value["VALUE"]):'null').", ".
(intval($value["VALUE"])===$value["VALUE"]?CIBlock::roundDB($value["VALUE"]):0).", ".

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question