mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 18:48:51 +02:00
N°2527 - Manage hierarchical keys in database maintenance tools
This commit is contained in:
122
sources/Core/MetaModel/HierarchicalKey.php
Normal file
122
sources/Core/MetaModel/HierarchicalKey.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Core\MetaModel;
|
||||
|
||||
use CMDBSource;
|
||||
use CoreException;
|
||||
use MetaModel;
|
||||
|
||||
class HierarchicalKey {
|
||||
|
||||
/**
|
||||
* Verify that an HK control information is correct
|
||||
* @param $sClass
|
||||
* @param $sAttCode
|
||||
* @param $oAttDef
|
||||
*
|
||||
* @throws \CoreException thrown if not correct
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function VerifyIntegrity($sClass, $sAttCode, $oAttDef)
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sClass, $sAttCode);
|
||||
$sLeft = $oAttDef->GetSQLLeft();
|
||||
$sRight = $oAttDef->GetSQLRight();
|
||||
|
||||
list($aControlByParent, $aControlById) = self::GetHierarchyControlData($sTable, $sAttCode, $sLeft, $sRight, $sLeft);
|
||||
|
||||
// Get global boundaries
|
||||
$sSQL = "SELECT MAX(`$sRight`) AS MaxRight, MIN(`$sLeft`) as MinLeft FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL, MYSQLI_ASSOC);
|
||||
$aValues = $aRes[0];
|
||||
// fake super-root
|
||||
$aControlById[0] = [
|
||||
'ctrl_left' => $aValues['MinLeft'] - 1, // to mimic the controls of a fake super-root
|
||||
'ctrl_right' => $aValues['MaxRight'] + 1,
|
||||
];
|
||||
foreach ($aControlByParent as $iParentId => $aTreeIds) {
|
||||
$iParentLeft = $aControlById[$iParentId]['ctrl_left'];
|
||||
$iParentRight = $aControlById[$iParentId]['ctrl_right'];
|
||||
$iMinLeft = $iParentLeft;
|
||||
|
||||
foreach ($aTreeIds as $aValues) {
|
||||
$iChildLeft = $aValues[$sLeft];
|
||||
$iChildRight = $aValues[$sRight];
|
||||
if ($iChildLeft <= $iMinLeft || $iParentRight <= $iChildRight || $iChildRight <= $iChildLeft) {
|
||||
throw new CoreException("Wrong HK control values");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function Rebuild($sClass, $sAttCode, $oAttDef, $bForce = false)
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sClass, $sAttCode);
|
||||
$sLeft = $oAttDef->GetSQLLeft();
|
||||
$sRight = $oAttDef->GetSQLRight();
|
||||
list($aControlByParent) = self::GetHierarchyControlData($sTable, $sAttCode, $sLeft, $sRight, 'id');
|
||||
|
||||
$aEntriesToUpdate = [];
|
||||
|
||||
$iCurrentControl = 1;
|
||||
// roots
|
||||
$aEntries = $aControlByParent[0];
|
||||
while (!empty($aEntries)) {
|
||||
// consider the first entry
|
||||
$aEntry = &$aEntries[0];
|
||||
if (!array_key_exists('new_left', $aEntry)) {
|
||||
// The node has never been seen, set its left control
|
||||
$aEntry['new_left'] = $iCurrentControl++;
|
||||
if (array_key_exists($aEntry['id'], $aControlByParent)) {
|
||||
// node has children, add them to the list
|
||||
$aChildren = $aControlByParent[$aEntry['id']];
|
||||
$aEntries = array_merge($aChildren, $aEntries);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// All the children have been computed, close the node
|
||||
$aEntry['new_right'] = $iCurrentControl++;
|
||||
if ($bForce || $aEntry['ctrl_left'] != $aEntry['new_left'] || $aEntry['ctrl_right'] != $aEntry['new_right']) {
|
||||
$aEntriesToUpdate[] = $aEntry;
|
||||
}
|
||||
// remove the entry
|
||||
array_shift($aEntries);
|
||||
}
|
||||
|
||||
foreach ($aEntriesToUpdate as $aEntry) {
|
||||
$iLeft = $aEntry['new_left'];
|
||||
$iRight = $aEntry['new_right'];
|
||||
$iId = $aEntry['id'];
|
||||
$sSQL = "UPDATE `$sTable` SET `$sLeft` = $iLeft, `$sRight` = $iRight WHERE id= $iId";
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTable database table
|
||||
* @param string $sAttCode parent field (hierarchy)
|
||||
* @param string $sLeft left field
|
||||
* @param string $sRight right field
|
||||
*
|
||||
* @return array[] $aControlById all the left and right by id and $aControlByParent same but organized by parent
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
private static function GetHierarchyControlData($sTable, $sAttCode, $sLeft, $sRight, $sOrderBy)
|
||||
{
|
||||
$sSQL = "SELECT id, `$sLeft` AS ctrl_left, `$sRight` AS ctrl_right, `$sAttCode` AS parent_id FROM `$sTable` WHERE 1 ORDER BY `$sOrderBy`";
|
||||
$aTreeIds = CMDBSource::QueryToArray($sSQL, MYSQLI_ASSOC);
|
||||
$aControlById = [];
|
||||
$aControlByParent = [];
|
||||
while (!empty($aTreeIds)) {
|
||||
$aTreeId = array_shift($aTreeIds);
|
||||
$aControlById[$aTreeId['id']] = $aTreeId;
|
||||
$aControlByParent[$aTreeId['parent_id']][] = $aTreeId;
|
||||
}
|
||||
return [$aControlByParent, $aControlById];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user