Files
iTop/core/deletionplan.class.inc.php

246 lines
6.1 KiB
PHP

<?php
/*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Algorithm to delete object(s) and maintain data integrity
*/
/**
* Deletion plan (other objects to be deleted/modified, eventual issues, etc.)
*
* @package iTopORM
*/
class DeletionPlan
{
//protected $m_aIssues;
protected $m_bFoundStopper;
protected $m_bFoundSecurityIssue;
protected $m_bFoundManualDelete;
protected $m_bFoundManualOperation;
protected $m_iToDelete;
protected $m_iToUpdate;
protected $m_aToDelete;
protected $m_aToUpdate;
protected static $m_aModeUpdate = [
DEL_SILENT => [
DEL_SILENT => DEL_SILENT,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL,
],
DEL_MANUAL => [
DEL_SILENT => DEL_MANUAL,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_MANUAL,
],
DEL_AUTO => [
DEL_SILENT => DEL_AUTO,
DEL_AUTO => DEL_AUTO,
DEL_MANUAL => DEL_AUTO,
],
];
public function __construct()
{
$this->m_iToDelete = 0;
$this->m_iToUpdate = 0;
$this->m_aToDelete = [];
$this->m_aToUpdate = [];
$this->m_bFoundStopper = false;
$this->m_bFoundSecurityIssue = false;
$this->m_bFoundManualDelete = false;
$this->m_bFoundManualOperation = false;
}
public function ComputeResults()
{
$this->m_iToDelete = 0;
$this->m_iToUpdate = 0;
foreach ($this->m_aToDelete as $sClass => $aToDelete) {
foreach ($aToDelete as $iId => $aData) {
$this->m_iToDelete++;
if (isset($aData['issue'])) {
$this->m_bFoundStopper = true;
$this->m_bFoundManualOperation = true;
if (isset($aData['issue_security'])) {
$this->m_bFoundSecurityIssue = true;
}
}
if ($aData['mode'] == DEL_MANUAL) {
$this->m_aToDelete[$sClass][$iId]['issue'] = $sClass.'::'.$iId.' '.Dict::S('UI:Delete:MustBeDeletedManually');
$this->m_bFoundStopper = true;
$this->m_bFoundManualDelete = true;
}
}
}
// Getting and setting time limit are not symetric:
// www.php.net/manual/fr/function.set-time-limit.php#72305
$iPreviousTimeLimit = ini_get('max_execution_time');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
foreach ($this->m_aToUpdate as $sClass => $aToUpdate) {
foreach ($aToUpdate as $iId => $aData) {
set_time_limit(intval($iLoopTimeLimit));
$this->m_iToUpdate++;
$oObject = $aData['to_reset'];
$aExtKeyLabels = [];
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) {
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
}
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite();
if (!$bRes) {
$this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues);
$this->m_bFoundStopper = true;
if ($bSecurityIssues) {
$this->m_aToUpdate[$sClass][$iId]['issue_security'] = true;
$this->m_bFoundSecurityIssue = true;
}
}
}
}
set_time_limit(intval($iPreviousTimeLimit));
}
public function GetIssues()
{
$aIssues = [];
foreach ($this->m_aToDelete as $sClass => $aToDelete) {
foreach ($aToDelete as $iId => $aData) {
if (isset($aData['issue'])) {
$aIssues[] = $aData['issue'];
}
}
}
foreach ($this->m_aToUpdate as $sClass => $aToUpdate) {
foreach ($aToUpdate as $iId => $aData) {
if (isset($aData['issue'])) {
$aIssues[] = $aData['issue'];
}
}
}
return $aIssues;
}
public function ListDeletes()
{
return $this->m_aToDelete;
}
public function ListUpdates()
{
return $this->m_aToUpdate;
}
public function GetTargetCount()
{
return $this->m_iToDelete + $this->m_iToUpdate;
}
public function FoundStopper()
{
return $this->m_bFoundStopper;
}
public function FoundSecurityIssue()
{
return $this->m_bFoundSecurityIssue;
}
public function FoundManualOperation()
{
return $this->m_bFoundManualOperation;
}
public function FoundManualDelete()
{
return $this->m_bFoundManualDelete;
}
public function FoundManualUpdate()
{
}
public function AddToDelete($oObject, $iDeletionMode = null)
{
if (is_null($iDeletionMode)) {
$bRequestedExplicitely = true;
$iDeletionMode = DEL_AUTO;
} else {
$bRequestedExplicitely = false;
}
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToUpdate[$sClass][$iId])) {
unset($this->m_aToUpdate[$sClass][$iId]);
}
if (isset($this->m_aToDelete[$sClass][$iId])) {
if ($this->m_aToDelete[$sClass][$iId]['requested_explicitely']) {
// No change: let it in mode DEL_AUTO
} else {
$iPrevDeletionMode = $this->m_aToDelete[$sClass][$iId]['mode'];
$iNewDeletionMode = self::$m_aModeUpdate[$iPrevDeletionMode][$iDeletionMode];
$this->m_aToDelete[$sClass][$iId]['mode'] = $iNewDeletionMode;
if ($bRequestedExplicitely) {
// This object was in the root list
$this->m_aToDelete[$sClass][$iId]['requested_explicitely'] = true;
$this->m_aToDelete[$sClass][$iId]['mode'] = DEL_AUTO;
}
}
} else {
$this->m_aToDelete[$sClass][$iId] = [
'to_delete' => $oObject,
'mode' => $iDeletionMode,
'requested_explicitely' => $bRequestedExplicitely,
];
}
}
public function SetDeletionIssues($oObject, $aIssues, $bSecurityIssue)
{
if (count($aIssues ?? []) > 0) {
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
$this->m_aToDelete[$sClass][$iId]['issue'] = implode(', ', $aIssues);
if ($bSecurityIssue) {
$this->m_aToDelete[$sClass][$iId]['issue_security'] = true;
}
}
}
public function AddToUpdate($oObject, $oAttDef, $value = 0)
{
$sClass = get_class($oObject);
$iId = $oObject->GetKey();
if (isset($this->m_aToDelete[$sClass][$iId])) {
// skip... it should be deleted anyhow !
} else {
if (!isset($this->m_aToUpdate[$sClass][$iId])) {
$this->m_aToUpdate[$sClass][$iId] = [
'to_reset' => $oObject,
];
}
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
}
}
}