Enhancement: the default value for a module's parameter can now be specified (and altered) via the XML and will no longer reside in the configuration file.

SVN:trunk[3518]
This commit is contained in:
Denis Flaven
2015-03-25 15:11:24 +00:00
parent 166f5ce73f
commit 8b36699893
3 changed files with 293 additions and 3 deletions

View File

@@ -1150,9 +1150,20 @@ class Config
{
return $this->m_aModuleSettings[$sModule][$sProperty];
}
return $defaultvalue;
// Fall back to the predefined XML parameter, if any
return $this->GetModuleParameter($sModule, $sProperty, $defaultvalue);
}
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
{
$aAllParams = ModulesXMLParameters::GetData($sModule);
if(array_key_exists($sProperty, $aAllParams))
{
return $aAllParams[$sProperty];
}
return $defaultvalue;
}
public function SetModuleSetting($sModule, $sProperty, $value)
{
$this->m_aModuleSettings[$sModule][$sProperty] = $value;

View File

@@ -40,6 +40,9 @@ class MFCompiler
$this->aLog = array();
$this->sMainPHPCode = '<'.'?'."php\n";
$this->sMainPHPCode .= "/**\n";
$this->sMainPHPCode .= " * This file was automatically generated by the compiler on ".date('Y-m-d H:i:s')." -- DO NOT EDIT\n";
$this->sMainPHPCode .= " */\n";
}
protected function Log($sText)
@@ -384,6 +387,10 @@ EOF;
$oPortalsNode = $this->oFactory->GetNodes('/itop_design/portals')->item(0);
$this->CompilePortals($oPortalsNode, $sTempTargetDir, $sFinalTargetDir);
// Compile the XML parameters
$oParametersNode = $this->oFactory->GetNodes('/itop_design/module_parameters')->item(0);
$this->CompileParameters($oParametersNode, $sTempTargetDir, $sFinalTargetDir);
// Write core/main.php
SetupUtils::builddir($sTempTargetDir.'/core');
$sPHPFile = $sTempTargetDir.'/core/main.php';
@@ -1977,9 +1984,13 @@ EOF;
uasort($aPortalsConfig, array(get_class($this), 'SortOnRank'));
$this->sMainPHPCode .= "\n";
$this->sMainPHPCode .= "/**\n";
$this->sMainPHPCode .= " * Portal(s) definition(s) extracted from the XML definition at compile time\n";
$this->sMainPHPCode .= " */\n";
$this->sMainPHPCode .= "class PortalDispatcherData\n";
$this->sMainPHPCode .= "{\n";
$this->sMainPHPCode .= "\tprotected static \$aData = ".str_replace("\n", "\n\t", var_export($aPortalsConfig, true)).";\n\n";
$this->sMainPHPCode .= "\tprotected static \$aData = ".var_export($aPortalsConfig, true).";\n\n";
$this->sMainPHPCode .= "\tpublic static function GetData(\$sPortalId = null)\n";
$this->sMainPHPCode .= "\t{\n";
$this->sMainPHPCode .= "\t\tif (\$sPortalId === null) return self::\$aData;\n";
@@ -1989,11 +2000,42 @@ EOF;
$this->sMainPHPCode .= "}\n";
}
}
public static function SortOnRank($aConf1, $aConf2)
{
return ($aConf1['rank'] < $aConf2['rank']) ? -1 : 1;
}
protected function CompileParameters($oParametersNode, $sTempTargetDir, $sFinalTargetDir)
{
if ($oParametersNode)
{
// Create some static PHP data in <env-xxx>/core/main.php
$oParameters = $oParametersNode->GetNodes('parameters');
$aParametersConfig = array();
foreach($oParameters as $oParams)
{
$sModuleId = $oParams->getAttribute('id');
$oParamsReader = new MFParameters($oParams);
$aParametersConfig[$sModuleId] = $oParamsReader->GetAll();
}
$this->sMainPHPCode .= "\n";
$this->sMainPHPCode .= "/**\n";
$this->sMainPHPCode .= " * Modules parameters extracted from the XML definition at compile time\n";
$this->sMainPHPCode .= " */\n";
$this->sMainPHPCode .= "class ModulesXMLParameters\n";
$this->sMainPHPCode .= "{\n";
$this->sMainPHPCode .= "\tprotected static \$aData = ".var_export($aParametersConfig, true).";\n\n";
$this->sMainPHPCode .= "\tpublic static function GetData(\$sModuleId = null)\n";
$this->sMainPHPCode .= "\t{\n";
$this->sMainPHPCode .= "\t\tif (\$sModuleId === null) return self::\$aData;\n";
$this->sMainPHPCode .= "\t\tif (!array_key_exists(\$sModuleId, self::\$aData)) return array();\n";
$this->sMainPHPCode .= "\t\treturn self::\$aData[\$sModuleId];\n";
$this->sMainPHPCode .= "\t}\n";
$this->sMainPHPCode .= "}\n";
}
}
}
?>

View File

