mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-26 20:18:52 +02:00
Clarified the meaning of the attribute 'finalclass'
SVN:trunk[380]
This commit is contained in:
@@ -589,7 +589,7 @@ abstract class cmdbAbstractObject extends CMDBObject
|
||||
$oPage->add("<$sClassName alias=\"$sAlias\" id=\"".$oObj->GetKey()."\">\n");
|
||||
foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()) && ($sAttCode != 'finalclass') )
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()))
|
||||
{
|
||||
$sValue = $oObj->GetAsXML($sAttCode);
|
||||
$oPage->add("<$sAttCode>$sValue</$sAttCode>\n");
|
||||
|
||||
@@ -59,7 +59,7 @@ abstract class AttributeDefinition
|
||||
|
||||
protected $m_sCode;
|
||||
private $m_aParams = array();
|
||||
private $m_sHostClass = array();
|
||||
private $m_sHostClass = '!undefined!';
|
||||
protected function Get($sParamName) {return $this->m_aParams[$sParamName];}
|
||||
protected function IsParam($sParamName) {return (array_key_exists($sParamName, $this->m_aParams));}
|
||||
|
||||
@@ -668,6 +668,36 @@ class AttributeClass extends AttributeString
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute dedicated to the finalclass automatic attribute
|
||||
*
|
||||
* @package iTopORM
|
||||
* @author Romain Quetiez <romainquetiez@yahoo.fr>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.itop.com
|
||||
* @since 1.0
|
||||
* @version $itopversion$
|
||||
*/
|
||||
class AttributeFinalClass extends AttributeString
|
||||
{
|
||||
public function __construct($sCode, $aParams)
|
||||
{
|
||||
$this->m_sCode = $sCode;
|
||||
$aParams["allowed_values"] = null;
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function IsWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue)
|
||||
{
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a varchar column (size < ?) to an attribute that must never be shown to the user
|
||||
*
|
||||
|
||||
@@ -354,18 +354,18 @@ abstract class MetaModel
|
||||
self::_check_subclass($sClass);
|
||||
return self::$m_aClassParams[$sClass]["db_finalclass_field"];
|
||||
}
|
||||
final static public function HasFinalClassField($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!array_key_exists("db_finalclass_field", self::$m_aClassParams[$sClass])) return false;
|
||||
return (self::$m_aClassParams[$sClass]["db_finalclass_field"]);
|
||||
}
|
||||
final static public function IsStandaloneClass($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
$sRootClass = self::GetRootClass($sClass);
|
||||
return (!self::HasFinalClassField($sRootClass));
|
||||
if (count(self::$m_aChildClasses[$sClass]) == 0)
|
||||
{
|
||||
if (count(self::$m_aParentClasses[$sClass]) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final static public function IsParentClass($sParentClass, $sChildClass)
|
||||
{
|
||||
@@ -877,37 +877,6 @@ abstract class MetaModel
|
||||
self::$m_aFilterDefs[$sClass]['id'] = $oFilter;
|
||||
self::$m_aFilterOrigins[$sClass]['id'] = $sClass;
|
||||
|
||||
// Add a 'class' attribute/filter to the root classes and their children
|
||||
//
|
||||
if (!self::IsStandaloneClass($sClass))
|
||||
{
|
||||
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
throw new CoreException("Class $sClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code");
|
||||
}
|
||||
if (array_key_exists('finalclass', self::$m_aFilterDefs[$sClass]))
|
||||
{
|
||||
throw new CoreException("Class $sClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code");
|
||||
}
|
||||
$sClassAttCode = 'finalclass';
|
||||
$sRootClass = self::GetRootClass($sClass);
|
||||
$sDbFinalClassField = self::DBGetClassField($sRootClass);
|
||||
$oClassAtt = new AttributeClass($sClassAttCode, array(
|
||||
"class_category"=>null,
|
||||
"more_values"=>'',
|
||||
"sql"=>$sDbFinalClassField,
|
||||
"default_value"=>$sClass,
|
||||
"is_null_allowed"=>false,
|
||||
"depends_on"=>array()
|
||||
));
|
||||
self::$m_aAttribDefs[$sClass][$sClassAttCode] = $oClassAtt;
|
||||
self::$m_aAttribOrigins[$sClass][$sClassAttCode] = $sRootClass;
|
||||
|
||||
$oClassFlt = new FilterFromAttribute($oClassAtt);
|
||||
self::$m_aFilterDefs[$sClass][$sClassAttCode] = $oClassFlt;
|
||||
self::$m_aFilterOrigins[$sClass][$sClassAttCode] = self::GetRootClass($sClass);
|
||||
}
|
||||
|
||||
// Define defaults values for the standard ZLists
|
||||
//
|
||||
//foreach (self::$m_aListInfos as $sListCode => $aListConfig)
|
||||
@@ -921,6 +890,50 @@ abstract class MetaModel
|
||||
//}
|
||||
}
|
||||
|
||||
// Add a 'class' attribute/filter to the root classes and their children
|
||||
//
|
||||
foreach(self::EnumRootClasses() as $sRootClass)
|
||||
{
|
||||
if (self::IsStandaloneClass($sRootClass)) continue;
|
||||
|
||||
$sDbFinalClassField = self::DBGetClassField($sRootClass);
|
||||
if (strlen($sDbFinalClassField) == 0)
|
||||
{
|
||||
$sDbFinalClassField = 'finalclass';
|
||||
self::$m_aClassParams[$sClass]["db_finalclass_field"] = 'finalclass';
|
||||
}
|
||||
$oClassAtt = new AttributeFinalClass('finalclass', array(
|
||||
"sql"=>$sDbFinalClassField,
|
||||
"default_value"=>$sRootClass,
|
||||
"is_null_allowed"=>false,
|
||||
"depends_on"=>array()
|
||||
));
|
||||
$oClassAtt->SetHostClass($sRootClass);
|
||||
self::$m_aAttribDefs[$sRootClass]['finalclass'] = $oClassAtt;
|
||||
self::$m_aAttribOrigins[$sRootClass]['finalclass'] = $sRootClass;
|
||||
|
||||
$oClassFlt = new FilterFromAttribute($oClassAtt);
|
||||
self::$m_aFilterDefs[$sRootClass]['finalclass'] = $oClassFlt;
|
||||
self::$m_aFilterOrigins[$sRootClass]['finalclass'] = $sRootClass;
|
||||
|
||||
foreach(self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass)
|
||||
{
|
||||
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass]))
|
||||
{
|
||||
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code");
|
||||
}
|
||||
if (array_key_exists('finalclass', self::$m_aFilterDefs[$sChildClass]))
|
||||
{
|
||||
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code");
|
||||
}
|
||||
self::$m_aAttribDefs[$sChildClass]['finalclass'] = clone $oClassAtt;
|
||||
self::$m_aAttribOrigins[$sChildClass]['finalclass'] = $sRootClass;
|
||||
|
||||
$oClassFlt = new FilterFromAttribute($oClassAtt);
|
||||
self::$m_aFilterDefs[$sChildClass]['finalclass'] = $oClassFlt;
|
||||
self::$m_aFilterOrigins[$sChildClass]['finalclass'] = self::GetRootClass($sChildClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To be overriden, must be called for any object class (optimization)
|
||||
@@ -1014,18 +1027,17 @@ abstract class MetaModel
|
||||
self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]);
|
||||
self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]);
|
||||
}
|
||||
// later on, we might consider inheritance in different ways !!!
|
||||
//if (strlen(self::DBGetTable($sSourceClass)) != 0)
|
||||
if (self::HasFinalClassField(self::$m_aRootClasses[$sSourceClass]))
|
||||
// Build root class information
|
||||
if (array_key_exists($sSourceClass, self::$m_aRootClasses))
|
||||
{
|
||||
// Inherit the root class
|
||||
// Inherit...
|
||||
self::$m_aRootClasses[$sTargetClass] = self::$m_aRootClasses[$sSourceClass];
|
||||
}
|
||||
else
|
||||
{
|
||||
// I am a root class, standalone as well !
|
||||
// ????
|
||||
//self::$m_aRootClasses[$sTargetClass] = $sTargetClass;
|
||||
// This class will be the root class
|
||||
self::$m_aRootClasses[$sSourceClass] = $sSourceClass;
|
||||
self::$m_aRootClasses[$sTargetClass] = $sSourceClass;
|
||||
}
|
||||
self::$m_aParentClasses[$sTargetClass] += self::$m_aParentClasses[$sSourceClass];
|
||||
self::$m_aParentClasses[$sTargetClass][] = $sSourceClass;
|
||||
@@ -1212,6 +1224,10 @@ abstract class MetaModel
|
||||
self::_check_subclass($sClass);
|
||||
return (self::GetRootClass($sClass) == $sClass);
|
||||
}
|
||||
public static function EnumRootClasses()
|
||||
{
|
||||
return array_unique(self::$m_aRootClasses);
|
||||
}
|
||||
public static function EnumParentClasses($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -2540,10 +2556,12 @@ abstract class MetaModel
|
||||
$sTable = self::DBGetTable($sClass);
|
||||
$sKeyField = self::DBGetKey($sClass);
|
||||
|
||||
if (!self::IsStandaloneClass($sClass))
|
||||
{
|
||||
if (self::IsRootClass($sClass))
|
||||
{
|
||||
// Check that the final class field contains the name of a class which inherited from the current class
|
||||
//
|
||||
if (self::HasFinalClassField($sClass))
|
||||
{
|
||||
$sFinalClassField = self::DBGetClassField($sClass);
|
||||
|
||||
$aAllowedValues = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL);
|
||||
@@ -2552,10 +2570,7 @@ abstract class MetaModel
|
||||
$sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS id FROM `$sTable` AS maintable WHERE `$sFinalClassField` NOT IN ($sAllowedValues)";
|
||||
self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "final class (field `<em>$sFinalClassField</em>`) is wrong (expected a value in {".$sAllowedValues."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel);
|
||||
}
|
||||
|
||||
// Compound objects model - node/leaf classes (not the root itself)
|
||||
//
|
||||
if (!self::IsStandaloneClass($sClass) && !self::HasFinalClassField($sClass))
|
||||
else
|
||||
{
|
||||
$sRootTable = self::DBGetTable($sRootClass);
|
||||
$sRootKey = self::DBGetKey($sRootClass);
|
||||
@@ -2576,6 +2591,7 @@ abstract class MetaModel
|
||||
$sSelWrongRecs = "SELECT DISTINCT maintable.`$sRootKey` AS id FROM `$sRootTable` AS maintable LEFT JOIN `$sTable` ON maintable.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND maintable.`$sFinalClassField` IN ($sExpectedClasses)";
|
||||
self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in root table `<em>$sRootTable</em>`, but no counterpart in table `<em>$sTable</em>` (root records pointing to a class in {".$sExpectedClasses."})", $sRootClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:CMDBChangeOp/Attribute:objclass+' => 'object class',
|
||||
'Class:CMDBChangeOp/Attribute:objkey' => 'object id',
|
||||
'Class:CMDBChangeOp/Attribute:objkey+' => 'object id',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => 'finalclass',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => 'type',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
@@ -116,7 +116,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Event/Attribute:date+' => 'date and time at which the changes have been recorded',
|
||||
'Class:Event/Attribute:userinfo' => 'user info',
|
||||
'Class:Event/Attribute:userinfo+' => 'identification of the user that was doing the action that triggered this event',
|
||||
'Class:Event/Attribute:finalclass' => 'finalclass',
|
||||
'Class:Event/Attribute:finalclass' => 'type',
|
||||
'Class:Event/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
@@ -221,7 +221,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Action/Attribute:status/Value:disabled+' => 'Inactive',
|
||||
'Class:Action/Attribute:related_triggers' => 'Related Triggers',
|
||||
'Class:Action/Attribute:related_triggers+' => 'Triggers linked to this action',
|
||||
'Class:Action/Attribute:finalclass' => 'finalclass',
|
||||
'Class:Action/Attribute:finalclass' => 'Type',
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
@@ -278,7 +278,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Trigger/Attribute:description+' => 'one line description',
|
||||
'Class:Trigger/Attribute:linked_actions' => 'Triggered actions',
|
||||
'Class:Trigger/Attribute:linked_actions+' => 'Actions performed when the trigger is activated',
|
||||
'Class:Trigger/Attribute:finalclass' => 'finalclass',
|
||||
'Class:Trigger/Attribute:finalclass' => 'Type',
|
||||
'Class:Trigger/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:logRealObject/Attribute:org_id+' => 'ID of the object owner organization',
|
||||
'Class:logRealObject/Attribute:org_name' => 'Organization',
|
||||
'Class:logRealObject/Attribute:org_name+' => 'Company / Department owning this object',
|
||||
'Class:logRealObject/Attribute:finalclass' => 'finalclass',
|
||||
'Class:logRealObject/Attribute:finalclass' => 'Type',
|
||||
'Class:logRealObject/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($oAttDef->IsWritable() && ($sAttCode != 'finalclass')) // finalclass should not be considered as 'writable' isn't it ?
|
||||
else if ($oAttDef->IsWritable())
|
||||
{
|
||||
$aChoices[$sAttCode] = $oAttDef->GetLabel();
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class XMLDataLoader
|
||||
$oTargetObj = MetaModel::NewObject($sClass);
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()) && ($sAttCode != 'finalclass') )
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user