mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-25 09:16:44 +02:00
Compare commits
2 Commits
develop
...
feature/96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc9df64eea | ||
|
|
41d4f04375 |
@@ -916,7 +916,9 @@ class CMDBSource
|
||||
$aColumn = [];
|
||||
$aData = self::QueryToArray($sSql);
|
||||
foreach ($aData as $aRow) {
|
||||
@$aColumn[] = $aRow[$col];
|
||||
if ($aRow[$col] !== null) {
|
||||
$aColumn[] = $aRow[$col];
|
||||
}
|
||||
}
|
||||
return $aColumn;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\DataCleanupService;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
|
||||
use ContextTag;
|
||||
@@ -168,6 +169,7 @@ class DataFeatureRemovalController extends Controller
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv);
|
||||
$aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit());
|
||||
DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
|
||||
$aDeletionPlan = (new StaticDeletionPlan())->GetStaticDeletionPlan($aGetRemovedClasses);
|
||||
|
||||
$aParams['aClasses'] = $aGetRemovedClasses;
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\DataFeatureRemoval\Service;
|
||||
|
||||
use CMDBSource;
|
||||
use MetaModel;
|
||||
|
||||
class StaticDeletionPlan
|
||||
{
|
||||
private array $aDeletionPlan = [];
|
||||
|
||||
/**
|
||||
* @param array $aClasses Classes to clean entirely
|
||||
*
|
||||
* @return array ['class' => [
|
||||
* 'delete' => [ids],
|
||||
* 'delete_sql' => string,
|
||||
* 'update_extkey_nullable' => [ids],
|
||||
* 'update_extkey_nullable_sql' => [sSQL],
|
||||
* 'update_hierarchical' => [ids],
|
||||
* 'update_hierarchical_sql' => [sSQL],
|
||||
* 'issue' => [id],
|
||||
* ]];
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetStaticDeletionPlan(array $aClasses): array
|
||||
{
|
||||
foreach ($aClasses as $sClass) {
|
||||
[$sDeleteSQL, $aIds] = $this->GetInitialClassDeletionPlan($sClass);
|
||||
$this->aDeletionPlan[$sClass] = [
|
||||
'delete' => $aIds,
|
||||
'delete_sql' => $sDeleteSQL,
|
||||
];
|
||||
|
||||
$this->DeletionPlanForReferencingClasses($sClass);
|
||||
}
|
||||
|
||||
return $this->aDeletionPlan;
|
||||
}
|
||||
|
||||
private function DeletionPlanForReferencingClasses(string $sClass): void
|
||||
{
|
||||
$sIdsToRemove = implode(', ', $this->aDeletionPlan[$sClass]['delete']);
|
||||
$aReferencingMe = MetaModel::EnumReferencingClasses($sClass);
|
||||
foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) {
|
||||
$sRemoteTable = MetaModel::DBGetTable($sRemoteClass);
|
||||
/** @var \AttributeExternalKey $oExtKeyAttDef */
|
||||
foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) {
|
||||
// skip if this external key is behind an external field
|
||||
if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($oExtKeyAttDef->IsNullAllowed()) {
|
||||
// update
|
||||
[$sUpdateSQL, $aIds] = $this->UpdateExtKeyNullable($sRemoteTable, $sExtKeyAttCode, $sIdsToRemove);
|
||||
$this->aDeletionPlan[$sRemoteClass]['update_extkey_nullable_sql'][$sExtKeyAttCode] = $sUpdateSQL;
|
||||
$this->aDeletionPlan[$sRemoteClass]['update_extkey_nullable'] = array_unique(array_merge($this->aDeletionPlan[$sRemoteClass]['update_extkey_nullable'] ?? [], $aIds));
|
||||
} else {
|
||||
// delete
|
||||
$aRemoteIdsToRemove = $this->GetRemoteIdsForExtKey($sRemoteTable, $sExtKeyAttCode, $sIdsToRemove);
|
||||
|
||||
$iDeletePropagationOption = $oExtKeyAttDef->GetDeletionPropagationOption();
|
||||
if ($iDeletePropagationOption == DEL_MANUAL) {
|
||||
// Issue, do not recurse
|
||||
if (count($aRemoteIdsToRemove) > 0) {
|
||||
$this->aDeletionPlan[$sRemoteClass]['issue'] = array_unique(array_merge($this->aDeletionPlan[$sRemoteClass]['issue'] ?? [], $aRemoteIdsToRemove));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($iDeletePropagationOption == DEL_MOVEUP) && ($oExtKeyAttDef->IsHierarchicalKey())) {
|
||||
// update hierarchical keys due to row cleanup in the same table
|
||||
$sIdsToRemove = implode(',', $this->aDeletionPlan[$sRemoteClass]['delete']);
|
||||
[$sUpdateSQL, $aIds] = $this->UpdateHierarchicalExtKey($sRemoteTable, $sExtKeyAttCode, $sIdsToRemove);
|
||||
$this->aDeletionPlan[$sRemoteClass]['update_hierarchical_sql'][$sExtKeyAttCode] = $sUpdateSQL;
|
||||
$this->aDeletionPlan[$sRemoteClass]['update_hierarchical'] = array_unique(array_merge($this->aDeletionPlan[$sRemoteClass]['update_hierarchical'] ?? [], $aIds));
|
||||
// do not recurse
|
||||
continue;
|
||||
}
|
||||
|
||||
// Delete entries in Remote Class
|
||||
$this->aDeletionPlan[$sRemoteClass]['delete'] = array_unique(array_merge($this->aDeletionPlan[$sRemoteClass]['delete'] ?? [], $aRemoteIdsToRemove));
|
||||
$sRemoteIdsToDelete = implode(',', $aRemoteIdsToRemove);
|
||||
$this->aDeletionPlan[$sRemoteClass]['delete_sql'] = "DELETE FROM $sRemoteTable WHERE id IN ($sRemoteIdsToDelete)";
|
||||
|
||||
$this->DeletionPlanForReferencingClasses($sRemoteClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sRemoteTable
|
||||
* @param string $sExtKeyAttCode
|
||||
* @param string $sIdsToRemoveInTargetClass
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function UpdateExtKeyNullable(string $sRemoteTable, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): array
|
||||
{
|
||||
$aIds = $this->GetRemoteIdsForExtKey($sRemoteTable, $sExtKeyAttCode, $sIdsToRemoveInTargetClass);
|
||||
|
||||
$sUpdateSQL = <<<SQL
|
||||
UPDATE $sRemoteTable SET updated.$sExtKeyAttCode = 0
|
||||
FROM $sRemoteTable AS updated
|
||||
WHERE updated.$sExtKeyAttCode IN ($sIdsToRemoveInTargetClass)
|
||||
SQL;
|
||||
|
||||
return [$sUpdateSQL, $aIds];
|
||||
}
|
||||
|
||||
public function UpdateHierarchicalExtKey(string $sRemoteTable, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): array
|
||||
{
|
||||
$sUpdateSQL = <<<SQL
|
||||
UPDATE $sRemoteTable SET updated.$sExtKeyAttCode = removed.$sExtKeyAttCode
|
||||
FROM $sRemoteTable AS updated
|
||||
INNER JOIN $sRemoteTable AS removed ON updated.$sExtKeyAttCode = removed.id
|
||||
WHERE removed.id IN ($sIdsToRemoveInTargetClass)
|
||||
SQL;
|
||||
|
||||
$sSQL = <<<SQL
|
||||
SELECT id
|
||||
FROM $sRemoteTable AS updated
|
||||
INNER JOIN $sRemoteTable AS removed ON updated.$sExtKeyAttCode = removed.id
|
||||
WHERE removed.id IN ($sIdsToRemoveInTargetClass)
|
||||
SQL;
|
||||
$aIds = CMDBSource::QueryToCol($sSQL, 'id');
|
||||
|
||||
return [$sUpdateSQL, $aIds];
|
||||
}
|
||||
|
||||
public function GetRemoteIdsForExtKey(string $sRemoteTable, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): array
|
||||
{
|
||||
$sSQL = "SELECT id FROM $sRemoteTable WHERE $sExtKeyAttCode IN ($sIdsToRemoveInTargetClass)";
|
||||
|
||||
return CMDBSource::QueryToCol($sSQL, 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function GetInitialClassDeletionPlan(string $sClass): array
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sClass);
|
||||
$sSQL = "SELECT id FROM $sTable";
|
||||
$aIds = CMDBSource::QueryToCol($sSQL, 'id');
|
||||
$sDeleteSQL = "DELETE FROM $sTable";
|
||||
|
||||
return [$sDeleteSQL, $aIds];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@ return array(
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => $baseDir . '/src/Service/ObjectService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => $baseDir . '/src/Service/ObjectServiceSummary.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\StaticDeletionPlan' => $baseDir . '/src/Service/StaticDeletionPlan.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => $baseDir . '/src/Service/iObjectService.php',
|
||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
@@ -31,6 +31,7 @@ class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => __DIR__ . '/../..' . '/src/Service/ObjectService.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => __DIR__ . '/../..' . '/src/Service/ObjectServiceSummary.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\StaticDeletionPlan' => __DIR__ . '/../..' . '/src/Service/StaticDeletionPlan.php',
|
||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => __DIR__ . '/../..' . '/src/Service/iObjectService.php',
|
||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||
);
|
||||
|
||||
@@ -74,7 +74,6 @@ if (SetupUtils::IsSessionSetupTokenValid()) {
|
||||
// The configuration file already exists
|
||||
if (!is_writable($sConfigFile)) {
|
||||
SetupUtils::ExitReadOnlyMode(false); // Reset readonly mode in case of problem
|
||||
SetupUtils::EraseSetupToken();
|
||||
$sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV);
|
||||
$oP = new SetupPage('Installation Cannot Continue');
|
||||
$oP->add("<h2>Fatal error</h2>\n");
|
||||
@@ -87,7 +86,6 @@ HTML;
|
||||
$oP->p($sButtonsHtml);
|
||||
|
||||
$oP->output();
|
||||
// Prevent token creation
|
||||
exit;
|
||||
} else {
|
||||
chmod($sConfigFile, 0440);
|
||||
|
||||
@@ -196,7 +196,6 @@ class WizardController
|
||||
SetupLog::Info("=== Setup screen: ".$oStep->GetTitle().' ('.get_class($oStep).')');
|
||||
$oPage = new SetupPage($oStep->GetTitle());
|
||||
$oPage->LinkScriptFromAppRoot('setup/setup.js');
|
||||
$oStep->PreFormDisplay($oPage);
|
||||
|
||||
$oPage->add('<form id="wiz_form" class="ibo-setup--wizard" method="post">');
|
||||
$oPage->add('<div class="ibo-setup--wizard--content">');
|
||||
|
||||
@@ -76,10 +76,6 @@ abstract class WizardStep
|
||||
{
|
||||
}
|
||||
|
||||
public function PreFormDisplay(SetupPage $oPage)
|
||||
{
|
||||
}
|
||||
|
||||
protected function CheckDependencies()
|
||||
{
|
||||
if (is_null($this->bDependencyCheck)) {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class AbstractCleanup extends ItopCustomDatamodelTestCase
|
||||
{
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
return __DIR__.'/data_cleanup_delta.xml';
|
||||
}
|
||||
|
||||
protected array $aIdByClass;
|
||||
protected array $aIdByObjectName = [];
|
||||
|
||||
protected function GivenDFRTreeInDB(string $sTree)
|
||||
{
|
||||
$this->aIdByClass = [];
|
||||
$aTree = explode("\n", $sTree);
|
||||
foreach ($aTree as $sLine) {
|
||||
if (trim($sLine) === '') {
|
||||
continue;
|
||||
}
|
||||
$this->GivenDFRTreeLineInDB($sLine);
|
||||
}
|
||||
}
|
||||
|
||||
protected function GivenDFRTreeLineInDB(string $sLine)
|
||||
{
|
||||
[$sLeft, $sRight] = explode('<-', $sLine);
|
||||
$sLeft = trim($sLeft);
|
||||
|
||||
$iLeftId = $this->aIdByObjectName[$sLeft] ?? 0;
|
||||
if ($iLeftId === 0) {
|
||||
[$sChildClass] = explode('_', $sLeft, 2);
|
||||
$iLeftId = $this->GivenObjectInDB($sChildClass, ['name' => $sLeft]);
|
||||
$this->aIdByClass[$sChildClass][] = $iLeftId;
|
||||
$this->aIdByObjectName[$sLeft] = $iLeftId;
|
||||
}
|
||||
|
||||
$sRight = trim($sRight);
|
||||
if (preg_match("/(?<name>(?<class>[^_]+)_\d+)(\s+\((?<extkey>\w+)\))?/", $sRight, $aMatches) !== false) {
|
||||
}
|
||||
|
||||
[$sChildClass] = explode('_', $sRight, 2);
|
||||
|
||||
$iRightId = $this->GivenObjectInDB($sChildClass, ['name' => $sRight, 'extkey_id' => $iLeftId]);
|
||||
$this->aIdByClass[$sChildClass][] = $iRightId;
|
||||
$this->aIdByObjectName[$sRight] = $iRightId;
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,10 @@ use PHPUnit\Framework\MockObject\MockObject;
|
||||
* @see DataCleanupSummaryEntity
|
||||
* @see ItopDataTestCase
|
||||
*/
|
||||
class DataCleanupServiceTest extends ItopCustomDatamodelTestCase
|
||||
class DataCleanupServiceTest extends \AbstractCleanup
|
||||
{
|
||||
private ExecutionLimits&MockObject $oExecutionLimits;
|
||||
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
return __DIR__.'/data_cleanup_delta.xml';
|
||||
}
|
||||
|
||||
//--- GetCleanupSummary tests ---
|
||||
|
||||
/**
|
||||
@@ -261,36 +256,6 @@ class DataCleanupServiceTest extends ItopCustomDatamodelTestCase
|
||||
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||
}
|
||||
|
||||
private function GivenDFRTreeInDB(string $sTree)
|
||||
{
|
||||
$aTree = explode("\n", $sTree);
|
||||
foreach ($aTree as $sLine) {
|
||||
if (trim($sLine) === "") {
|
||||
continue;
|
||||
}
|
||||
$this->GivenDFRTreeLineInDB($sLine);
|
||||
}
|
||||
}
|
||||
|
||||
private array $aIdByObjectName = [];
|
||||
private function GivenDFRTreeLineInDB(string $sLine)
|
||||
{
|
||||
[$sLeft, $sRight] = explode('<-', $sLine);
|
||||
$sLeft = trim($sLeft);
|
||||
|
||||
$iLeftId = $this->aIdByObjectName[$sLeft] ?? 0;
|
||||
if ($iLeftId === 0) {
|
||||
[$sChildClass, ] = explode('_', $sLeft, 2);
|
||||
$iLeftId = $this->GivenObjectInDB($sChildClass, ['name' => $sLeft]);
|
||||
$this->aIdByObjectName[$sLeft] = $iLeftId;
|
||||
}
|
||||
|
||||
$sRight = trim($sRight);
|
||||
[$sChildClass, ] = explode('_', $sRight, 2);
|
||||
$iRightId = $this->GivenObjectInDB($sChildClass, ['name' => $sRight, 'extkey_id' => $iLeftId]);
|
||||
$this->aIdByObjectName[$sRight] = $iRightId;
|
||||
}
|
||||
|
||||
private function GivenExecutionLimits(int $iStopAfterCallNumberReached): void
|
||||
{
|
||||
$matcher = $this->any();
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Module\DataFeatureRemoval;
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan;
|
||||
use MetaModel;
|
||||
|
||||
class StaticDeletionPlanTest extends \AbstractCleanup
|
||||
{
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
return __DIR__.'/data_cleanup_delta.xml';
|
||||
}
|
||||
|
||||
public function testGetInitialClassDeletionPlan()
|
||||
{
|
||||
$this->GivenDFRTreeInDB(<<<EOF
|
||||
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||
DFRToRemoveLeaf_1 <- DFRToUpdate_2
|
||||
DFRToRemoveLeaf_2 <- DFRToUpdate_3
|
||||
EOF);
|
||||
|
||||
$oService = new StaticDeletionPlan();
|
||||
$aRes = $oService->GetInitialClassDeletionPlan('DFRToRemoveLeaf');
|
||||
self::assertCount(2, $aRes[1]);
|
||||
self::assertEquals($this->aIdByClass['DFRToRemoveLeaf'], $aRes[1]);
|
||||
$sTable = MetaModel::DBGetTable('DFRToRemoveLeaf');
|
||||
$sExpectedSQL = "DELETE FROM $sTable";
|
||||
self::assertEquals($sExpectedSQL, $aRes[0]);
|
||||
}
|
||||
|
||||
public function testUpdateExtKeyNullable()
|
||||
{
|
||||
$this->GivenDFRTreeInDB(<<<EOF
|
||||
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||
DFRToRemoveLeaf_1 <- DFRToUpdate_2
|
||||
DFRToRemoveLeaf_2 <- DFRToUpdate_3
|
||||
DFRLeafNotToRemove_1 <- DFRToUpdate_4
|
||||
EOF);
|
||||
|
||||
// WHEN
|
||||
$oService = new StaticDeletionPlan();
|
||||
$sRemoteTable = MetaModel::DBGetTable('DFRToUpdate');
|
||||
$aRes = $oService->UpdateExtKeyNullable(
|
||||
$sRemoteTable,
|
||||
'extkey_id',
|
||||
implode(',', $this->aIdByClass['DFRToRemoveLeaf'])
|
||||
);
|
||||
$sUpdateSQL = $aRes[0];
|
||||
$aIds = $aRes[1];
|
||||
|
||||
// THEN
|
||||
$sExpectedSQLEnd = " IN (".implode(',', $this->aIdByClass['DFRToRemoveLeaf']).")";
|
||||
self::assertStringEndsWith($sExpectedSQLEnd, $sUpdateSQL);
|
||||
|
||||
self::assertCount(3, $aIds);
|
||||
$sIdsToRemoveInTargetClass = implode(',', $this->aIdByClass['DFRToRemoveLeaf']);
|
||||
$aExpectedIds = $oService->GetRemoteIdsForExtKey($sRemoteTable, 'extkey_id', $sIdsToRemoveInTargetClass);
|
||||
|
||||
self::assertEquals($aExpectedIds, $aIds);
|
||||
|
||||
// var_export($aRes);
|
||||
// var_export($this->aIdByClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that GetCleanupSummary returns an empty array when passed null as input.
|
||||
*/
|
||||
public function testGetCleanupSummaryReturnsEmptyArrayWhenNull(): void
|
||||
{
|
||||
$oService = new StaticDeletionPlan();
|
||||
$aResult = $oService->GetStaticDeletionPlan([]);
|
||||
|
||||
$this->assertIsArray($aResult, 'Expected result to be an array when input is null.');
|
||||
$this->assertEmpty($aResult, 'Expected result to be empty array when input is null.');
|
||||
}
|
||||
|
||||
public function testExecuteCleanup_DeleteOneObjPerClass()
|
||||
{
|
||||
$this->GivenDFRTreeInDB(<<<EOF
|
||||
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_2
|
||||
EOF);
|
||||
|
||||
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||
$oService = new StaticDeletionPlan();
|
||||
$aRes = $oService->GetStaticDeletionPlan($aClasses);
|
||||
|
||||
var_export($aRes);
|
||||
|
||||
var_export($this->aIdByClass);
|
||||
|
||||
self::assertTrue(true);
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,15 @@
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="extkey2_id" xsi:type="AttributeExternalKey">
|
||||
<sql>extkey2_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<target_class>DFRToRemove</target_class>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
@@ -145,49 +154,6 @@
|
||||
</presentation>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
</class>
|
||||
<class id="DFRToRemoveLeaf" _created_in="itop-structure" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>dfrtoremoveleaf</db_table>
|
||||
<naming>
|
||||
<attributes/>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes/>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="desc" xsi:type="AttributeString">
|
||||
<sql>desc</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
<dependencies/>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items/>
|
||||
</list>
|
||||
<search>
|
||||
<items/>
|
||||
</search>
|
||||
<details>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="desc">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
<parent>DFRToRemove</parent>
|
||||
</class>
|
||||
<class id="DFRRemovedCollateralCascade" _created_in="itop-structure" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
@@ -292,6 +258,92 @@
|
||||
</presentation>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
</class>
|
||||
<class id="DFRLeafNotToRemove" _created_in="itop-structure" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>dfrleafnottoremove</db_table>
|
||||
<naming>
|
||||
<attributes/>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes/>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="info" xsi:type="AttributeString">
|
||||
<sql>info</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
<dependencies/>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items/>
|
||||
</list>
|
||||
<search>
|
||||
<items/>
|
||||
</search>
|
||||
<details>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="info">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
<parent>DFRToRemove</parent>
|
||||
</class>
|
||||
<class id="DFRToRemoveLeaf" _created_in="itop-structure" _delta="define">
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
<db_table>dfrtoremoveleaf</db_table>
|
||||
<naming>
|
||||
<attributes/>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes/>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="desc" xsi:type="AttributeString">
|
||||
<sql>desc</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<validation_pattern/>
|
||||
<dependencies/>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items/>
|
||||
</list>
|
||||
<search>
|
||||
<items/>
|
||||
</search>
|
||||
<details>
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="desc">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
<parent>DFRToRemove</parent>
|
||||
</class>
|
||||
</classes>
|
||||
<dictionaries>
|
||||
<dictionary id="EN US">
|
||||
|
||||
@@ -59,7 +59,7 @@ foreach ($aAddedExtensions as $iIndex => $sExtensionCode) {
|
||||
}
|
||||
}
|
||||
|
||||
$sRemovedExtensions = utils::ReadParam('removed_modules', '', false, 'raw');
|
||||
$sRemovedExtensions = utils::ReadParam('removed_modules', 'itop-container-mgmt', false, 'raw');
|
||||
$aRemovedExtensionsAndModules = [];
|
||||
if (mb_strlen($sRemovedExtensions) > 0) {
|
||||
$aRemovedExtensionsAndModules = explode(',', $sRemovedExtensions);
|
||||
|
||||
Reference in New Issue
Block a user