mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 22:39:03 +02:00
Stop watches - beta (change tracking to be reviewed)
SVN:trunk[2166]
This commit is contained in:
@@ -132,6 +132,22 @@ abstract class AttributeDefinition
|
||||
return $this->m_sHostClass;
|
||||
}
|
||||
|
||||
public function ListSubItems()
|
||||
{
|
||||
$aSubItems = array();
|
||||
foreach(MetaModel::ListAttributeDefs($this->m_sHostClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeSubItem)
|
||||
{
|
||||
if ($oAttDef->Get('target_attcode') == $this->m_sCode)
|
||||
{
|
||||
$aSubItems[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aSubItems;
|
||||
}
|
||||
|
||||
// Note: I could factorize this code with the parameter management made for the AttributeDef class
|
||||
// to be overloaded
|
||||
static public function ListExpectedParams()
|
||||
@@ -174,6 +190,8 @@ abstract class AttributeDefinition
|
||||
public function IsHierarchicalKey() {return false;}
|
||||
public function IsExternalField() {return false;}
|
||||
public function IsWritable() {return false;}
|
||||
public function LoadInObject() {return true;}
|
||||
public function GetValue($oHostObject){return null;} // must return the value if LoadInObject returns false
|
||||
public function IsNullAllowed() {return true;}
|
||||
public function GetCode() {return $this->m_sCode;}
|
||||
|
||||
@@ -389,16 +407,25 @@ abstract class AttributeDefinition
|
||||
return (string)$sValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to display the value in the GUI
|
||||
*/
|
||||
public function GetAsHTML($sValue, $oHostObject = null)
|
||||
{
|
||||
return Str::pure2html((string)$sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to export the value in XML
|
||||
*/
|
||||
public function GetAsXML($sValue, $oHostObject = null)
|
||||
{
|
||||
return Str::pure2xml((string)$sValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to escape the value when read by DBObject::GetAsCSV()
|
||||
*/
|
||||
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
return (string)$sValue;
|
||||
@@ -2432,7 +2459,7 @@ class AttributeDuration extends AttributeInteger
|
||||
return Str::pure2html(self::FormatDuration($value));
|
||||
}
|
||||
|
||||
static function FormatDuration($duration)
|
||||
public static function FormatDuration($duration)
|
||||
{
|
||||
$aDuration = self::SplitDuration($duration);
|
||||
$sResult = '';
|
||||
@@ -2507,12 +2534,18 @@ class AttributeDate extends AttributeDateTime
|
||||
class AttributeDeadline extends AttributeDateTime
|
||||
{
|
||||
public function GetAsHTML($value, $oHostObject = null)
|
||||
{
|
||||
$sResult = self::FormatDeadline($value);
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
public static function FormatDeadline($value)
|
||||
{
|
||||
$sResult = '';
|
||||
if ($value !== null)
|
||||
{
|
||||
$iValue = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$sDate = parent::GetAsHTML($value, $oHostObject);
|
||||
$sDate = $value;
|
||||
$difference = $iValue - time();
|
||||
|
||||
if ($difference >= 0)
|
||||
@@ -2526,6 +2559,7 @@ class AttributeDeadline extends AttributeDateTime
|
||||
$sFormat = MetaModel::GetConfig()->Get('deadline_format', '$difference$');
|
||||
$sResult = str_replace(array('$date$', '$difference$'), array($sDate, $sDifference), $sFormat);
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
@@ -3234,7 +3268,11 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
public function IsScalar() {return true;}
|
||||
public function IsWritable() {return false;}
|
||||
public function GetDefaultValue() {return $this->NewStopWatch();}
|
||||
//public function IsNullAllowed() {return $this->GetOptional("is_null_allowed", false);}
|
||||
|
||||
public function GetEditValue($value, $oHostObj = null)
|
||||
{
|
||||
return $value->GetTimeSpent();
|
||||
}
|
||||
|
||||
public function GetStates()
|
||||
{
|
||||
@@ -3264,6 +3302,24 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
public function Equals($val1, $val2)
|
||||
{
|
||||
if ($val1 === $val2) return true;
|
||||
|
||||
if (is_object($val1) != is_object($val2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!is_object($val1))
|
||||
{
|
||||
// string ?
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both values are Object sets
|
||||
return $val1->HasSameContents($val2);
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
if ($sPrefix == '')
|
||||
@@ -3281,6 +3337,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sThPrefix = '_'.$iThreshold;
|
||||
$aColumns[$sThPrefix.'_deadline'] = $sPrefix.$sThPrefix.'_deadline';
|
||||
$aColumns[$sThPrefix.'_passed'] = $sPrefix.$sThPrefix.'_passed';
|
||||
$aColumns[$sThPrefix.'_triggered'] = $sPrefix.$sThPrefix.'_triggered';
|
||||
$aColumns[$sThPrefix.'_overrun'] = $sPrefix.$sThPrefix.'_overrun';
|
||||
}
|
||||
return $aColumns;
|
||||
@@ -3314,6 +3371,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sThPrefix = '_'.$iThreshold;
|
||||
$aExpectedCols[] = $sPrefix.$sThPrefix.'_deadline';
|
||||
$aExpectedCols[] = $sPrefix.$sThPrefix.'_passed';
|
||||
$aExpectedCols[] = $sPrefix.$sThPrefix.'_triggered';
|
||||
$aExpectedCols[] = $sPrefix.$sThPrefix.'_overrun';
|
||||
}
|
||||
foreach ($aExpectedCols as $sExpectedCol)
|
||||
@@ -3340,6 +3398,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$iThreshold,
|
||||
self::DateToSeconds($aCols[$sPrefix.$sThPrefix.'_deadline']),
|
||||
(bool)($aCols[$sPrefix.$sThPrefix.'_passed'] == 1),
|
||||
(bool)($aCols[$sPrefix.$sThPrefix.'_triggered'] == 1),
|
||||
$aCols[$sPrefix.$sThPrefix.'_overrun']
|
||||
);
|
||||
}
|
||||
@@ -3362,6 +3421,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sPrefix = $this->GetCode().'_'.$iThreshold;
|
||||
$aValues[$sPrefix.'_deadline'] = self::SecondsToDate($value->GetThresholdDate($iThreshold));
|
||||
$aValues[$sPrefix.'_passed'] = $value->IsThresholdPassed($iThreshold) ? '1' : '0';
|
||||
$aValues[$sPrefix.'_triggered'] = $value->IsThresholdTriggered($iThreshold) ? '1' : '0';
|
||||
$aValues[$sPrefix.'_overrun'] = $value->GetOverrun($iThreshold);
|
||||
}
|
||||
}
|
||||
@@ -3388,6 +3448,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sPrefix = $this->GetCode().'_'.$iThreshold;
|
||||
$aColumns[$sPrefix.'_deadline'] = 'DATETIME NULL';
|
||||
$aColumns[$sPrefix.'_passed'] = 'TINYINT(1) NULL';
|
||||
$aColumns[$sPrefix.'_triggered'] = 'TINYINT(1) NULL';
|
||||
$aColumns[$sPrefix.'_overrun'] = 'INT(11) UNSIGNED NULL';
|
||||
}
|
||||
return $aColumns;
|
||||
@@ -3395,8 +3456,6 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
//return array();
|
||||
// still not working... see later...
|
||||
$aRes = array(
|
||||
$this->GetCode() => new FilterFromAttribute($this),
|
||||
$this->GetCode().'_started' => new FilterFromAttribute($this, '_started'),
|
||||
@@ -3408,6 +3467,7 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sPrefix = $this->GetCode().'_'.$iThreshold;
|
||||
$aRes[$sPrefix.'_deadline'] = new FilterFromAttribute($this, '_deadline');
|
||||
$aRes[$sPrefix.'_passed'] = new FilterFromAttribute($this, '_passed');
|
||||
$aRes[$sPrefix.'_triggered'] = new FilterFromAttribute($this, '_triggered');
|
||||
$aRes[$sPrefix.'_overrun'] = new FilterFromAttribute($this, '_overrun');
|
||||
}
|
||||
return $aRes;
|
||||
@@ -3449,6 +3509,288 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
{
|
||||
return $this->Get('thresholds');
|
||||
}
|
||||
|
||||
/**
|
||||
* To expose internal values: Declare an attribute AttributeSubItem
|
||||
* and implement the GetSubItemXXXX verbs
|
||||
*/
|
||||
public function GetSubItemSQLExpression($sItemCode)
|
||||
{
|
||||
$sPrefix = $this->GetCode();
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
return array('' => $sPrefix.'_timespent');
|
||||
case 'started':
|
||||
return array('' => $sPrefix.'_started');
|
||||
case 'laststart':
|
||||
return array('' => $sPrefix.'_laststart');
|
||||
case 'stopped':
|
||||
return array('' => $sPrefix.'_stopped');
|
||||
}
|
||||
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
return array('' => $sPrefix.'_'.$iThreshold.'_deadline');
|
||||
case 'passed':
|
||||
return array('' => $sPrefix.'_'.$iThreshold.'_passed');
|
||||
case 'triggered':
|
||||
return array('' => $sPrefix.'_'.$iThreshold.'_triggered');
|
||||
case 'overrun':
|
||||
return array('' => $sPrefix.'_'.$iThreshold.'_overrun');
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new CoreException("Unknown item code '$sItemCode' for attribute ".$this->GetHostClass().'::'.$this->GetCode());
|
||||
}
|
||||
|
||||
public function GetSubItemValue($sItemCode, $value, $oHostObject = null)
|
||||
{
|
||||
$oStopWatch = $value;
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
return $oStopWatch->GetTimeSpent();
|
||||
case 'started':
|
||||
return $oStopWatch->GetStartDate();
|
||||
case 'laststart':
|
||||
return $oStopWatch->GetLastStartDate();
|
||||
case 'stopped':
|
||||
return $oStopWatch->GetStopDate();
|
||||
}
|
||||
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
return $oStopWatch->GetThresholdDate($iThreshold);
|
||||
case 'passed':
|
||||
return $oStopWatch->IsThresholdPassed($iThreshold);
|
||||
case 'triggered':
|
||||
return $oStopWatch->IsThresholdTriggered($iThreshold);
|
||||
case 'overrun':
|
||||
return $oStopWatch->GetOverrun($iThreshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new CoreException("Unknown item code '$sItemCode' for attribute ".$this->GetHostClass().'::'.$this->GetCode());
|
||||
}
|
||||
|
||||
static protected function GetDateFormat($bFull = false)
|
||||
{
|
||||
if ($bFull)
|
||||
{
|
||||
return "Y-m-d H:i:s";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Y-m-d H:i";
|
||||
}
|
||||
}
|
||||
|
||||
public function GetSubItemAsHTML($sItemCode, $value)
|
||||
{
|
||||
$sHtml = $value;
|
||||
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
$sHtml = Str::pure2html(AttributeDuration::FormatDuration($value));
|
||||
break;
|
||||
case 'started':
|
||||
case 'laststart':
|
||||
case 'stopped':
|
||||
if (is_null($value))
|
||||
{
|
||||
$sHtml = ''; // Undefined
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml = date(self::GetDateFormat(), $value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
if ($value)
|
||||
{
|
||||
$sDate = date(self::GetDateFormat(true /*full*/), $value);
|
||||
$sHtml = Str::pure2html(AttributeDeadline::FormatDeadline($sDate));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml = '';
|
||||
}
|
||||
break;
|
||||
case 'passed':
|
||||
$sHtml = $value ? '1' : '0';
|
||||
break;
|
||||
case 'triggered':
|
||||
$sHtml = $value ? '1' : '0';
|
||||
break;
|
||||
case 'overrun':
|
||||
$sHtml = Str::pure2html(AttributeDuration::FormatDuration($value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function GetSubItemAsCSV($sItemCode, $value, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetSubItemAsXML($sItemCode, $value)
|
||||
{
|
||||
return Str::pure2xml((string)$value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View of a subvalue of another attribute
|
||||
* If an attribute implements the verbs GetSubItem.... then it can expose
|
||||
* internal values, each of them being an attribute and therefore they
|
||||
* can be displayed at different times in the object lifecycle, and used for
|
||||
* reporting (as a condition in OQL, or as an additional column in an export)
|
||||
* Known usages: Stop Watches can expose threshold statuses
|
||||
*/
|
||||
class AttributeSubItem extends AttributeDefinition
|
||||
{
|
||||
static public function ListExpectedParams()
|
||||
{
|
||||
return array_merge(parent::ListExpectedParams(), array('target_attcode', 'item_code'));
|
||||
}
|
||||
|
||||
public function GetParentAttCode() {return $this->Get("target_attcode");}
|
||||
|
||||
/**
|
||||
* Helper : get the attribute definition to which the execution will be forwarded
|
||||
*/
|
||||
protected function GetTargetAttDef()
|
||||
{
|
||||
$sClass = $this->GetHostClass();
|
||||
$oParentAttDef = MetaModel::GetAttributeDef($sClass, $this->Get('target_attcode'));
|
||||
return $oParentAttDef;
|
||||
}
|
||||
|
||||
public function GetEditClass() {return "";}
|
||||
|
||||
public function GetValuesDef() {return null;}
|
||||
//public function GetPrerequisiteAttributes() {return $this->Get("depends_on");}
|
||||
|
||||
public function IsDirectField() {return true;}
|
||||
public function IsScalar() {return true;}
|
||||
public function IsWritable() {return false;}
|
||||
public function GetDefaultValue() {return null;}
|
||||
// public function IsNullAllowed() {return false;}
|
||||
public function LoadInObject() {return false;} // if this verb returns true, then GetValue must be implemented
|
||||
|
||||
//
|
||||
// protected function ScalarToSQL($value) {return $value;} // format value as a valuable SQL literal (quoted outside)
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
}
|
||||
|
||||
public function GetSQLColumns()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function GetFilterDefinitions()
|
||||
{
|
||||
return array($this->GetCode() => new FilterFromAttribute($this));
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return "=";
|
||||
}
|
||||
|
||||
public function GetBasicFilterSQLExpr($sOpCode, $value)
|
||||
{
|
||||
$sQValue = CMDBSource::Quote($value);
|
||||
switch ($sOpCode)
|
||||
{
|
||||
case '!=':
|
||||
return $this->GetSQLExpr()." != $sQValue";
|
||||
break;
|
||||
case '=':
|
||||
default:
|
||||
return $this->GetSQLExpr()." = $sQValue";
|
||||
}
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemSQLExpression($this->Get('item_code'));
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by DBOBject::Get()
|
||||
*/
|
||||
public function GetValue($parentValue, $oHostObject = null)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemValue($this->Get('item_code'), $parentValue, $oHostObject);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function GetAsHTML($value, $oHostObject = null)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemAsHTML($this->Get('item_code'), $value);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemAsCSV($this->Get('item_code'), $value, $sSeparator = ',', $sTextQualifier = '"');
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function GetAsXML($value, $oHostObject = null)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemAsXML($this->Get('item_code'), $value);
|
||||
return $res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -133,8 +133,18 @@ abstract class CMDBObject extends DBObject
|
||||
foreach ($aValues as $sAttCode=> $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField()) continue; // #@# temporary
|
||||
if ($oAttDef->IsLinkSet()) continue; // #@# temporary
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = null;
|
||||
}
|
||||
|
||||
if ($oAttDef instanceOf AttributeOneWayPassword)
|
||||
{
|
||||
// One Way encrypted passwords' history is stored -one way- encrypted
|
||||
@@ -144,11 +154,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
if (is_null($original))
|
||||
{
|
||||
$original = '';
|
||||
}
|
||||
@@ -164,11 +170,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
if (is_null($original))
|
||||
{
|
||||
$original = '';
|
||||
}
|
||||
@@ -184,11 +186,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
if (is_null($original))
|
||||
{
|
||||
$original = new ormDocument();
|
||||
}
|
||||
@@ -197,26 +195,30 @@ abstract class CMDBObject extends DBObject
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeStopWatch)
|
||||
{
|
||||
// Stop watches
|
||||
// TEMPORARY IMPLEMENTATION
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
|
||||
$oMyChangeOp->Set("change", $oChange->GetKey());
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
// Stop watches - record changes for sub items only (they are visible, the rest is not visible)
|
||||
//
|
||||
if (is_null($original))
|
||||
{
|
||||
$original = new OrmStopWatch();
|
||||
}
|
||||
foreach ($oAttDef->ListSubItems() as $sSubItemAttCode => $oSubItemAttDef)
|
||||
{
|
||||
$item_value = $oSubItemAttDef->GetValue($value);
|
||||
$item_original = $oSubItemAttDef->GetValue($original);
|
||||
|
||||
// Temporary - working thanks to ormStopWatch::__toString()
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$sOriginalValue = $aOrigValues[$sAttCode];
|
||||
if ($item_value != $item_original)
|
||||
{
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
|
||||
$oMyChangeOp->Set("change", $oChange->GetKey());
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sSubItemAttCode);
|
||||
|
||||
$oMyChangeOp->Set("oldvalue", $item_original);
|
||||
$oMyChangeOp->Set("newvalue", $item_value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sOriginalValue = 'undefined';
|
||||
}
|
||||
$oMyChangeOp->Set("oldvalue", $sOriginalValue);
|
||||
$oMyChangeOp->Set("newvalue", $value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeCaseLog)
|
||||
{
|
||||
@@ -238,17 +240,9 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
if (!is_null($original) && ($original instanceof ormCaseLog))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
if ($original instanceof ormCaseLog)
|
||||
{
|
||||
$original = $original->GetText();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = null;
|
||||
$original = $original->GetText();
|
||||
}
|
||||
$oMyChangeOp->Set("prevdata", $original);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
@@ -262,16 +256,11 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
if (is_null($original))
|
||||
{
|
||||
$sOriginalValue = $aOrigValues[$sAttCode];
|
||||
$original = 'undefined';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sOriginalValue = 'undefined';
|
||||
}
|
||||
$oMyChangeOp->Set("oldvalue", $sOriginalValue);
|
||||
$oMyChangeOp->Set("oldvalue", $original);
|
||||
$oMyChangeOp->Set("newvalue", $value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ abstract class DBObject
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (!$oAttDef->LoadInObject()) continue;
|
||||
if (!isset($this->m_aLoadedAtt[$sAttCode]) || !$this->m_aLoadedAtt[$sAttCode])
|
||||
{
|
||||
return false;
|
||||
@@ -248,6 +249,8 @@ abstract class DBObject
|
||||
// Skip links (could not be loaded by the mean of this query)
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
|
||||
if (!$oAttDef->LoadInObject()) continue;
|
||||
|
||||
// Note: we assume that, for a given attribute, if it can be loaded,
|
||||
// then one column will be found with an empty suffix, the others have a suffix
|
||||
// Take care: the function isset will return false in case the value is null,
|
||||
@@ -411,68 +414,73 @@ abstract class DBObject
|
||||
|
||||
public function GetStrict($sAttCode)
|
||||
{
|
||||
if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
|
||||
{
|
||||
throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
|
||||
}
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
|
||||
if (isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
if (!$oAttDef->LoadInObject())
|
||||
{
|
||||
// Standard case... we have the information directly
|
||||
}
|
||||
elseif ($this->m_bIsInDB && !$this->m_bDirty)
|
||||
{
|
||||
// Lazy load (polymorphism): complete by reloading the entire object
|
||||
// #@# non-scalar attributes.... handle that differently?
|
||||
$this->Reload();
|
||||
}
|
||||
elseif ($sAttCode == 'friendlyname')
|
||||
{
|
||||
// The friendly name is not computed and the object is dirty
|
||||
// Todo: implement the computation of the friendly name based on sprintf()
|
||||
//
|
||||
$this->m_aCurrValues[$sAttCode] = '';
|
||||
$sParentAttCode = $oAttDef->GetParentAttCode();
|
||||
$parentValue = $this->GetStrict($sParentAttCode);
|
||||
$value = $oAttDef->GetValue($parentValue, $this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not loaded... is it related to an external key?
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
if (isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
{
|
||||
// Let's get the object and compute all of the corresponding attributes
|
||||
// (i.e not only the requested attribute)
|
||||
//
|
||||
$sExtKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
|
||||
if ($iRemote = $this->Get($sExtKeyAttCode))
|
||||
// Standard case... we have the information directly
|
||||
}
|
||||
elseif ($this->m_bIsInDB && !$this->m_bDirty)
|
||||
{
|
||||
// Lazy load (polymorphism): complete by reloading the entire object
|
||||
// #@# non-scalar attributes.... handle that differently?
|
||||
$this->Reload();
|
||||
}
|
||||
elseif ($sAttCode == 'friendlyname')
|
||||
{
|
||||
// The friendly name is not computed and the object is dirty
|
||||
// Todo: implement the computation of the friendly name based on sprintf()
|
||||
//
|
||||
$this->m_aCurrValues[$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not loaded... is it related to an external key?
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$oRemote = MetaModel::GetObject($oExtKeyAttDef->GetTargetClass(), $iRemote);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRemote = null;
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sExtKeyAttCode))
|
||||
// Let's get the object and compute all of the corresponding attributes
|
||||
// (i.e not only the requested attribute)
|
||||
//
|
||||
$sExtKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
|
||||
if ($iRemote = $this->Get($sExtKeyAttCode))
|
||||
{
|
||||
if ($oRemote)
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$oRemote = MetaModel::GetObject($oExtKeyAttDef->GetTargetClass(), $iRemote);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRemote = null;
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sExtKeyAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oRemote->Get($oDef->GetExtAttCode());
|
||||
if ($oRemote)
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oRemote->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
|
||||
}
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
|
||||
}
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
}
|
||||
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
if ($value instanceof DBObjectSet)
|
||||
{
|
||||
$value->Rewind();
|
||||
|
||||
@@ -2365,6 +2365,7 @@ abstract class MetaModel
|
||||
foreach ($aAttList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
// keep because it can be used for sorting - if (!$oAttDef->LoadInObject()) continue;
|
||||
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
|
||||
@@ -54,23 +54,47 @@ class ormStopWatch
|
||||
$this->aThresholds = array();
|
||||
}
|
||||
|
||||
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $iOverrun = 0)
|
||||
// BUGGY - DOES NOT DETECT A CHANGE IN THE DEADLINE
|
||||
//
|
||||
public function HasSameContents($oStopWatch)
|
||||
{
|
||||
if ($oStopWatch->iTimeSpent != $this->iTimeSpent) return false;
|
||||
if ($oStopWatch->iStarted != $this->iStarted) return false;
|
||||
if ($oStopWatch->iLastStart != $this->iLastStart) return false;
|
||||
if ($oStopWatch->iStopped != $this->iStopped) return false;
|
||||
if ($oStopWatch->aThresholds != $this->aThresholds) return false;
|
||||
|
||||
// Array comparison is not recursive... let's do it by myself
|
||||
foreach ($oStopWatch->aThresholds as $iPercent => $aThresholdData)
|
||||
{
|
||||
// Assumption: the thresholds will not change dynamically (defined at application design time)
|
||||
$aThisThresholdData = $this->aThresholds[$iPercent];
|
||||
if ($aThisThresholdData['deadline'] != $aThresholdData['deadline']) return false;
|
||||
if ($aThisThresholdData['passed'] != $aThresholdData['passed']) return false;
|
||||
if ($aThisThresholdData['triggered'] != $aThresholdData['triggered']) return false;
|
||||
if ($aThisThresholdData['overrun'] != $aThresholdData['overrun']) return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = 0)
|
||||
{
|
||||
$this->aThresholds[$iPercent] = array(
|
||||
'deadline' => $tDeadline, // unix time (seconds)
|
||||
'passed' => $bPassed,
|
||||
'triggered' => $bTriggered,
|
||||
'overrun' => $iOverrun
|
||||
);
|
||||
}
|
||||
|
||||
public function MarkThresholdAsPassed($iPercent)
|
||||
public function MarkThresholdAsTriggered($iPercent)
|
||||
{
|
||||
$this->aThresholds[$iPercent]['passed'] = true;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return (string)$this->iTimeSpent;
|
||||
$this->aThresholds[$iPercent]['triggered'] = true;
|
||||
}
|
||||
|
||||
public function GetTimeSpent()
|
||||
@@ -127,6 +151,17 @@ class ormStopWatch
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function IsThresholdTriggered($iPercent)
|
||||
{
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
return $this->aThresholds[$iPercent]['triggered'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsHTML($oAttDef, $oHostObject = null)
|
||||
{
|
||||
@@ -157,21 +192,20 @@ class ormStopWatch
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => $aThresholdData)
|
||||
{
|
||||
if ($aThresholdData['passed'])
|
||||
$sThresholdDesc = $oAttDef->SecondsToDate($aThresholdData['deadline']);
|
||||
if ($aThresholdData['triggered'])
|
||||
{
|
||||
if ($aThresholdData['overrun'])
|
||||
{
|
||||
$aProperties[$iPercent.'%'] = $oAttDef->SecondsToDate($aThresholdData['deadline'])." <b>PASSED</b> by ".$aThresholdData['overrun']." seconds";
|
||||
$sThresholdDesc .= " <b>TRIGGERED</b>, Overrun:".(int) $aThresholdData['overrun']." seconds";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties[$iPercent.'%'] = $oAttDef->SecondsToDate($aThresholdData['deadline'])." <b>PASSED</b>";
|
||||
// Still active, overrun unknown
|
||||
$sThresholdDesc .= " <b>TRIGGERED</b>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties[$iPercent.'%'] = $oAttDef->SecondsToDate($aThresholdData['deadline']);
|
||||
}
|
||||
$aProperties[$iPercent.'%'] = $sThresholdDesc;
|
||||
}
|
||||
$sRes = "<TABLE class=\"listResults\">";
|
||||
$sRes .= "<TBODY>";
|
||||
@@ -247,6 +281,7 @@ class ormStopWatch
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
$aThresholdData['deadline'] = null;
|
||||
$aThresholdData['overrun'] = null;
|
||||
}
|
||||
@@ -289,21 +324,31 @@ class ormStopWatch
|
||||
$iDurationGoal = $this->ComputeGoal($oObject, $oAttDef);
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
if (!$aThresholdData['passed'])
|
||||
if (is_null($iDurationGoal))
|
||||
{
|
||||
if (is_null($iDurationGoal))
|
||||
{
|
||||
// No limit: leave null thresholds
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
|
||||
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
|
||||
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
|
||||
}
|
||||
// No limit: leave null thresholds
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
|
||||
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
|
||||
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
|
||||
|
||||
}
|
||||
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
|
||||
{
|
||||
// The threshold is in the future, reset
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new threshold is in the past
|
||||
$aThresholdData['passed'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -323,21 +368,21 @@ class ormStopWatch
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
if ($aThresholdData['passed'])
|
||||
if (!is_null($aThresholdData['deadline']) && (time() > $aThresholdData['deadline']))
|
||||
{
|
||||
if (is_null($aThresholdData['overrun']))
|
||||
{
|
||||
// First stop after the deadline is passed
|
||||
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
|
||||
$aThresholdData['overrun'] = $iOverrun;
|
||||
}
|
||||
else
|
||||
$aThresholdData['passed'] = true;
|
||||
if ($aThresholdData['overrun'] > 0)
|
||||
{
|
||||
// Accumulate from last start
|
||||
$aThresholdData['overrun'] += $iElapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// First stop after the deadline has been passed
|
||||
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
|
||||
$aThresholdData['overrun'] = $iOverrun;
|
||||
}
|
||||
}
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
|
||||
$this->iLastStart = null;
|
||||
@@ -372,8 +417,8 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
{
|
||||
$iPercent = $aThresholdData['percent']; // could be different than the index !
|
||||
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_{$iThreshold}_passed = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()";
|
||||
echo $sExpression."<br/>\n";
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()";
|
||||
//echo $sExpression."<br/>\n";
|
||||
$oFilter = DBObjectSearch::FromOQL($sExpression);
|
||||
$aList = array();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
@@ -382,7 +427,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
|
||||
echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."<br/>\n";
|
||||
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
|
||||
|
||||
// Execute planned actions
|
||||
//
|
||||
@@ -396,10 +441,10 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
call_user_func_array($aCallSpec, $aParams);
|
||||
}
|
||||
|
||||
// Mark the threshold as "passed"
|
||||
// Mark the threshold as "triggered"
|
||||
//
|
||||
$oSW = $oObj->Get($sAttCode);
|
||||
$oSW->MarkThresholdAsPassed($iThreshold);
|
||||
$oSW->MarkThresholdAsTriggered($iThreshold);
|
||||
$oObj->Set($sAttCode, $oSW);
|
||||
|
||||
if($oObj->IsModified())
|
||||
@@ -407,7 +452,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
// Todo - factorize so that only one single change will be instantiated
|
||||
$oMyChange = new CMDBChange();
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", "Automatic - threshold passed");
|
||||
$oMyChange->Set("userinfo", "Automatic - threshold triggered");
|
||||
$iChangeId = $oMyChange->DBInsertNoReload();
|
||||
|
||||
$oObj->DBUpdateTracked($oMyChange, true /*skip security*/);
|
||||
@@ -432,7 +477,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
}
|
||||
|
||||
$iProcessed = count($aList);
|
||||
return "Encountered $iProcessed passed threshold(s)";
|
||||
return "Triggered $iProcessed threshold(s)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -724,6 +724,11 @@ EOF;
|
||||
}
|
||||
$aParameters['thresholds'] = 'array('.implode(', ', $aThresholds).')';
|
||||
}
|
||||
elseif ($sAttType == 'AttributeSubItem')
|
||||
{
|
||||
$aParameters['target_attcode'] = $this->GetPropString($oField, 'target_attcode');
|
||||
$aParameters['item_code'] = $this->GetPropString($oField, 'item_code');
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParameters['allowed_values'] = 'null'; // or "new ValueSetEnum('SELECT xxxx')"
|
||||
|
||||
Reference in New Issue
Block a user