@@ -2079,4 +2079,241 @@ class MFDocument extends DOMDocument
return self::GetItopNodePath($oNode->parentNode).'/'.$sNodeDesc;
}
}
/**
* Helper class manage parameters stored as XML nodes
* to be converted to a PHP structure during compilation
* Values can be either a hash, an array, a string, a boolean, an int or a float
*/
class MFParameters
{
protected $aData = null;
public function __construct(DOMNode $oNode)
{
$this->aData = array();
$this->LoadFromDOM($oNode);
}
public function Get($sCode, $default = '')
{
if (array_key_exists($sCode, $this->aData))
{
return $this->aData[$sCode];
}
return $default;
}
public function GetAll()
{
return $this->aData;
}
public function LoadFromDOM(DOMNode $oNode)
{
$this->aData = array();
foreach($oNode->childNodes as $oChildNode)
{
if ($oChildNode instanceof DOMElement)
{
$this->aData[$oChildNode->nodeName] = $this->ReadElement($oChildNode);
}
}
}
protected function ReadElement(DOMNode $oNode)
{
if ($oNode instanceof DOMElement)
{
$sDefaultNodeType = ($this->HasChildNodes($oNode)) ? 'hash' : 'string';
$sNodeType = $oNode->getAttribute('type');
if ($sNodeType == '')
{
$sNodeType = $sDefaultNodeType;
}
switch($sNodeType)
{
case 'array':
$value = array();
// Treat the current element as zero based array, child tag names are NOT meaningful
$sFirstTagName = null;
foreach($oNode->childNodes as $oChildElement)
{
if ($oChildElement instanceof DOMElement)
{
if ($sFirstTagName == null)
{
$sFirstTagName = $oChildElement->nodeName;
}
else if ($sFirstTagName != $oChildElement->nodeName)
{
throw new Exception("Invalid Parameters: mixed tags ('$sFirstTagName' and '".$oChildElement->nodeName."') inside array '".$oNode->nodeName."'");
}
$val = $this->ReadElement($oChildElement);
$idx = (string)$oChildElement->getAttribute('id'); // Don't cast into float, since floats are converted to int (i.e. truncated) when used as hash indexes (cf: http://php.net/manual/en/language.types.array.php)
if ($idx !== '')
{
$value[$idx] = $val;
}
else
{
// No specific Id, just push the value at the end of the array
$value[] = $val;
}
}
}
ksort($value, SORT_NUMERIC);
break;
case 'hash':
$value = array();
// Treat the current element as a hash, child tag names are keys
foreach($oNode->childNodes as $oChildElement)
{
if ($oChildElement instanceof DOMElement)
{
if (array_key_exists($oChildElement->nodeName, $value))
{
throw new Exception("Invalid Parameters file: duplicate tags '".$oChildElement->nodeName."' inside hash '".$oNode->nodeName."'");
}
$val = $this->ReadElement($oChildElement);
$value[$oChildElement->nodeName] = $val;
}
}
break;
case 'int':
case 'integer':
$value = (int)$this->GetText($oNode);
break;
case 'bool':
case 'boolean':
if (($this->GetText($oNode) == 'true') || ($this->GetText($oNode) == 1))
{
$value = true;
}
else
{
$value = false;
}
break;
case 'string':
default:
$value = str_replace('\n', "\n", (string)$this->GetText($oNode));
}
}
else if ($oNode instanceof DOMText)
{
$value = $oNode->wholeText;
}
return $value;
}
protected function GetAttribute($sAttName, $oNode, $sDefaultValue)
{
$sRet = $sDefaultValue;
foreach($oNode->attributes as $oAttribute)
{
if ($oAttribute->nodeName == $sAttName)
{
$sRet = $oAttribute->nodeValue;
break;
}
}
return $sRet;
}
/**
* Returns the TEXT of the current node (possibly from several subnodes)
*/
public function GetText($oNode, $sDefault = null)
{
$sText = null;
foreach($oNode->childNodes as $oChildNode)
{
if ($oChildNode instanceof DOMText)
{
if (is_null($sText)) $sText = '';
$sText .= $oChildNode->wholeText;
}
}
if (is_null($sText))
{
return $sDefault;
}
else
{
return $sText;
}
}
/**
* Check if a node as child nodes (apart from text nodes)
*/
public function HasChildNodes($oNode)
{
if ($oNode instanceof DOMElement)
{
foreach($oNode->childNodes as $oChildNode)
{
if ($oChildNode instanceof DOMElement)
{
return true;
}
}
}
return false;
}
function Merge(XMLParameters $oTask)
{
$this->aData = $this->array_merge_recursive_distinct($this->aData, $oTask->aData);
}
/**
* array_merge_recursive does indeed merge arrays, but it converts values with duplicate
* keys to arrays rather than overwriting the value in the first array with the duplicate
* value in the second array, as array_merge does. I.e., with array_merge_recursive,
* this happens (documented behavior):
*
* array_merge_recursive(array('key' => 'org value'), array('key' => 'new value'));
* => array('key' => array('org value', 'new value'));
*
* array_merge_recursive_distinct does not change the datatypes of the values in the arrays.
* Matching keys' values in the second array overwrite those in the first array, as is the
* case with array_merge, i.e.:
*
* array_merge_recursive_distinct(array('key' => 'org value'), array('key' => 'new value'));
* => array('key' => array('new value'));
*
* Parameters are passed by reference, though only for performance reasons. They're not
* altered by this function.
*
* @param array $array1
* @param array $array2
* @return array
* @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk>
* @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com>
*/
protected function array_merge_recursive_distinct ( array &$array1, array &$array2 )
{
$merged = $array1;
foreach ( $array2 as $key => &$value )
{
if ( is_array ( $value ) && isset ( $merged [$key] ) && is_array ( $merged [$key] ) )
{
$merged [$key] = $this->array_merge_recursive_distinct ( $merged [$key], $value );
}
else
{
$merged [$key] = $value;
}
}
return $merged;
}
}