mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-23 09:12:16 +02:00
Compare commits
9 Commits
feature/96
...
feature/91
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fd25be17c | ||
|
|
016c7d5fc1 | ||
|
|
d61ddadaa4 | ||
|
|
e8e842dcea | ||
|
|
9b90ed3983 | ||
|
|
04380802b6 | ||
|
|
963da15510 | ||
|
|
ebbdb426fc | ||
|
|
8534b5af7e |
@@ -1,5 +1,121 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||||
|
<classes>
|
||||||
|
<class id="DataFeatureRemovalBackgroundOperation" _delta="define">
|
||||||
|
<properties>
|
||||||
|
<category>bizmodel,searchable</category>
|
||||||
|
<abstract>false</abstract>
|
||||||
|
<db_table>datafeatureremovalbackgroundoperation</db_table>
|
||||||
|
<style>
|
||||||
|
<icon>
|
||||||
|
<fileref ref="icons8-electricity_643cf7fd7a024968679dc0c35a710a03"/>
|
||||||
|
</icon>
|
||||||
|
<main_color>#0000ff</main_color>
|
||||||
|
</style>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
<uniqueness_rules>
|
||||||
|
<rule id="list_of_classes">
|
||||||
|
<attributes>
|
||||||
|
<attribute id="classes"/>
|
||||||
|
</attributes>
|
||||||
|
<filter><![CDATA[]]></filter>
|
||||||
|
<disabled>false</disabled>
|
||||||
|
<is_blocking>true</is_blocking>
|
||||||
|
</rule>
|
||||||
|
</uniqueness_rules>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="creation_date" xsi:type="AttributeDateTime">
|
||||||
|
<sql>creation_date</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="features_code" xsi:type="AttributeText">
|
||||||
|
<sql>features_code</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<width/>
|
||||||
|
<height/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="classes" xsi:type="AttributeText">
|
||||||
|
<sql>classes</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<width/>
|
||||||
|
<height/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
</fields>
|
||||||
|
<methods/>
|
||||||
|
<presentation>
|
||||||
|
<list>
|
||||||
|
<items>
|
||||||
|
<item id="creation_date">
|
||||||
|
<rank>10</rank>
|
||||||
|
</item>
|
||||||
|
<item id="features_code">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
<item id="classes">
|
||||||
|
<rank>30</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</list>
|
||||||
|
<search>
|
||||||
|
<items/>
|
||||||
|
</search>
|
||||||
|
<details>
|
||||||
|
<items>
|
||||||
|
<item id="creation_date">
|
||||||
|
<rank>10</rank>
|
||||||
|
</item>
|
||||||
|
<item id="features_code">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
<item id="classes">
|
||||||
|
<rank>30</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</presentation>
|
||||||
|
<parent>cmdbAbstractObject</parent>
|
||||||
|
</class>
|
||||||
|
</classes>
|
||||||
|
<dictionaries>
|
||||||
|
<dictionary id="EN US">
|
||||||
|
<entries>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation" _delta="define"><![CDATA[DataFeatureRemovalBackgroundOperation]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:creation_date" _delta="define"><![CDATA[Creation date]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:creation_date+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:features_code" _delta="define"><![CDATA[Features code]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:features_code+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:classes" _delta="define"><![CDATA[Classes]]></entry>
|
||||||
|
<entry id="Class:DataFeatureRemovalBackgroundOperation/Attribute:classes+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
</entries>
|
||||||
|
</dictionary>
|
||||||
|
</dictionaries>
|
||||||
|
<files>
|
||||||
|
<file id="icons8-electricity_643cf7fd7a024968679dc0c35a710a03" xsi:type="File" _delta="define_if_not_exists">
|
||||||
|
<name>images/icons/icons8-electricity.svg</name>
|
||||||
|
<mime_type>image/svg+xml</mime_type>
|
||||||
|
<data>PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSIyNDBweCIgaGVpZ2h0PSIyNDBweCI+PHBhdGggZmlsbD0iIzM3YzZkMCIgZD0iTTI2LjQ1MTIsMzdsNy43NzY0Ni0xNS41NTI5MWExLDEsMCwwLDAtLjg5NDM1LTEuNDQ3MjJMMjIuOTUxMiwxOS45OTkyNWw2LjMzNi0xMy41NzYzNUExLDEsMCwwLDAsMjguMzgxLDVIMjIuNTk2MzlhMSwxLDAsMCwwLS45MTExMS41ODc4M2wtOC41OTUyNCwxOUExLDEsMCwwLDAsMTQuMDAxMTUsMjZoMTAuNDVsLTUuNSwxMVoiLz48cGF0aCBmaWxsPSIjMzdjNmQwIiBkPSJNMTYuMjIyODYsMzdIMjkuODY0NzFhLjU1NzM1LjU1NzM1LDAsMCwxLC4zNTgxNSwxTDE5Ljk2LDQ0LjM2N2ExLjAzMzY0LDEuMDMzNjQsMCwwLDEtMS40OTEyMS0uNDI1ODZMMTUuNzIyODYsMzcuNzVBLjUwNDUuNTA0NSwwLDAsMSwxNi4yMjI4NiwzN1oiLz48L3N2Zz4=</data>
|
||||||
|
</file>
|
||||||
|
</files>
|
||||||
<menus>
|
<menus>
|
||||||
<menu id="DataFeatureRemovalMenu" xsi:type="WebPageMenuNode" _delta="define">
|
<menu id="DataFeatureRemovalMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||||
<rank>30</rank>
|
<rank>30</rank>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ Dict::Add('EN US', 'English', 'English', [
|
|||||||
'DataFeatureRemoval:Features:Title' => 'Features',
|
'DataFeatureRemoval:Features:Title' => 'Features',
|
||||||
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
||||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
|
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
|
||||||
|
'DataFeatureRemoval:Analysis:Ok' => "No data to cleanup",
|
||||||
|
|
||||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
|
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
|
||||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s rows to clean before continuing',
|
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s rows to clean before continuing',
|
||||||
@@ -40,6 +41,7 @@ Dict::Add('EN US', 'English', 'English', [
|
|||||||
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
||||||
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
|
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
|
||||||
'UI:Button:DoDeletion' => 'Delete data',
|
'UI:Button:DoDeletion' => 'Delete data',
|
||||||
|
'UI:Button:DoAsyncDeletion' => 'Do asynchronous deletion',
|
||||||
'UI:Button:BackToMain' => 'Back to Feature Removal',
|
'UI:Button:BackToMain' => 'Back to Feature Removal',
|
||||||
'UI:Button:Setup' => 'Back to setup',
|
'UI:Button:Setup' => 'Back to setup',
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
|||||||
'DataFeatureRemoval:Features:Title' => 'Fonctionnalités',
|
'DataFeatureRemoval:Features:Title' => 'Fonctionnalités',
|
||||||
'DataFeatureRemoval:Analysis:Title' => 'Résultat de l’analyse',
|
'DataFeatureRemoval:Analysis:Title' => 'Résultat de l’analyse',
|
||||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s élément(s) à nettoyer avant de poursuivre',
|
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s élément(s) à nettoyer avant de poursuivre',
|
||||||
|
'DataFeatureRemoval:Analysis:Ok' => "Aucune donnée à nettoyer",
|
||||||
|
|
||||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression',
|
'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression',
|
||||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s ligne(s) à nettoyer avant de poursuivre',
|
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s ligne(s) à nettoyer avant de poursuivre',
|
||||||
@@ -39,6 +40,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
|||||||
'UI:Button:ModifyChoices' => 'Modifier les choix',
|
'UI:Button:ModifyChoices' => 'Modifier les choix',
|
||||||
'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir l’assistant de configuration',
|
'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir l’assistant de configuration',
|
||||||
'UI:Button:PlanDeletion' => 'Préparer le plan de suppression',
|
'UI:Button:PlanDeletion' => 'Préparer le plan de suppression',
|
||||||
|
'UI:Button:DoAsyncDeletion' => 'Lancer la suppression en tâche de fond',
|
||||||
'UI:Button:DoDeletion' => 'Supprimer les données',
|
'UI:Button:DoDeletion' => 'Supprimer les données',
|
||||||
'UI:Button:BackToMain' => 'Retour à la suppression de fonctionnalités',
|
'UI:Button:BackToMain' => 'Retour à la suppression de fonctionnalités',
|
||||||
'UI:Button:Setup' => 'Retour à l’assistant de configuration',
|
'UI:Button:Setup' => 'Retour à l’assistant de configuration',
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ SetupWebPage::AddModule(
|
|||||||
'datamodel' => [
|
'datamodel' => [
|
||||||
'vendor/autoload.php',
|
'vendor/autoload.php',
|
||||||
'model.combodo-data-feature-removal.php', // Contains the PHP code generated by the "compilation" of datamodel.combodo-data-feature-removal.xml
|
'model.combodo-data-feature-removal.php', // Contains the PHP code generated by the "compilation" of datamodel.combodo-data-feature-removal.xml
|
||||||
|
'src/Hook/DataFeatureRemovalBackgroundTask.php',
|
||||||
],
|
],
|
||||||
'webservice' => [],
|
'webservice' => [],
|
||||||
'data.struct' => [
|
'data.struct' => [
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
|||||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalConfig;
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalConfig;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Service\BackgroundOperationService;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService;
|
use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
||||||
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
||||||
@@ -39,15 +40,19 @@ class DataFeatureRemovalController extends Controller
|
|||||||
$this->AddAnalyzeParams();
|
$this->AddAnalyzeParams();
|
||||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||||
$aParams['aExtensions'] = $this->GetExtensionsTable();
|
$aParams['aExtensions'] = $this->GetExtensionsTable();
|
||||||
|
$aParams['aExtensionsCode'] = $this->aSelectedExtensionsForCheck;
|
||||||
$aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable;
|
$aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable;
|
||||||
$aParams['aClasses'] = array_keys($this->aCountClassesToCleanup);
|
$aParams['aClasses'] = array_keys($this->aCountClassesToCleanup);
|
||||||
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
|
|
||||||
$aParams['bHasData'] = $this->iCount > 0;
|
$aParams['bHasData'] = $this->iCount > 0;
|
||||||
$aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup';
|
$aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup';
|
||||||
$aParams['iCount'] = $this->iCount;
|
$aParams['iCount'] = $this->iCount;
|
||||||
|
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
|
||||||
|
$aParams['bAnalysisOk'] = (count($this->aCountClassesToCleanup) > 0) && ($this->iCount === 0);
|
||||||
|
|
||||||
$this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css');
|
$this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css');
|
||||||
$this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js');
|
$this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js');
|
||||||
|
|
||||||
|
$this->m_sOperation = "Main";
|
||||||
$this->DisplayPage($aParams);
|
$this->DisplayPage($aParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +127,7 @@ class DataFeatureRemovalController extends Controller
|
|||||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||||
$aParams['aDeletionPlanSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
$aParams['aDeletionPlanSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||||
$aParams['aClasses'] = $aClasses;
|
$aParams['aClasses'] = $aClasses;
|
||||||
|
$aParams['aExtensionsCode'] = utils::ReadPostedParam('aExtensionsCode', []);
|
||||||
$aParams['iQueryCount'] = $iQueryCount;
|
$aParams['iQueryCount'] = $iQueryCount;
|
||||||
$aParams['bDeletionPossible'] = ($iQueryCount <= DataFeatureRemovalConfig::GetInstance()->Get('max_count_estimation_for_safe_cleanup', 100));
|
$aParams['bDeletionPossible'] = ($iQueryCount <= DataFeatureRemovalConfig::GetInstance()->Get('max_count_estimation_for_safe_cleanup', 100));
|
||||||
|
|
||||||
@@ -134,6 +140,14 @@ class DataFeatureRemovalController extends Controller
|
|||||||
$this->ValidateTransactionId();
|
$this->ValidateTransactionId();
|
||||||
|
|
||||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||||
|
$sDeletionButtonValue = utils::ReadPostedParam('btn_deletion', null);
|
||||||
|
$bAsynchronous = ('async_deletion' === $sDeletionButtonValue);
|
||||||
|
|
||||||
|
if ($bAsynchronous) {
|
||||||
|
BackgroundOperationService::GetInstance()->CreateOperation(utils::ReadPostedParam('aExtensionsCode', []), $aClasses);
|
||||||
|
$this->OperationMain();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$aDeletionExecutionSummary = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
$aDeletionExecutionSummary = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
||||||
$aColumns = ['Class', 'DeletedCount' , 'UpdatedCount'];
|
$aColumns = ['Class', 'DeletedCount' , 'UpdatedCount'];
|
||||||
@@ -164,16 +178,24 @@ class DataFeatureRemovalController extends Controller
|
|||||||
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
||||||
/** @var \iTopExtension $oExtension */
|
/** @var \iTopExtension $oExtension */
|
||||||
|
|
||||||
|
$bCleanupOngoing = BackgroundOperationService::GetInstance()->IsExtensionBeingCleaned($sCode);
|
||||||
$sChecked = '';
|
$sChecked = '';
|
||||||
$sDisabledHtml = '';
|
$sDisabledHtml = '';
|
||||||
if ($oExtension->bRemovedFromDisk) {
|
|
||||||
|
$sLabel = $oExtension->sLabel;
|
||||||
|
if ($bCleanupOngoing) {
|
||||||
|
$sDisabledHtml = 'disabled=""';
|
||||||
|
$sLabel .= <<<HTML
|
||||||
|
<span class="ibo-spinner ibo-is-inline ibo-spinner ibo-block" data-role="ibo-spinner"><i class="ibo-spinner--icon fas fa-sync-alt fa-spin" aria-hidden="true"/></span>
|
||||||
|
HTML;
|
||||||
|
;
|
||||||
|
} elseif ($oExtension->bRemovedFromDisk) {
|
||||||
$sDisabledHtml = 'disabled=""';
|
$sDisabledHtml = 'disabled=""';
|
||||||
$sChecked = 'checked';
|
$sChecked = 'checked';
|
||||||
} elseif (in_array($sCode, $this->aSelectedExtensionsForCheck)) {
|
} elseif (in_array($sCode, $this->aSelectedExtensionsForCheck)) {
|
||||||
$sChecked = 'checked';
|
$sChecked = 'checked';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sLabel = $oExtension->sLabel;
|
|
||||||
$sVersion = $oExtension->sVersion;
|
$sVersion = $oExtension->sVersion;
|
||||||
$sIdEnable = "aExtensions[$sCode][enable]";
|
$sIdEnable = "aExtensions[$sCode][enable]";
|
||||||
|
|
||||||
@@ -231,12 +253,12 @@ HTML,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return void
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function ReadRemovedExtensions(): void
|
public function ReadRemovedExtensions(): array
|
||||||
{
|
{
|
||||||
if (count($this->aSelectedExtensionsForCheck) > 0) {
|
if (count($this->aSelectedExtensionsForCheck) > 0) {
|
||||||
return;
|
return $this->aSelectedExtensionsForCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
|
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
|
||||||
@@ -253,5 +275,7 @@ HTML,
|
|||||||
$this->aSelectedExtensionsForCheck[] = $sCode;
|
$this->aSelectedExtensionsForCheck[] = $sCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->aSelectedExtensionsForCheck;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
||||||
|
|
||||||
|
use Config;
|
||||||
use MetaModel;
|
use MetaModel;
|
||||||
use utils;
|
use utils;
|
||||||
|
|
||||||
@@ -49,4 +50,22 @@ class DataFeatureRemovalConfig
|
|||||||
$oConfig = utils::GetConfig();
|
$oConfig = utils::GetConfig();
|
||||||
$oConfig->SetModuleSetting(DataFeatureRemovalHelper::MODULE_NAME, $sParamName, $value);
|
$oConfig->SetModuleSetting(DataFeatureRemovalHelper::MODULE_NAME, $sParamName, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Config|null $oConfig
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \ConfigException
|
||||||
|
* @throws \CoreException
|
||||||
|
*/
|
||||||
|
public function SaveItopConfiguration(Config $oConfig = null)
|
||||||
|
{
|
||||||
|
if (is_null($oConfig)) {
|
||||||
|
$oConfig = utils::GetConfig();
|
||||||
|
}
|
||||||
|
$sConfigFile = APPROOT.'conf/'.utils::GetCurrentEnvironment().'/config-itop.php';
|
||||||
|
@chmod($sConfigFile, 0770); // Allow overwriting the file
|
||||||
|
$oConfig->WriteToFile($sConfigFile);
|
||||||
|
@chmod($sConfigFile, 0444); // Read-only
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,14 @@ namespace Combodo\iTop\DataFeatureRemoval\Helper;
|
|||||||
class DataFeatureRemovalHelper
|
class DataFeatureRemovalHelper
|
||||||
{
|
{
|
||||||
public const MODULE_NAME = 'combodo-data-feature-removal';
|
public const MODULE_NAME = 'combodo-data-feature-removal';
|
||||||
|
|
||||||
|
public static function IsTimeLimitExceeded(int $iUnixTimeLimit): bool
|
||||||
|
{
|
||||||
|
if ($iUnixTimeLimit === 0) {
|
||||||
|
//no time limit
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (time() > $iUnixTimeLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalConfig;
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Service\BackgroundOperationService;
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
||||||
|
|
||||||
|
class DataFeatureRemovalBackgroundTask implements iBackgroundProcess
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function GetPeriodicity()
|
||||||
|
{
|
||||||
|
return DataFeatureRemovalConfig::GetInstance()->Get('cron_periodicity_in_s', 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function Process($iUnixTimeLimit)
|
||||||
|
{
|
||||||
|
$iCount = 0;
|
||||||
|
while ($oBackgroundOperation = BackgroundOperationService::GetInstance()->GetNext()) {
|
||||||
|
$aClasses = BackgroundOperationService::GetInstance()->GetClasses($oBackgroundOperation);
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses, $iUnixTimeLimit);
|
||||||
|
|
||||||
|
IssueLog::Info(__METHOD__, null, $aRes);
|
||||||
|
|
||||||
|
IssueLog::Debug(__METHOD__, null, [
|
||||||
|
'$iUnixTimeLimit' => $iUnixTimeLimit,
|
||||||
|
'time' => time(),
|
||||||
|
'timeout reached' => DataFeatureRemovalHelper::IsTimeLimitExceeded($iUnixTimeLimit),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (DataFeatureRemovalHelper::IsTimeLimitExceeded($iUnixTimeLimit)) {
|
||||||
|
//timeout reached
|
||||||
|
return "Handled $iCount operations.";
|
||||||
|
}
|
||||||
|
|
||||||
|
//execution finished before timeout: nothing left to remove
|
||||||
|
$oBackgroundOperation->DBDelete();
|
||||||
|
$iCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Handled $iCount operations.";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Combodo\iTop\DataFeatureRemoval\Service;
|
||||||
|
|
||||||
|
use DataFeatureRemovalBackgroundOperation;
|
||||||
|
use DBObjectSet;
|
||||||
|
use DBSearch;
|
||||||
|
use MetaModel;
|
||||||
|
|
||||||
|
class BackgroundOperationService
|
||||||
|
{
|
||||||
|
private static BackgroundOperationService $oInstance;
|
||||||
|
|
||||||
|
protected function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function GetInstance(): BackgroundOperationService
|
||||||
|
{
|
||||||
|
if (!isset(self::$oInstance)) {
|
||||||
|
self::$oInstance = new BackgroundOperationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function SetInstance(?BackgroundOperationService $oInstance): void
|
||||||
|
{
|
||||||
|
static::$oInstance = $oInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DataFeatureRemovalBackgroundOperation
|
||||||
|
* @throws \CoreException
|
||||||
|
* @throws \CoreUnexpectedValue
|
||||||
|
* @throws \MySQLException
|
||||||
|
* @throws \OQLException
|
||||||
|
*/
|
||||||
|
public function GetNext(): ?DataFeatureRemovalBackgroundOperation
|
||||||
|
{
|
||||||
|
$sOQL = <<<OQL
|
||||||
|
SELECT DataFeatureRemovalBackgroundOperation
|
||||||
|
OQL;
|
||||||
|
|
||||||
|
$oSet = new DBObjectSet(DBSearch::FromOQL($sOQL), ['creation_date' => true]);
|
||||||
|
/** @var DataFeatureRemovalBackgroundOperation $oDBObject */
|
||||||
|
$oDBObject = $oSet->Fetch();
|
||||||
|
|
||||||
|
return $oDBObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $aExtensionsCodes
|
||||||
|
* @param array $aClasses
|
||||||
|
* @return void
|
||||||
|
* @throws \ArchivedObjectException
|
||||||
|
* @throws \CoreCannotSaveObjectException
|
||||||
|
* @throws \CoreException
|
||||||
|
* @throws \CoreUnexpectedValue
|
||||||
|
* @throws \CoreWarning
|
||||||
|
* @throws \MySQLException
|
||||||
|
* @throws \OQLException
|
||||||
|
*/
|
||||||
|
public function CreateOperation(array $aExtensionsCodes, array $aClasses): void
|
||||||
|
{
|
||||||
|
sort($aExtensionsCodes);
|
||||||
|
sort($aClasses);
|
||||||
|
|
||||||
|
$aValues = [
|
||||||
|
'creation_date' => time(),
|
||||||
|
'features_code' => '|'.implode('|', $aExtensionsCodes).'|',
|
||||||
|
'classes' => implode(',', $aClasses),
|
||||||
|
];
|
||||||
|
$oObj = MetaModel::NewObject('DataFeatureRemovalBackgroundOperation', $aValues);
|
||||||
|
$oObj->DBWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sExtensionCode
|
||||||
|
* @return bool
|
||||||
|
* @throws \CoreException
|
||||||
|
* @throws \MissingQueryArgument
|
||||||
|
* @throws \MySQLException
|
||||||
|
* @throws \MySQLHasGoneAwayException
|
||||||
|
* @throws \OQLException
|
||||||
|
*/
|
||||||
|
public function IsExtensionBeingCleaned(string $sExtensionCode): bool
|
||||||
|
{
|
||||||
|
$sOQL = <<<OQL
|
||||||
|
SELECT DataFeatureRemovalBackgroundOperation WHERE features_code LIKE '%|$sExtensionCode|%'
|
||||||
|
OQL;
|
||||||
|
|
||||||
|
$oSet = new DBObjectSet(DBSearch::FromOQL($sOQL));
|
||||||
|
return $oSet->Count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DataFeatureRemovalBackgroundOperation $oBackgroundOperation
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function GetClasses(DataFeatureRemovalBackgroundOperation $oBackgroundOperation): array
|
||||||
|
{
|
||||||
|
return explode(',', $oBackgroundOperation->Get('classes'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ namespace Combodo\iTop\DataFeatureRemoval\Service;
|
|||||||
use CMDBSource;
|
use CMDBSource;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity;
|
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||||
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||||
use DBObjectSearch;
|
use DBObjectSearch;
|
||||||
use DeletionPlan;
|
use DeletionPlan;
|
||||||
use MetaModel;
|
use MetaModel;
|
||||||
@@ -13,6 +14,8 @@ class DeletionPlanService
|
|||||||
{
|
{
|
||||||
private static DeletionPlanService $oInstance;
|
private static DeletionPlanService $oInstance;
|
||||||
|
|
||||||
|
public int $iExecutionCount = 0;
|
||||||
|
|
||||||
protected function __construct()
|
protected function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -89,7 +92,10 @@ class DeletionPlanService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @since 3.3.0
|
||||||
* @param array $aClasses
|
* @param array $aClasses
|
||||||
|
* @param int $iUnixTimeLimit : max execution time in seconds since Epoch before stopping deletion. by default: no limit (ie remove all without stop)
|
||||||
|
* @param int $iMaxExecutionCount : max execution count before stopping deletion. by default: no limit (ie remove all without stop)
|
||||||
*
|
*
|
||||||
* @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity>
|
* @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity>
|
||||||
* @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException
|
* @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException
|
||||||
@@ -97,7 +103,7 @@ class DeletionPlanService
|
|||||||
* @throws \CoreUnexpectedValue
|
* @throws \CoreUnexpectedValue
|
||||||
* @throws \MySQLException
|
* @throws \MySQLException
|
||||||
*/
|
*/
|
||||||
public function ExecuteDeletionPlan(array $aClasses): array
|
public function ExecuteDeletionPlan(array $aClasses, int $iUnixTimeLimit = 0, int $iMaxExecutionCount = -1): array
|
||||||
{
|
{
|
||||||
$oDeletionPlan = $this->GetDeletionPlan($aClasses);
|
$oDeletionPlan = $this->GetDeletionPlan($aClasses);
|
||||||
|
|
||||||
@@ -105,11 +111,19 @@ class DeletionPlanService
|
|||||||
throw new DataFeatureRemovalException("Deletion Plan cannot be executed due to issues");
|
throw new DataFeatureRemovalException("Deletion Plan cannot be executed due to issues");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->iExecutionCount = 0;
|
||||||
|
|
||||||
$aSummary = [];
|
$aSummary = [];
|
||||||
foreach ($oDeletionPlan->ListUpdates() as $sClass => $aToUpdate) {
|
foreach ($oDeletionPlan->ListUpdates() as $sClass => $aToUpdate) {
|
||||||
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
||||||
|
|
||||||
foreach ($aToUpdate as $aData) {
|
foreach ($aToUpdate as $aData) {
|
||||||
|
if ($this->IsTimeLimitExceeded($iUnixTimeLimit, $iMaxExecutionCount)) {
|
||||||
|
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||||
|
return $aSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->iExecutionCount++;
|
||||||
$oToUpdate = $aData['to_reset'];
|
$oToUpdate = $aData['to_reset'];
|
||||||
/** @var \DBObject $oToUpdate */
|
/** @var \DBObject $oToUpdate */
|
||||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) {
|
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) {
|
||||||
@@ -126,6 +140,13 @@ class DeletionPlanService
|
|||||||
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
$oDeletionPlanSummaryEntity = $aSummary[$sClass] ?? new DeletionPlanSummaryEntity($sClass);
|
||||||
|
|
||||||
foreach ($aDeletes as $sId => $aDelete) {
|
foreach ($aDeletes as $sId => $aDelete) {
|
||||||
|
if ($this->IsTimeLimitExceeded($iUnixTimeLimit, $iMaxExecutionCount)) {
|
||||||
|
$aSummary[$sClass] = $oDeletionPlanSummaryEntity;
|
||||||
|
return $aSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->iExecutionCount++;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CMDBSource::Query('START TRANSACTION');
|
CMDBSource::Query('START TRANSACTION');
|
||||||
// Delete any existing change tracking about the current object
|
// Delete any existing change tracking about the current object
|
||||||
@@ -144,7 +165,7 @@ class DeletionPlanService
|
|||||||
|
|
||||||
CMDBSource::Query('COMMIT');
|
CMDBSource::Query('COMMIT');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\IssueLog::Exception(__METHOD__.': Cleanup failed', $e);
|
\IssueLog::Exception(__METHOD__.": Cleanup failed", $e);
|
||||||
CMDBSource::Query('ROLLBACK');
|
CMDBSource::Query('ROLLBACK');
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
@@ -179,4 +200,13 @@ class DeletionPlanService
|
|||||||
|
|
||||||
return $oDeletionPlan;
|
return $oDeletionPlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function IsTimeLimitExceeded(int $iUnixTimeLimit, int $iMaxExecutionCount = -1): bool
|
||||||
|
{
|
||||||
|
if (($iMaxExecutionCount !== -1) && ($iMaxExecutionCount <= $this->iExecutionCount)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataFeatureRemovalHelper::IsTimeLimitExceeded($iUnixTimeLimit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,15 @@
|
|||||||
{% for sKey, sClass in aClasses %}
|
{% for sKey, sClass in aClasses %}
|
||||||
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for sKey, sCode in aExtensionsCode %}
|
||||||
|
{% UIInput ForHidden { sName:"aExtensionsCode[" ~ sKey ~ "]", sValue:sCode } %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% UIToolbar ForButton {} %}
|
{% UIToolbar ForButton {} %}
|
||||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||||
{% EndUIToolbar %}
|
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoAsyncDeletion'|dict_s, sName:'btn_deletion', sId:'btn_async_deletion', sValue: 'async_deletion', bIsSubmit:true} %}
|
||||||
|
{% EndUIToolbar %}
|
||||||
{% EndUIForm %}
|
{% EndUIForm %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ 'DataFeatureRemoval:DeletionPlan:ToManyOperations'|dict_s }}
|
{{ 'DataFeatureRemoval:DeletionPlan:ToManyOperations'|dict_s }}
|
||||||
|
|||||||
@@ -12,8 +12,13 @@
|
|||||||
{% for sKey, sClass in aClasses %}
|
{% for sKey, sClass in aClasses %}
|
||||||
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for sKey, sCode in aExtensionsCode %}
|
||||||
|
{% UIInput ForHidden { sName:"aExtensionsCode[" ~ sKey ~ "]", sValue:sCode } %}
|
||||||
|
{% endfor %}
|
||||||
{% UIToolbar ForButton {} %}
|
{% UIToolbar ForButton {} %}
|
||||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:PlanDeletion'|dict_s, sName:'btn_plandeletion', sId:'btn_plandeletion', bIsSubmit:true} %}
|
{% UIButton ForPrimaryAction {sLabel:'UI:Button:PlanDeletion'|dict_s, sName:'btn_plandeletion', sId:'btn_plandeletion', bIsSubmit:true} %}
|
||||||
{% EndUIToolbar %}
|
{% EndUIToolbar %}
|
||||||
{% EndUIForm %}
|
{% EndUIForm %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
{% include 'Features.html.twig' %}
|
{% include 'Features.html.twig' %}
|
||||||
{% include 'ExtensionRemovalData.html.twig' %}
|
{% include 'ExtensionRemovalData.html.twig' %}
|
||||||
|
|
||||||
{% if not bHasData %}
|
{% if bAnalysisOk %}
|
||||||
|
{{ "DataFeatureRemoval:Analysis:Ok"|dict_s }}
|
||||||
|
|
||||||
{% UIToolbar ForButton {} %}
|
{% UIToolbar ForButton {} %}
|
||||||
<a href="{{ sSetupUrl }}">
|
<a href="{{ sSetupUrl }}">
|
||||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:false} %}
|
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:false} %}
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ if (PHP_VERSION_ID < 50600) {
|
|||||||
echo $err;
|
echo $err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new RuntimeException($err);
|
trigger_error(
|
||||||
|
$err,
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ return array(
|
|||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => $baseDir . '/src/Helper/DataFeatureRemovalLog.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => $baseDir . '/src/Helper/DataFeatureRemovalLog.php',
|
||||||
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\BackgroundOperationService' => $baseDir . '/src/Service/BackgroundOperationService.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => $baseDir . '/src/Service/DeletionPlanService.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => $baseDir . '/src/Service/DeletionPlanService.php',
|
||||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
|
|||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalLog.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalLog.php',
|
||||||
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\BackgroundOperationService' => __DIR__ . '/../..' . '/src/Service/BackgroundOperationService.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php',
|
||||||
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => __DIR__ . '/../..' . '/src/Service/DeletionPlanService.php',
|
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DeletionPlanService' => __DIR__ . '/../..' . '/src/Service/DeletionPlanService.php',
|
||||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ namespace Combodo\iTop\Test\UnitTest\Module\DataFeatureRemoval\Service;
|
|||||||
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity;
|
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanSummaryEntity;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||||
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
use Combodo\iTop\DataFeatureRemoval\Service\DeletionPlanService;
|
||||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||||
use DeletionPlan;
|
use DeletionPlan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for the DeletionPlanService class in the Combodo Data Feature Removal module.
|
* Unit tests for the DeletionPlanService cf Combodo Data Feature Removal module.
|
||||||
*
|
*
|
||||||
* These tests cover:
|
* These tests cover:
|
||||||
* - GetDeletionPlanSummary method: handling null and empty input, and verifying summary output for various delete/update scenarios.
|
* - GetDeletionPlanSummary method: handling null and empty input, and verifying summary output for various delete/update scenarios.
|
||||||
@@ -32,14 +32,8 @@ use DeletionPlan;
|
|||||||
* @see DeletionPlanSummaryEntity
|
* @see DeletionPlanSummaryEntity
|
||||||
* @see ItopDataTestCase
|
* @see ItopDataTestCase
|
||||||
*/
|
*/
|
||||||
class DeletionPlanServiceTest extends ItopDataTestCase
|
class DeletionPlanServiceTest extends ItopCustomDatamodelTestCase
|
||||||
{
|
{
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
$this->RequireOnceItopFile('env-production/combodo-data-feature-removal/vendor/autoload.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
//--- GetDeletionPlanSummary tests ---
|
//--- GetDeletionPlanSummary tests ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -255,8 +249,6 @@ class DeletionPlanServiceTest extends ItopDataTestCase
|
|||||||
*/
|
*/
|
||||||
public function testExecuteDeletionPlanThrowsExceptionWhenIssuesExist(): void
|
public function testExecuteDeletionPlanThrowsExceptionWhenIssuesExist(): void
|
||||||
{
|
{
|
||||||
$this->RequireOnceItopFile('env-production/combodo-data-feature-removal/src/Helper/DataFeatureRemovalException.php');
|
|
||||||
|
|
||||||
$oDeletionPlan = $this->createMock(DeletionPlan::class);
|
$oDeletionPlan = $this->createMock(DeletionPlan::class);
|
||||||
$oDeletionPlan->method('GetIssues')->willReturn(['Some issue']);
|
$oDeletionPlan->method('GetIssues')->willReturn(['Some issue']);
|
||||||
$oDeletionPlan->method('ListDeletes')->willReturn([]);
|
$oDeletionPlan->method('ListDeletes')->willReturn([]);
|
||||||
@@ -274,4 +266,197 @@ class DeletionPlanServiceTest extends ItopDataTestCase
|
|||||||
|
|
||||||
$oMockService->ExecuteDeletionPlan(['SomeClass']);
|
$oMockService->ExecuteDeletionPlan(['SomeClass']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_DeleteAllWithoutLimit()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||||
|
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||||
|
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
||||||
|
$aExpected = [
|
||||||
|
['DFRToUpdate', 1, 0 ],
|
||||||
|
['DFRToRemoveLeaf', 0, 1 ],
|
||||||
|
['DFRRemovedCollateral', 0, 1 ],
|
||||||
|
['DFRRemovedCollateralCascade', 0, 1 ],
|
||||||
|
];
|
||||||
|
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_DeleteManyObjPerClassWithoutLimit()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||||
|
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||||
|
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_2 <- DFRToUpdate_2
|
||||||
|
DFRToRemoveLeaf_2 <- DFRRemovedCollateral_2
|
||||||
|
DFRRemovedCollateral_2 <- DFRRemovedCollateralCascade_2
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_3 <- DFRToUpdate_3
|
||||||
|
DFRToRemoveLeaf_3 <- DFRRemovedCollateral_3
|
||||||
|
DFRRemovedCollateral_3 <- DFRRemovedCollateralCascade_3
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
||||||
|
$aExpected = [
|
||||||
|
['DFRToUpdate', 3, 0 ],
|
||||||
|
['DFRToRemoveLeaf', 0, 3 ],
|
||||||
|
['DFRRemovedCollateral', 0, 3 ],
|
||||||
|
['DFRRemovedCollateralCascade', 0, 3 ],
|
||||||
|
];
|
||||||
|
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_ManualDeleteShouldFail()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRManual_1
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
$this->expectException(DataFeatureRemovalException::class);
|
||||||
|
$this->expectExceptionMessage('Deletion Plan cannot be executed due to issues');
|
||||||
|
DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function AssertSummaryEquals(array $expected, $actual, $sMessage = '')
|
||||||
|
{
|
||||||
|
$aExpected = [];
|
||||||
|
foreach ($expected as $line) {
|
||||||
|
$sClass = $line[0];
|
||||||
|
$iUpdate = $line[1];
|
||||||
|
$iDelete = $line[2];
|
||||||
|
|
||||||
|
$oDeletionPlanSummaryEntity = new DeletionPlanSummaryEntity($sClass);
|
||||||
|
$oDeletionPlanSummaryEntity->iUpdateCount = $iUpdate;
|
||||||
|
$oDeletionPlanSummaryEntity->iDeleteCount = $iDelete;
|
||||||
|
$aExpected[$sClass] = $oDeletionPlanSummaryEntity;
|
||||||
|
}
|
||||||
|
$this->assertEquals($aExpected, $actual, $sMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_StopInUpdates()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||||
|
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||||
|
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_2 <- DFRToUpdate_2
|
||||||
|
DFRToRemoveLeaf_2 <- DFRRemovedCollateral_2
|
||||||
|
DFRRemovedCollateral_2 <- DFRRemovedCollateralCascade_2
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_3 <- DFRToUpdate_3
|
||||||
|
DFRToRemoveLeaf_3 <- DFRRemovedCollateral_3
|
||||||
|
DFRRemovedCollateral_3 <- DFRRemovedCollateralCascade_3
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses, 0, 3);
|
||||||
|
$aExpected = [
|
||||||
|
['DFRToUpdate', 3, 0 ],
|
||||||
|
['DFRToRemoveLeaf', 0, 0 ],
|
||||||
|
];
|
||||||
|
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_StopInDeletes()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRToUpdate_1
|
||||||
|
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||||
|
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_2 <- DFRToUpdate_2
|
||||||
|
DFRToRemoveLeaf_2 <- DFRRemovedCollateral_2
|
||||||
|
DFRRemovedCollateral_2 <- DFRRemovedCollateralCascade_2
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_3 <- DFRToUpdate_3
|
||||||
|
DFRToRemoveLeaf_3 <- DFRRemovedCollateral_3
|
||||||
|
DFRRemovedCollateral_3 <- DFRRemovedCollateralCascade_3
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses, 0, 8);
|
||||||
|
$aExpected = [
|
||||||
|
['DFRToUpdate', 3, 0 ],
|
||||||
|
['DFRToRemoveLeaf', 0, 3 ],
|
||||||
|
['DFRRemovedCollateral', 0, 2 ],
|
||||||
|
];
|
||||||
|
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteDeletionPlan_WrongOrderDeletion()
|
||||||
|
{
|
||||||
|
$this->GivenDFRTreeInDB(<<<EOF
|
||||||
|
DFRToRemoveLeaf_1 <- DFRRemovedCollateral_1
|
||||||
|
DFRRemovedCollateral_1 <- DFRRemovedCollateralCascade_1
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_2 <- DFRRemovedCollateral_2
|
||||||
|
DFRRemovedCollateral_2 <- DFRRemovedCollateralCascade_2
|
||||||
|
|
||||||
|
DFRToRemoveLeaf_3 <- DFRRemovedCollateral_3
|
||||||
|
DFRRemovedCollateral_3 <- DFRRemovedCollateralCascade_3
|
||||||
|
EOF);
|
||||||
|
|
||||||
|
$aClasses = [ 'DFRToRemoveLeaf' ];
|
||||||
|
|
||||||
|
$oSet = new \DBObjectSet(\DBObjectSearch::FromOQL("SELECT DFRRemovedCollateral WHERE name='DFRRemovedCollateral_3'"));
|
||||||
|
$oExpectedObj = $oSet->Fetch();
|
||||||
|
self::assertNotNull($oExpectedObj);
|
||||||
|
|
||||||
|
$aRes = DeletionPlanService::GetInstance()->ExecuteDeletionPlan($aClasses, 0, 5);
|
||||||
|
$aExpected = [
|
||||||
|
['DFRToRemoveLeaf', 0, 3 ],
|
||||||
|
['DFRRemovedCollateral', 0, 2 ],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->AssertSummaryEquals($aExpected, $aRes);
|
||||||
|
|
||||||
|
$oSet = new \DBObjectSet(\DBObjectSearch::FromOQL("SELECT DFRRemovedCollateral WHERE name='DFRRemovedCollateral_3'"));
|
||||||
|
$oActualObj = $oSet->Fetch();
|
||||||
|
self::assertNotNull($oActualObj, "Deletion plan executed in wrong order: DFRRemovedCollateralCascade/DFRRemovedCollateral are not valid anymore");
|
||||||
|
self::assertEquals($oExpectedObj->GetKey(), $oActualObj->GetKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetDatamodelDeltaAbsPath(): string
|
||||||
|
{
|
||||||
|
return __DIR__.'/deletionplan_delta.xml';
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
list($sLeft, $sRight) = explode('<-', $sLine);
|
||||||
|
$sLeft = trim($sLeft);
|
||||||
|
|
||||||
|
$iLeftId = $this->aIdByObjectName[$sLeft] ?? 0;
|
||||||
|
if ($iLeftId === 0) {
|
||||||
|
list($sChildClass, ) = explode('_', $sLeft, 2);
|
||||||
|
$iLeftId = $this->GivenObjectInDB($sChildClass, ['name' => $sLeft]);
|
||||||
|
$this->aIdByObjectName[$sLeft] = $iLeftId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sRight = trim($sRight);
|
||||||
|
list($sChildClass, ) = explode('_', $sRight, 2);
|
||||||
|
$iRightId = $this->GivenObjectInDB($sChildClass, ['name' => $sRight, 'extkey_id' => $iLeftId]);
|
||||||
|
$this->aIdByObjectName[$sRight] = $iRightId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,346 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2">
|
||||||
|
<classes>
|
||||||
|
<class id="DFRToRemove" _created_in="itop-structure" _delta="define">
|
||||||
|
<properties>
|
||||||
|
<category>bizmodel,searchable</category>
|
||||||
|
<abstract>true</abstract>
|
||||||
|
<db_table>dfrtoremove</db_table>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="name" xsi:type="AttributeString">
|
||||||
|
<sql>name</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>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</presentation>
|
||||||
|
<parent>cmdbAbstractObject</parent>
|
||||||
|
</class>
|
||||||
|
<class id="DFRToUpdate" _created_in="itop-structure" _delta="define">
|
||||||
|
<properties>
|
||||||
|
<category>bizmodel,searchable</category>
|
||||||
|
<abstract>false</abstract>
|
||||||
|
<db_table>dfrtoupdate</db_table>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="name" xsi:type="AttributeString">
|
||||||
|
<sql>name</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>true</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="extkey_id" xsi:type="AttributeExternalKey">
|
||||||
|
<sql>extkey_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>
|
||||||
|
<list>
|
||||||
|
<items/>
|
||||||
|
</list>
|
||||||
|
<search>
|
||||||
|
<items/>
|
||||||
|
</search>
|
||||||
|
<details>
|
||||||
|
<items>
|
||||||
|
<item id="name">
|
||||||
|
<rank>10</rank>
|
||||||
|
</item>
|
||||||
|
<item id="extkey_id">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</presentation>
|
||||||
|
<parent>cmdbAbstractObject</parent>
|
||||||
|
</class>
|
||||||
|
<class id="DFRRemovedCollateral" _created_in="itop-structure" _delta="define">
|
||||||
|
<properties>
|
||||||
|
<category>bizmodel,searchable</category>
|
||||||
|
<abstract>false</abstract>
|
||||||
|
<db_table>dfrremovedcollateral</db_table>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="name" xsi:type="AttributeString">
|
||||||
|
<sql>name</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>true</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="extkey_id" xsi:type="AttributeExternalKey">
|
||||||
|
<sql>extkey_id</sql>
|
||||||
|
<filter/>
|
||||||
|
<dependencies/>
|
||||||
|
<is_null_allowed>false</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>
|
||||||
|
<list>
|
||||||
|
<items/>
|
||||||
|
</list>
|
||||||
|
<search>
|
||||||
|
<items/>
|
||||||
|
</search>
|
||||||
|
<details>
|
||||||
|
<items>
|
||||||
|
<item id="name">
|
||||||
|
<rank>10</rank>
|
||||||
|
</item>
|
||||||
|
<item id="extkey_id">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</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>
|
||||||
|
<abstract>false</abstract>
|
||||||
|
<db_table>dfrremovedcollateralcascade</db_table>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="name" xsi:type="AttributeString">
|
||||||
|
<sql>name</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>true</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="extkey_id" xsi:type="AttributeExternalKey">
|
||||||
|
<sql>extkey_id</sql>
|
||||||
|
<filter/>
|
||||||
|
<dependencies/>
|
||||||
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<target_class>DFRRemovedCollateral</target_class>
|
||||||
|
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||||
|
<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="extkey_id">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</presentation>
|
||||||
|
<parent>cmdbAbstractObject</parent>
|
||||||
|
</class>
|
||||||
|
<class id="DFRManual" _created_in="itop-structure" _delta="define">
|
||||||
|
<properties>
|
||||||
|
<category>bizmodel,searchable</category>
|
||||||
|
<abstract>false</abstract>
|
||||||
|
<db_table>dfrmanual</db_table>
|
||||||
|
<naming>
|
||||||
|
<attributes/>
|
||||||
|
</naming>
|
||||||
|
<reconciliation>
|
||||||
|
<attributes/>
|
||||||
|
</reconciliation>
|
||||||
|
</properties>
|
||||||
|
<fields>
|
||||||
|
<field id="name" xsi:type="AttributeString">
|
||||||
|
<sql>name</sql>
|
||||||
|
<default_value/>
|
||||||
|
<is_null_allowed>true</is_null_allowed>
|
||||||
|
<validation_pattern/>
|
||||||
|
<dependencies/>
|
||||||
|
<tracking_level>all</tracking_level>
|
||||||
|
</field>
|
||||||
|
<field id="extkey_id" xsi:type="AttributeExternalKey">
|
||||||
|
<sql>extkey_id</sql>
|
||||||
|
<filter/>
|
||||||
|
<dependencies/>
|
||||||
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<target_class>DFRToRemove</target_class>
|
||||||
|
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||||
|
<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="extkey_id">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</details>
|
||||||
|
</presentation>
|
||||||
|
<parent>cmdbAbstractObject</parent>
|
||||||
|
</class>
|
||||||
|
</classes>
|
||||||
|
<dictionaries>
|
||||||
|
<dictionary id="EN US">
|
||||||
|
<entries>
|
||||||
|
<entry id="Class:DFRToRemove/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemove/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemove" _delta="define"><![CDATA[DFRToRemove]]></entry>
|
||||||
|
<entry id="Class:DFRToRemove+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemove/Attribute:name" _delta="define"><![CDATA[Name]]></entry>
|
||||||
|
<entry id="Class:DFRToRemove/Attribute:name+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate" _delta="define"><![CDATA[DFRToUpdate]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/Attribute:name" _delta="define"><![CDATA[Name]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/Attribute:name+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/Attribute:extkey_id" _delta="define"><![CDATA[Dfrtoremove id]]></entry>
|
||||||
|
<entry id="Class:DFRToUpdate/Attribute:extkey_id+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral" _delta="define"><![CDATA[DFRRemovedCollateral]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/Attribute:name" _delta="define"><![CDATA[Name]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/Attribute:name+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/Attribute:extkey_id" _delta="define"><![CDATA[Dfrtoremove id]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateral/Attribute:extkey_id+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf" _delta="define"><![CDATA[DFRToRemoveLeaf]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf/Attribute:desc" _delta="define"><![CDATA[Desc]]></entry>
|
||||||
|
<entry id="Class:DFRToRemoveLeaf/Attribute:desc+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade" _delta="define"><![CDATA[DFRRemovedCollateralCascade]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/Attribute:name" _delta="define"><![CDATA[Name]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/Attribute:name+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/Attribute:extkey_id" _delta="define"><![CDATA[Dfrremovedcollateral id]]></entry>
|
||||||
|
<entry id="Class:DFRRemovedCollateralCascade/Attribute:extkey_id+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRManual/Name" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRManual/ComplementaryName" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRManual" _delta="define"><![CDATA[DFRManual]]></entry>
|
||||||
|
<entry id="Class:DFRManual+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRManual/Attribute:name" _delta="define"><![CDATA[Name]]></entry>
|
||||||
|
<entry id="Class:DFRManual/Attribute:name+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
<entry id="Class:DFRManual/Attribute:extkey_id" _delta="define"><![CDATA[Dfrtoremove id]]></entry>
|
||||||
|
<entry id="Class:DFRManual/Attribute:extkey_id+" _delta="define"><![CDATA[]]></entry>
|
||||||
|
</entries>
|
||||||
|
</dictionary>
|
||||||
|
</dictionaries>
|
||||||
|
</itop_design>
|
||||||
Reference in New Issue
Block a user