diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index c8fa5e32f..5752a2e5b 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -672,7 +672,7 @@ class DisplayBlock $oFilter->AddCondition($sStateAttrCode, $sStateValue, '='); $oSet = new DBObjectSet($oFilter); $aCounts[$sStateValue] = $oSet->Count(); - $aStateLabels[$sStateValue] = Dict::S("Class:".$oAttDef->GetHostClass()."/Attribute:$sStateAttrCode/Value:$sStateValue"); + $aStateLabels[$sStateValue] = $oAttDef->GetValueLabel($sStateValue); if ($aCounts[$sStateValue] == 0) { $aCounts[$sStateValue] = '-'; diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 411a0e778..d0234dc58 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -179,7 +179,26 @@ abstract class AttributeDefinition public function IsWritable() {return false;} public function IsNullAllowed() {return true;} public function GetCode() {return $this->m_sCode;} - public function GetLabel() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, $this->m_sCode);} + + public function GetLabel() + { + $sLabel = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, ''); + if (strlen($sLabel) == 0) + { + $sLabel = $this->m_sCode; + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sLabel = $oAttDef->GetLabel(); + } + } + } + return $sLabel; + } + public function GetLabel_Obsolete() { // Written for compatibility with a data model written prior to version 0.9.1 @@ -192,8 +211,42 @@ abstract class AttributeDefinition return $this->GetLabel(); } } - public function GetDescription() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', '');} - public function GetHelpOnEdition() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', '');} + + public function GetDescription() + { + $sDescription = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', ''); + if (strlen($sDescription) == 0) + { + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sDescription = $oAttDef->GetDescription(); + } + } + } + return $sDescription; + } + + public function GetHelpOnEdition() + { + $sHelp = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', ''); + if (strlen($sHelp) == 0) + { + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sHelp = $oAttDef->GetHelpOnEdition(); + } + } + } + return $sHelp; + } public function GetHelpOnSmartSearch() { @@ -1895,7 +1948,7 @@ class AttributeEnum extends AttributeString return parent::GetBasicFilterSQLExpr($sOpCode, $value); } - public function GetAsHTML($sValue, $oHostObject = null) + public function GetValueLabel($sValue) { if (is_null($sValue)) { @@ -1904,17 +1957,61 @@ class AttributeEnum extends AttributeString } else { - $sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue); + $sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, ''); + if (strlen($sLabel) == 0) + { + $sLabel = $sValue; + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sLabel = $oAttDef->GetValueLabel($sValue); + } + } + } } - $sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', $sValue); + return $sLabel; + } + + public function GetValueDescription($sValue) + { + if (is_null($sValue)) + { + // Unless a specific label is defined for the null value of this enum, use a generic "undefined" label + $sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', Dict::S('Enum:Undefined')); + } + else + { + $sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', ''); + if (strlen($sDescription) == 0) + { + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sDescription = $oAttDef->GetValueDescription($sValue); + } + } + } + } + return $sDescription; + } + + public function GetAsHTML($sValue, $oHostObject = null) + { + $sLabel = $this->GetValueLabel($sValue); + $sDescription = $this->GetValueDescription($sValue); // later, we could imagine a detailed description in the title return "".parent::GetAsHtml($sLabel).""; } public function GetEditValue($sValue) { - $sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue); - return $sLabel; + return $this->GetValueLabel($sValue); } public function GetAllowedValues($aArgs = array(), $sContains = '') @@ -1924,7 +2021,7 @@ class AttributeEnum extends AttributeString $aLocalizedValues = array(); foreach ($aRawValues as $sKey => $sValue) { - $aLocalizedValues[$sKey] = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sKey, $sKey); + $aLocalizedValues[$sKey] = $this->GetValueLabel($sKey); } return $aLocalizedValues; } @@ -2466,6 +2563,8 @@ class AttributeExternalKey extends AttributeDBFieldVoid */ class AttributeHierarchicalKey extends AttributeExternalKey { + protected $m_sTargetClass; + static protected function ListExpectedParams() { $aParams = parent::ListExpectedParams(); @@ -2482,6 +2581,18 @@ class AttributeHierarchicalKey extends AttributeExternalKey return true; } + /* + * The target class is the class for which the attribute has been defined first + */ + public function SetHostClass($sHostClass) + { + if (!isset($this->m_sTargetClass)) + { + $this->m_sTargetClass = $sHostClass; + } + parent::SetHostClass($sHostClass); + } + public function IsHierarchicalKey() {return true;} public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->GetHostClass();} public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;} diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 2a276b64a..92d99db42 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -974,21 +974,13 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) { $sStateAttrCode = self::GetStateAttributeCode($sClass); $oAttDef = self::GetAttributeDef($sClass, $sStateAttrCode); - // Be consistent with what is done for enums, since states are defined as enums... - return Dict::S("Class:".$oAttDef->GetHostClass()."/Attribute:$sStateAttrCode/Value:$sStateValue"); - - // I've decided the current implementation, because I need - // to get the description as well -GetAllowedValues does not render the description, - // so far... - // Could have been implemented the following way (not tested - // $oStateAttrDef = self::GetAttributeDef($sClass, $sStateAttrCode); - // $aAllowedValues = $oStateAttrDef->GetAllowedValues(); - // return $aAllowedValues[$sStateValue]; + return $oAttDef->GetValueLabel($sStateValue); } public static function GetStateDescription($sClass, $sStateValue) { $sStateAttrCode = self::GetStateAttributeCode($sClass); - return Dict::S("Class:$sClass/Attribute:$sStateAttrCode/Value:$sStateValue+", ''); + $oAttDef = self::GetAttributeDef($sClass, $sStateAttrCode); + return $oAttDef->GetValueDescription($sStateValue); } public static function EnumTransitions($sClass, $sStateCode) @@ -1426,19 +1418,10 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) self::$m_aAttribOrigins[$sTargetClass] = array(); } self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]); - // Note: while investigating on some issues related to attribute inheritance, - // I found out that the notion of "host class" is unclear - // For stability reasons, and also because a workaround has been found - // I leave it unchanged, but later it could be a good thing to force - // attribute host class to the new class (See code below) - // In that case, we will have to review the attribute labels - // (currently relying on host class => the original declaration - // of the attribute) - // See TRAC #148 - // foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef) - // { - // $oAttDef->SetHostClass($sTargetClass); - // } + foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef) + { + $oAttDef->SetHostClass($sTargetClass); + } self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]); } // Build root class information @@ -1678,6 +1661,17 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) self::_check_subclass($sClass); return (self::GetRootClass($sClass) == $sClass); } + public static function GetParentClass($sClass) + { + if (count(self::$m_aParentClasses[$sClass]) == 0) + { + return null; + } + else + { + return end(self::$m_aParentClasses[$sClass]); + } + } /** * Tells if a class contains a hierarchical key, and if so what is its AttCode * @return mixed String = sAttCode or false if the class is not part of a hierarchy