- Модуль: iblock
- Путь к файлу: ~/bitrix/modules/iblock/classes/general/iblocksection.php
- Класс: CAllIBlockSection
- Вызов: CAllIBlockSection::recountTreeAfterUpdate
static function recountTreeAfterUpdate($arFields, $db_record)
{
global $DB;
$ID = $arFields['ID'];
$move_distance = 0;
//Move inside the tree
if ((isset($arFields["SORT"]) && $arFields["SORT"] != $db_record["SORT"])
|| (isset($arFields["NAME"]) && $arFields["NAME"] != $db_record["NAME"])
|| (isset($arFields["IBLOCK_SECTION_ID"]) && $arFields["IBLOCK_SECTION_ID"] != $db_record["IBLOCK_SECTION_ID"]))
{
//First "delete" from the tree
$distance = (int)$db_record["RIGHT_MARGIN"] - (int)$db_record["LEFT_MARGIN"] + 1;
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,LEFT_MARGIN = -LEFT_MARGIN
,RIGHT_MARGIN = -RIGHT_MARGIN
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN >= ".(int)$db_record["LEFT_MARGIN"]."
AND LEFT_MARGIN <= ".(int)$db_record["RIGHT_MARGIN"]."
");
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,RIGHT_MARGIN = RIGHT_MARGIN - ".$distance."
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND RIGHT_MARGIN > ".$db_record["RIGHT_MARGIN"]."
");
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,LEFT_MARGIN = LEFT_MARGIN - ".$distance."
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN > ".$db_record["LEFT_MARGIN"]."
");
//Next insert into the the tree almost as we do when inserting the new one
$PARENT_ID = (int)($arFields["IBLOCK_SECTION_ID"] ?? $db_record["IBLOCK_SECTION_ID"]);
$NAME = $arFields["NAME"] ?? $db_record["NAME"];
$SORT = (int)($arFields["SORT"] ?? $db_record["SORT"]);
$arParents = array();
$strSql = "
SELECT BS.ID, BS.ACTIVE, BS.GLOBAL_ACTIVE, BS.DEPTH_LEVEL, BS.LEFT_MARGIN, BS.RIGHT_MARGIN
FROM b_iblock_section BS
WHERE BS.IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND BS.ID in (".(int)$db_record["IBLOCK_SECTION_ID"].", ".$PARENT_ID.")
";
$rsParents = $DB->Query($strSql);
while ($arParent = $rsParents->Fetch())
{
$arParents[$arParent["ID"]] = $arParent;
}
//Find rightmost child of the parent
$strSql = "
SELECT BS.ID, BS.RIGHT_MARGIN, BS.DEPTH_LEVEL
FROM b_iblock_section BS
WHERE BS.IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND ".($PARENT_ID > 0 ? "BS.IBLOCK_SECTION_ID=".$PARENT_ID : "BS.IBLOCK_SECTION_ID IS NULL")."
AND (
(BS.SORT < ".$SORT.")
OR (BS.SORT = ".$SORT." AND BS.NAME < '".$DB->ForSQL($NAME)."')
)
AND BS.ID <> ".$ID."
ORDER BY BS.SORT DESC, BS.NAME DESC
";
$rsChild = $DB->Query($strSql);
if ($arChild = $rsChild->Fetch())
{
//We found the left neighbour
$arUpdate = array(
"LEFT_MARGIN" => (int)$arChild["RIGHT_MARGIN"] + 1,
"DEPTH_LEVEL" => (int)$arChild["DEPTH_LEVEL"],
);
}
else
{
//If we have parent, when take its left_margin
if (isset($arParents[$PARENT_ID]) && $arParents[$PARENT_ID])
{
$arUpdate = array(
"LEFT_MARGIN" => (int)$arParents[$PARENT_ID]["LEFT_MARGIN"] + 1,
"DEPTH_LEVEL" => (int)$arParents[$PARENT_ID]["DEPTH_LEVEL"] + 1,
);
}
else
{
//We are only one/leftmost section in the iblock.
$arUpdate = array(
"LEFT_MARGIN" => 1,
"DEPTH_LEVEL" => 1,
);
}
}
$move_distance = (int)$db_record["LEFT_MARGIN"] - $arUpdate["LEFT_MARGIN"];
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,LEFT_MARGIN = LEFT_MARGIN + ".$distance."
,RIGHT_MARGIN = RIGHT_MARGIN + ".$distance."
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN >= ".$arUpdate["LEFT_MARGIN"]."
");
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,LEFT_MARGIN = -LEFT_MARGIN - ".$move_distance."
,RIGHT_MARGIN = -RIGHT_MARGIN - ".$move_distance."
".($arUpdate["DEPTH_LEVEL"] != (int)$db_record["DEPTH_LEVEL"] ? ",DEPTH_LEVEL = DEPTH_LEVEL - ".($db_record["DEPTH_LEVEL"] - $arUpdate["DEPTH_LEVEL"]) : "")."
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN <= ".(-(int)$db_record["LEFT_MARGIN"])."
AND LEFT_MARGIN >= ".(-(int)$db_record["RIGHT_MARGIN"])."
");
if (isset($arParents[$PARENT_ID]))
{
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,RIGHT_MARGIN = RIGHT_MARGIN + ".$distance."
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN <= ".$arParents[$PARENT_ID]["LEFT_MARGIN"]."
AND RIGHT_MARGIN >= ".$arParents[$PARENT_ID]["RIGHT_MARGIN"]."
");
}
}
//Check if parent was changed
if (isset($arFields["IBLOCK_SECTION_ID"]) && $arFields["IBLOCK_SECTION_ID"] != $db_record["IBLOCK_SECTION_ID"])
{
$rsSection = CIBlockSection::GetList(
array(),
array("ID" => $ID, "CHECK_PERMISSIONS" => "N"),
false,
array(
"ID", "IBLOCK_ID", "IBLOCK_SECTION_ID",
"LEFT_MARGIN", "RIGHT_MARGIN",
"ACTIVE", "GLOBAL_ACTIVE"
)
);
$arSection = $rsSection->Fetch();
unset($rsSection);
$strSql = "
SELECT ID, GLOBAL_ACTIVE
FROM b_iblock_section
WHERE IBLOCK_ID = ".$arSection["IBLOCK_ID"]."
AND ID = ".(int)$arFields["IBLOCK_SECTION_ID"]."
";
$rsParent = $DB->Query($strSql);
$arParent = $rsParent->Fetch();
//If new parent is not globally active
//or we are not active either
//we must be not globally active too
if (($arParent && $arParent["GLOBAL_ACTIVE"] == "N") || ($arFields["ACTIVE"] == "N"))
{
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,GLOBAL_ACTIVE = 'N'
WHERE
IBLOCK_ID = ".$arSection["IBLOCK_ID"]."
AND LEFT_MARGIN >= ".(int)$arSection["LEFT_MARGIN"]."
AND RIGHT_MARGIN <= ".(int)$arSection["RIGHT_MARGIN"]."
");
}
//New parent is globally active
//And we WAS NOT active
//But is going to be
elseif ($arSection["ACTIVE"] == "N" && $arFields["ACTIVE"] == "Y")
{
static::RecalcGlobalActiveFlag($arSection);
}
//New parent is globally active
//And we WAS active but NOT globally active
//But is going to be
elseif (
(!$arParent || $arParent["GLOBAL_ACTIVE"] == "Y")
&& $arSection["GLOBAL_ACTIVE"] == "N"
&& ($arSection["ACTIVE"] == "Y" || $arFields["ACTIVE"] == "Y")
)
{
static::RecalcGlobalActiveFlag($arSection);
}
//Otherwise we may not to change anything
}
//Parent not changed
//but we are going to change activity flag
elseif (isset($arFields["ACTIVE"]) && $arFields["ACTIVE"] != $db_record["ACTIVE"])
{
//Make all children globally inactive
if ($arFields["ACTIVE"] == "N")
{
$DB->Query("
UPDATE b_iblock_section SET
TIMESTAMP_X=".($DB->type == "ORACLE" ? "NULL" : "TIMESTAMP_X")."
,GLOBAL_ACTIVE = 'N'
WHERE
IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND LEFT_MARGIN >= ".(int)$db_record["LEFT_MARGIN"]."
AND RIGHT_MARGIN <= ".(int)$db_record["RIGHT_MARGIN"]."
");
}
else
{
//Check for parent activity
$strSql = "
SELECT ID, GLOBAL_ACTIVE
FROM b_iblock_section
WHERE IBLOCK_ID = ".$db_record["IBLOCK_ID"]."
AND ID = ".(int)$db_record["IBLOCK_SECTION_ID"]."
";
$rsParent = $DB->Query($strSql);
$arParent = $rsParent->Fetch();
//Parent is active
//and we changed
//so need to recalc
if (!$arParent || $arParent["GLOBAL_ACTIVE"] == "Y")
{
static::RecalcGlobalActiveFlag($db_record, -$move_distance);
}
}
}
}