mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-18 23:08:46 +02:00
N°2527 - Manage hierarchical keys in database maintenance tools
This commit is contained in:
34
datamodels/2.x/combodo-db-tools/bin/rebuildhk.php
Normal file
34
datamodels/2.x/combodo-db-tools/bin/rebuildhk.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Rebuild the hierarchical keys control data
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Core\MetaModel\HierarchicalKey;
|
||||
|
||||
require_once('../approot.inc.php');
|
||||
require_once APPROOT.'application/startup.inc.php';
|
||||
|
||||
foreach(MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
if (!MetaModel::HasTable($sClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
// Check (once) all the attributes that are hierarchical keys
|
||||
if ((MetaModel::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
echo "Rebuild hierarchical key $sAttCode from $sClass.\n";
|
||||
HierarchicalKey::Rebuild($sClass, $sAttCode, $oAttDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
@@ -17,6 +17,8 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
use Combodo\iTop\Core\MetaModel\HierarchicalKey;
|
||||
|
||||
class DatabaseAnalyzer
|
||||
{
|
||||
var $iTimeLimitPerOperation;
|
||||
@@ -162,6 +164,9 @@ class DatabaseAnalyzer
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$this->CheckExternalKeys($oAttDef, $sTable, $sKeyField, $sAttCode, $sClass, $aErrorsAndFixes);
|
||||
if ((MetaModel::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey()) {
|
||||
$this->CheckHK($sClass, $sAttCode, $aErrorsAndFixes);
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef->IsDirectField() && !($oAttDef instanceof AttributeTagSet))
|
||||
{
|
||||
@@ -506,5 +511,24 @@ class DatabaseAnalyzer
|
||||
$this->ExecQuery($sSelWrongRecs, $sFixit, $sErrorDesc, $sClass, $aErrorsAndFixes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check hierarchical keys
|
||||
*
|
||||
* @param $sClass
|
||||
* @param $sAttCode
|
||||
* @param $aErrorsAndFixes
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function CheckHK($sClass, $sAttCode, &$aErrorsAndFixes)
|
||||
{
|
||||
try {
|
||||
HierarchicalKey::VerifyIntegrity($sClass, $sAttCode, MetaModel::GetAttributeDef($sClass, $sAttCode));
|
||||
} catch (CoreException $e) {
|
||||
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-HKInvalid', $sAttCode);
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['count'] = 1;
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['query'] = '-- N/A';
|
||||
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = ['-- Run script env-'.utils::GetCurrentEnvironment().DIRECTORY_SEPARATOR.'combodo-db-tools'.DIRECTORY_SEPARATOR.'bin'.DIRECTORY_SEPARATOR.'rebuildhk.php' ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,17 +234,19 @@ function DisplayErrorDetails($aResults, $bVerbose)
|
||||
$oFieldSet = FieldSetUIBlockFactory::MakeStandard(Dict::S('DBTools:SQLquery'));
|
||||
$oCollapsible->AddSubBlock($oFieldSet);
|
||||
|
||||
$oCode = UIContentBlockUIBlockFactory::MakeForPreformatted($aError['query']);
|
||||
$oFieldSet->AddSubBlock($oCode);
|
||||
if (array_key_exists('query', $aError)) {
|
||||
$oCode = UIContentBlockUIBlockFactory::MakeForPreformatted($aError['query']);
|
||||
$oFieldSet->AddSubBlock($oCode);
|
||||
|
||||
if (isset($aError['fixit'])) {
|
||||
$oFieldSet = FieldSetUIBlockFactory::MakeStandard(Dict::S('DBTools:FixitSQLquery'));
|
||||
$oCollapsible->AddSubBlock($oFieldSet);
|
||||
if (isset($aError['fixit'])) {
|
||||
$oFieldSet = FieldSetUIBlockFactory::MakeStandard(Dict::S('DBTools:FixitSQLquery'));
|
||||
$oCollapsible->AddSubBlock($oFieldSet);
|
||||
|
||||
$aQueries = $aError['fixit'];
|
||||
foreach ($aQueries as $sFixQuery) {
|
||||
$oCode = UIContentBlockUIBlockFactory::MakeForPreformatted($sFixQuery);
|
||||
$oFieldSet->AddSubBlock($oCode);
|
||||
$aQueries = $aError['fixit'];
|
||||
foreach ($aQueries as $sFixQuery) {
|
||||
$oCode = UIContentBlockUIBlockFactory::MakeForPreformatted($sFixQuery);
|
||||
$oFieldSet->AddSubBlock($oCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all',
|
||||
'DBAnalyzer-Integrity-HKInvalid' => 'Broken hierarchical key `%1$s`',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted',
|
||||
'DBAnalyzer-Integrity-FinalClass' => 'Field `%2$s`.`%1$s` must have the same value as `%3$s`.`%1$s`',
|
||||
'DBAnalyzer-Integrity-RootFinalClass' => 'Field `%2$s`.`%1$s` must contains a valid class',
|
||||
|
||||
@@ -46,10 +46,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'DBTools:DetailedErrorTitle' => '%2$s erreur(s) dans la classe %1$s : %3$s',
|
||||
|
||||
'DBAnalyzer-Integrity-OrphanRecord' => 'Enregistrement orphelin dans `%1$s`, il devrait avoir son équivalent dans la table `%2$s`',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Clef externe invalide %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Clef externe manquante %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidExtKey' => 'Clé externe invalide %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-MissingExtKey' => 'Clé externe manquante %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-InvalidValue' => 'Valeur invalide pour %1$s (colonne: `%2$s.%3$s`)',
|
||||
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Certains comptes utilisateurs n\'ont aucun profile',
|
||||
'DBAnalyzer-Integrity-HKInvalid' => 'Clé hiérarchique `%1$s` invalide',
|
||||
'DBAnalyzer-Fetch-Count-Error' => 'Erreur de récupération dans `%1$s`, %2$d enregistrements récupérés / %3$d comptés',
|
||||
'DBAnalyzer-Integrity-FinalClass' => 'Le champ `%2$s`.`%1$s` doit avoir la même valeur que `%3$s`.`%1$s`',
|
||||
'DBAnalyzer-Integrity-RootFinalClass' => 'Le champ `%2$s`.`%1$s` doit contenir une classe valide',
|
||||
|
||||
@@ -40,9 +40,11 @@ class DBAnalyzerUtils
|
||||
$iCount = $aError['count'];
|
||||
fwrite($fReport, '-- Count: '.$iCount."\r\n");
|
||||
fwrite($fReport, '-- Error: '.$sErrorLabel."\r\n");
|
||||
$sQuery = $aError['query'];
|
||||
fwrite($fReport, '-- Query: '.$sQuery."\r\n");
|
||||
|
||||
if (array_key_exists('query', $aError)) {
|
||||
$sQuery = $aError['query'];
|
||||
fwrite($fReport, '-- Query: '.$sQuery."\r\n");
|
||||
}
|
||||
|
||||
if (isset($aError['fixit']))
|
||||
{
|
||||
fwrite($fReport, "\r\n-- Fix it (indication):\r\n\r\n");
|
||||
|
||||
@@ -44,8 +44,8 @@ class HierarchicalKey {
|
||||
$iMinLeft = $iParentLeft;
|
||||
|
||||
foreach ($aTreeIds as $aValues) {
|
||||
$iChildLeft = $aValues[$sLeft];
|
||||
$iChildRight = $aValues[$sRight];
|
||||
$iChildLeft = $aValues['ctrl_left'];
|
||||
$iChildRight = $aValues['ctrl_right'];
|
||||
if ($iChildLeft <= $iMinLeft || $iParentRight <= $iChildRight || $iChildRight <= $iChildLeft) {
|
||||
throw new CoreException("Wrong HK control values");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user