diff --git a/core/designdocument.class.inc.php b/core/designdocument.class.inc.php
index 0d3cafc1b..2be363414 100644
--- a/core/designdocument.class.inc.php
+++ b/core/designdocument.class.inc.php
@@ -1,20 +1,23 @@
+/**
+ * Copyright (c) 2010-2018 Combodo SARL
+ *
+ * This file is part of iTop.
+ *
+ * iTop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * iTop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with iTop. If not, see
+ *
+ */
/**
* Design document and associated nodes
@@ -57,6 +60,9 @@ class DesignDocument extends DOMDocument
/**
* Overload of the standard API
+ *
+ * @param $filename
+ * @param int $options
*/
public function load($filename, $options = 0)
{
@@ -65,6 +71,11 @@ class DesignDocument extends DOMDocument
/**
* Overload of the standard API
+ *
+ * @param $filename
+ * @param int $options
+ *
+ * @return int
*/
public function save($filename, $options = 0)
{
@@ -84,18 +95,18 @@ class DesignDocument extends DOMDocument
{
return $sXml;
}
- else
- {
- echo "
\n";
- echo htmlentities($sXml);
- echo "
\n";
- }
+
+ echo "\n";
+ echo htmlentities($sXml);
+ echo "
\n";
+
+ return '';
}
/**
* Quote and escape strings for use within an XPath expression
* Usage: DesignDocument::GetNodes('class[@id='.DesignDocument::XPathQuote($sId).']');
- * @param $sValue The value to be quoted
+ * @param string $sValue The value to be quoted
* @return string to be used within an XPath
*/
public static function XPathQuote($sValue)
@@ -115,7 +126,7 @@ class DesignDocument extends DOMDocument
/**
* Extracts some nodes from the DOM
* @param string $sXPath A XPath expression
- * @param DesignNode|null $oContextNode The node to start the search from
+ * @param DesignElement $oContextNode The node to start the search from
* @return \DOMNodeList
*/
public function GetNodes($sXPath, $oContextNode = null)
@@ -134,7 +145,7 @@ class DesignDocument extends DOMDocument
/**
* An alternative to getNodePath, that gives the id of nodes instead of the position within the children
- * @param $oNode The node to describe
+ * @param DesignElement $oNode The node to describe
* @return string
*/
public static function GetItopNodePath($oNode)
@@ -166,8 +177,11 @@ class DesignElement extends \DOMElement
/**
* Create an HTML representation of the DOM, for debugging purposes
+ *
* @param bool|false $bReturnRes Echoes or returns the HTML representation
+ *
* @return mixed void or the HTML representation of the DOM
+ * @throws \Exception
*/
public function Dump($bReturnRes = false)
{
@@ -180,19 +194,16 @@ class DesignElement extends \DOMElement
{
return $sXml;
}
- else
- {
- echo "\n";
- echo htmlentities($sXml);
- echo "
\n";
- }
+ echo "\n";
+ echo htmlentities($sXml);
+ echo "
\n";
+ return '';
}
-
/**
* Returns the node directly under the given node
* @param $sTagName
* @param bool|true $bMustExist
- * @return MFElement
+ * @return \MFElement
* @throws DOMFormatException
*/
public function GetUniqueElement($sTagName, $bMustExist = true)
@@ -216,7 +227,7 @@ class DesignElement extends \DOMElement
/**
* Returns the node directly under the current node, or null if missing
* @param $sTagName
- * @return MFElement
+ * @return \MFElement
* @throws DOMFormatException
*/
public function GetOptionalElement($sTagName)
@@ -252,9 +263,12 @@ class DesignElement extends \DOMElement
/**
* Get the TEXT value from a child node
+ *
* @param string $sTagName
* @param string|null $sDefault
+ *
* @return string
+ * @throws \DOMFormatException
*/
public function GetChildText($sTagName, $sDefault = null)
{
diff --git a/setup/compat/domcompat.php b/setup/compat/domcompat.php
new file mode 100644
index 000000000..7a2dd9ee1
--- /dev/null
+++ b/setup/compat/domcompat.php
@@ -0,0 +1,48 @@
+
+ *
+ */
+
+
+/**
+ * Allow the setup page to load and perform its checks (including the check about the required extensions)
+ */
+if (!class_exists('DOMDocument'))
+{
+ /**
+ * Class DOMDocument
+ */
+ class DOMDocument {
+ function __construct(){throw new Exception('The dom extension is not enabled');}
+ }
+}
+
+
+/**
+ * Allow the setup page to load and perform its checks (including the check about the required extensions)
+ */
+if (!class_exists('DOMElement'))
+{
+ /**
+ * Class DOMElement
+ */
+ class DOMElement {
+ function __construct(){throw new Exception('The dom extension is not enabled');}
+ }
+}
diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php
index 76a646008..0965599ba 100644
--- a/setup/modelfactory.class.inc.php
+++ b/setup/modelfactory.class.inc.php
@@ -1,31 +1,31 @@
+/**
+ * Copyright (c) 2010-2018 Combodo SARL
+ *
+ * This file is part of iTop.
+ *
+ * iTop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * iTop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with iTop. If not, see
+ *
+ */
/**
* ModelFactory: in-memory manipulation of the XML MetaModel
- *
- * @copyright Copyright (C) 2010-2017 Combodo SARL
- * @license http://opensource.org/licenses/AGPL-3.0
*/
-
require_once(APPROOT.'setup/moduleinstaller.class.inc.php');
require_once(APPROOT.'setup/itopdesignformat.class.inc.php');
+require_once(APPROOT.'setup/compat/domcompat.php');
require_once(APPROOT.'core/designdocument.class.inc.php');
/**
@@ -46,7 +46,7 @@ class MFException extends Exception
* @var string
*/
protected $sExtraInfo;
-
+
const COULD_NOT_BE_ADDED = 1;
const COULD_NOT_BE_DELETED = 2;
const COULD_NOT_BE_MODIFIED_NOT_FOUND = 3;
@@ -56,7 +56,17 @@ class MFException extends Exception
const NOT_FOUND = 7;
const PARENT_NOT_FOUND = 8;
-
+
+ /**
+ * MFException constructor.
+ *
+ * @param null $message
+ * @param null $code
+ * @param int $iSourceLineNumber
+ * @param string $sXPath
+ * @param string $sExtraInfo
+ * @param null $previous
+ */
public function __construct ($message = null, $code = null, $iSourceLineNumber = 0, $sXPath = '', $sExtraInfo = '', $previous = null)
{
parent::__construct($message, $code, $previous);
@@ -99,16 +109,51 @@ class MFException extends Exception
*/
class MFModule
{
+ /**
+ * @var string
+ */
protected $sId;
+ /**
+ * @var string
+ */
protected $sName;
+ /**
+ * @var string
+ */
protected $sVersion;
+ /**
+ * @var string
+ */
protected $sRootDir;
+ /**
+ * @var string
+ */
protected $sLabel;
+ /**
+ * @var array
+ */
protected $aDataModels;
+ /**
+ * @var bool
+ */
protected $bAutoSelect;
+ /**
+ * @var string
+ */
protected $sAutoSelect;
+ /**
+ * @var array
+ */
protected $aFilesToInclude;
-
+
+ /**
+ * MFModule constructor.
+ *
+ * @param $sId
+ * @param $sRootDir
+ * @param $sLabel
+ * @param bool $bAutoSelect
+ */
public function __construct($sId, $sRootDir, $sLabel, $bAutoSelect = false)
{
$this->sId = $sId;
@@ -140,38 +185,59 @@ class MFModule
closedir($hDir);
}
}
-
-
+
+
+ /**
+ * @return mixed
+ */
public function GetId()
{
return $this->sId;
}
-
+
+ /**
+ * @return mixed
+ */
public function GetName()
{
return $this->sName;
}
+ /**
+ * @return string
+ */
public function GetVersion()
{
return $this->sVersion;
}
+ /**
+ * @return mixed
+ */
public function GetLabel()
{
return $this->sLabel;
}
-
+
+ /**
+ * @return mixed
+ */
public function GetRootDir()
{
return $this->sRootDir;
}
+ /**
+ * @return string
+ */
public function GetModuleDir()
{
return basename($this->sRootDir);
}
+ /**
+ * @return array
+ */
public function GetDataModelFiles()
{
return $this->aDataModels;
@@ -184,7 +250,10 @@ class MFModule
{
return array();
}
-
+
+ /**
+ * @return array
+ */
public function GetDictionaryFiles()
{
$aDictionaries = array();
@@ -202,39 +271,46 @@ class MFModule
}
return $aDictionaries;
}
-
+
+ /**
+ * @return bool
+ */
public function IsAutoSelect()
{
return $this->bAutoSelect;
}
-
+
+ /**
+ * @param $sAutoSelect
+ */
public function SetAutoSelect($sAutoSelect)
{
$this->sAutoSelect = $sAutoSelect;
}
+ /**
+ * @return string
+ */
public function GetAutoSelect()
{
return $this->sAutoSelect;
}
-
+
+ /**
+ * @param $aFiles
+ * @param $sCategory
+ */
public function SetFilesToInclude($aFiles, $sCategory)
{
// Now ModuleDiscovery provides us directly with relative paths... nothing to do
$this->aFilesToInclude[$sCategory] = $aFiles;
-
- /*
- $sDir = basename($this->sRootDir);
- $iLen = strlen($sDir.'/');
- foreach($aFiles as $sFile)
- {
- $iPos = strpos($sFile, $sDir.'/');
- //$this->aFilesToInclude[$sCategory][] = substr($sFile, $iPos+$iLen);
- $this->aFilesToInclude[$sCategory][] = $sFile;
- }
- */
}
-
+
+ /**
+ * @param $sCategory
+ *
+ * @return mixed
+ */
public function GetFilesToInclude($sCategory)
{
return $this->aFilesToInclude[$sCategory];
@@ -248,34 +324,47 @@ class MFModule
*/
class MFDeltaModule extends MFModule
{
+ /**
+ * MFDeltaModule constructor.
+ *
+ * @param $sDeltaFile
+ */
public function __construct($sDeltaFile)
{
- $this->sId = 'datamodel-delta';
-
+ parent::__construct('datamodel-delta', '', 'Additional Delta');
$this->sName = 'delta';
$this->sVersion = '1.0';
-
- $this->sRootDir = '';
- $this->sLabel = 'Additional Delta';
$this->aDataModels = array($sDeltaFile);
$this->aFilesToInclude = array('addons' => array(), 'business' => array(), 'webservices' => array(),);
}
+ /**
+ * @return mixed|string
+ */
public function GetName()
{
return ''; // Objects created inside this pseudo module retain their original module's name
}
+ /**
+ * @return mixed|string
+ */
public function GetRootDir()
{
return '';
}
+ /**
+ * @return string
+ */
public function GetModuleDir()
{
return '';
}
+ /**
+ * @return array
+ */
public function GetDictionaryFiles()
{
return array();
@@ -288,29 +377,41 @@ class MFDeltaModule extends MFModule
*/
class MFCoreModule extends MFModule
{
+ /**
+ * MFCoreModule constructor.
+ *
+ * @param $sName
+ * @param $sLabel
+ * @param $sDeltaFile
+ */
public function __construct($sName, $sLabel, $sDeltaFile)
{
- $this->sId = $sName;
-
+ parent::__construct($sName, '', $sLabel);
$this->sName = $sName;
$this->sVersion = '1.0';
-
- $this->sRootDir = '';
- $this->sLabel = $sLabel;
$this->aDataModels = array($sDeltaFile);
$this->aFilesToInclude = array('addons' => array(), 'business' => array(), 'webservices' => array(),);
}
-
+
+ /**
+ * @return mixed|string
+ */
public function GetRootDir()
{
return '';
}
+ /**
+ * @return string
+ */
public function GetModuleDir()
{
return '';
}
+ /**
+ * @return array
+ */
public function GetDictionaryFiles()
{
return array();
@@ -323,29 +424,41 @@ class MFCoreModule extends MFModule
*/
class MFDictModule extends MFModule
{
+ /**
+ * MFDictModule constructor.
+ *
+ * @param $sName
+ * @param $sLabel
+ * @param $sRootDir
+ */
public function __construct($sName, $sLabel, $sRootDir)
{
- $this->sId = $sName;
-
+ parent::__construct($sName, $sRootDir, $sLabel);
$this->sName = $sName;
$this->sVersion = '1.0';
-
- $this->sRootDir = $sRootDir;
- $this->sLabel = $sLabel;
$this->aDataModels = array();
$this->aFilesToInclude = array('addons' => array(), 'business' => array(), 'webservices' => array(),);
}
+ /**
+ * @return mixed|string
+ */
public function GetRootDir()
{
return '';
}
+ /**
+ * @return string
+ */
public function GetModuleDir()
{
return '';
}
-
+
+ /**
+ * @return array
+ */
public function GetDictionaryFiles()
{
$aDictionaries = array();
@@ -378,16 +491,24 @@ class ModelFactory
protected $oModules;
protected $oClasses;
protected $oMenus;
+ protected $oMeta;
protected $oDictionaries;
static protected $aLoadedClasses;
static protected $aWellKnownParents = array('DBObject', 'CMDBObject','cmdbAbstractObject');
-// static protected $aWellKnownMenus = array('DataAdministration', 'Catalogs', 'ConfigManagement', 'Contact', 'ConfigManagementCI', 'ConfigManagement:Shortcuts', 'ServiceManagement');
static protected $aLoadedModules;
static protected $aLoadErrors;
protected $aDict;
protected $aDictKeys;
-
-
+
+
+ /**
+ * ModelFactory constructor.
+ *
+ * @param $aRootDirs
+ * @param array $aRootNodeExtensions
+ *
+ * @throws \Exception
+ */
public function __construct($aRootDirs, $aRootNodeExtensions = array())
{
$this->aDict = array();
@@ -425,7 +546,13 @@ class ModelFactory
libxml_use_internal_errors(true);
}
-
+
+ /**
+ * @param null $oNode
+ * @param bool $bReturnRes
+ *
+ * @return mixed
+ */
public function Dump($oNode = null, $bReturnRes = false)
{
if (is_null($oNode))
@@ -435,6 +562,9 @@ class ModelFactory
return $oNode->Dump($bReturnRes);
}
+ /**
+ * @param $sCacheFile
+ */
public function LoadFromFile($sCacheFile)
{
$this->oDOMDocument->load($sCacheFile);
@@ -451,14 +581,22 @@ class ModelFactory
}
}
+ /**
+ * @param $sCacheFile
+ */
public function SaveToFile($sCacheFile)
{
$this->oDOMDocument->save($sCacheFile);
}
+
/**
* To progressively replace LoadModule
- * @param MFElement $oSourceNode
- * @param MFElement $oTargetParentNode
+ *
+ * @param $oSourceNode
+ * @param $oTargetParentNode
+ *
+ * @throws \MFException
+ * @throws \DOMFormatException
*/
public function LoadDelta($oSourceNode, $oTargetParentNode)
{
@@ -701,13 +839,14 @@ class ModelFactory
$sError = implode(', ', $oFormat->GetErrors());
throw new Exception("Cannot load module $sModuleName, failed to upgrade to datamodel format of: $sXmlFile. Reason(s): $sError");
}
-
+
$oDeltaRoot = $oDocument->childNodes->item(0);
$this->LoadDelta($oDeltaRoot, $this->oDOMDocument);
}
$aDictionaries = $oModule->GetDictionaryFiles();
-
+
+ $sPHPFile = 'undefined';
try
{
$this->ResetTempDictionary();
@@ -797,7 +936,7 @@ class ModelFactory
* @param string $sLanguageCode The language code
* @param string $sEnglishLanguageDesc English description of the language (unused but kept for API compatibility)
* @param string $sLocalizedLanguageDesc Localized description of the language (unused but kept for API compatibility)
- * @param hash $aEntries The entries to load: string_code => translation
+ * @param array $aEntries The entries to load: string_code => translation
*/
protected function AddToTempDictionary($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries)
{
@@ -813,7 +952,7 @@ class ModelFactory
$this->aDict[$sLanguageCode]['entries'][$sKey] = $sValue;
}
}
-
+
protected function ResetTempDictionary()
{
$this->aDict = array();
@@ -853,6 +992,11 @@ class ModelFactory
return $sMessage;
}
+ /**
+ * @param bool $bExcludeWorkspace
+ *
+ * @return array
+ */
function GetLoadedModules($bExcludeWorkspace = true)
{
if ($bExcludeWorkspace)
@@ -872,8 +1016,13 @@ class ModelFactory
}
return $aModules;
}
-
-
+
+
+ /**
+ * @param $sModuleName
+ *
+ * @return mixed|null
+ */
function GetModule($sModuleName)
{
foreach(self::$aLoadedModules as $oModule)
@@ -882,36 +1031,30 @@ class ModelFactory
}
return null;
}
-
+
+ /**
+ * @param $sTagName
+ * @param string $sValue
+ *
+ * @return mixed
+ */
public function CreateElement($sTagName, $sValue = '')
{
return $this->oDOMDocument->createElement($sTagName, $sValue);
}
-
+
+ /**
+ * @param $sXPath
+ * @param $sId
+ * @param null $oContextNode
+ *
+ * @return \DOMNodeList
+ */
public function GetNodeById($sXPath, $sId, $oContextNode = null)
{
return $this->oDOMDocument->GetNodeById($sXPath, $sId, $oContextNode);
}
- /**
- * Apply extensibility rules into the DOM
- * @param array aRestrictionRules Array of array ('selectors' => array of XPaths, 'rules' => array of rules)
- * @return void
- */
- public function RestrictExtensibility($aRestrictionRules)
- {
- foreach ($aRestrictionRules as $aRestriction)
- {
- foreach ($aRestriction['selectors'] as $sSelector)
- {
- foreach($this->GetNodes($sSelector) as $oNode)
- {
- $oNode->RestrictExtensibility($aRestriction['rules']);
- }
- }
- }
- }
-
/**
* Check if the class specified by the given node already exists in the loaded DOM
* @param DOMNode $oClassNode The node corresponding to the class to load
@@ -987,7 +1130,13 @@ class ModelFactory
}
}
}
-
+
+ /**
+ * @param $sName
+ * @param $sIcon
+ *
+ * @return string
+ */
public function GetClassXMLTemplate($sName, $sIcon)
{
$sHeader = ''.'xml version="1.0" encoding="utf-8"?'.'>';
@@ -1018,7 +1167,10 @@ EOF
/**
* List all constants from the DOM, for a given module
+ *
* @param string $sModuleName
+ *
+ * @return \DOMNodeList
* @throws Exception
*/
public function ListConstants($sModuleName)
@@ -1028,7 +1180,10 @@ EOF
/**
* List all classes from the DOM, for a given module
+ *
* @param string $sModuleName
+ *
+ * @return \DOMNodeList
* @throws Exception
*/
public function ListClasses($sModuleName)
@@ -1054,12 +1209,22 @@ EOF
return $this->GetNodes("/itop_design/classes/class/class[class]");
}
+ /**
+ * @param $sClassName
+ *
+ * @return \DOMElement
+ */
public function GetClass($sClassName)
{
$oClassNode = $this->GetNodes("/itop_design/classes//class[@id='$sClassName']")->item(0);
return $oClassNode;
}
-
+
+ /**
+ * @param $sWellKnownParent
+ *
+ * @return mixed
+ */
public function AddWellKnownParent($sWellKnownParent)
{
$oWKClass = $this->oDOMDocument->CreateElement('class');
@@ -1067,13 +1232,25 @@ EOF
$this->oClasses->AppendChild($oWKClass);
return $oWKClass;
}
-
+
+ /**
+ * @param $oClassNode
+ *
+ * @return \DOMNodeList
+ */
public function GetChildClasses($oClassNode)
{
return $this->GetNodes("class", $oClassNode);
}
-
-
+
+
+ /**
+ * @param $sClassName
+ * @param $sAttCode
+ *
+ * @return \DOMElement|null
+ * @throws \Exception
+ */
public function GetField($sClassName, $sAttCode)
{
if (!$this->ClassNameExists($sClassName))
@@ -1088,41 +1265,56 @@ EOF
}
return $oFieldNode;
}
-
+
/**
* List all classes from the DOM
- * @throws Exception
+ *
+ * @param \DOMNode $oClassNode
+ *
+ * @return \DOMNodeList
*/
public function ListFields(DOMNode $oClassNode)
{
return $this->GetNodes("fields/field", $oClassNode);
}
-
+
/**
* List all transitions from a given state
+ *
* @param DOMNode $oStateNode The state
+ *
+ * @return \DOMNodeList
* @throws Exception
*/
public function ListTransitions(DOMNode $oStateNode)
{
return $this->GetNodes("transitions/transition", $oStateNode);
}
-
+
/**
* List all states of a given class
+ *
* @param DOMNode $oClassNode The class
+ *
+ * @return \DOMNodeList
* @throws Exception
*/
public function ListStates(DOMNode $oClassNode)
{
return $this->GetNodes("lifecycle/states/state", $oClassNode);
}
-
+
+ /**
+ * @return mixed
+ */
public function ApplyChanges()
{
return $this->oRoot->ApplyChanges();
}
-
+
+ /**
+ * @return mixed
+ */
public function ListChanges()
{
return $this->oRoot->ListChanges();
@@ -1130,7 +1322,11 @@ EOF
/**
- * Import the node into the delta
+ * Import the node into the delta
+ *
+ * @param $oNodeClone
+ *
+ * @return mixed
*/
protected function SetDeltaFlags($oNodeClone)
{
@@ -1170,9 +1366,12 @@ EOF
/**
* Create path for the delta
- * @param Array aMovedClasses The classes that have been moved in the hierarchy (deleted + created elsewhere)
+ *
+ * @param array aMovedClasses The classes that have been moved in the hierarchy (deleted + created elsewhere)
* @param DOMDocument oTargetDoc Where to attach the top of the hierarchy
- * @param MFElement oNode The node to import with its path
+ * @param MFElement oNode The node to import with its path
+ *
+ * @return \DOMElement|null
*/
protected function ImportNodeAndPathDelta($aMovedClasses, $oTargetDoc, $oNode)
{
@@ -1214,7 +1413,7 @@ EOF
{
if ($sAlteration == 'removed')
{
- // Remove that node: this specification will be overriden by the 'replaced' spec (see below)
+ // Remove that node: this specification will be overridden by the 'replaced' spec (see below)
$oClassNode->parentNode->removeChild($oClassNode);
}
else
@@ -1260,8 +1459,12 @@ EOF
/**
* Set the value for a given trace attribute
- * See MFElement::SetTrace to enable/disable change traces
- */
+ * See MFElement::SetTrace to enable/disable change traces
+ *
+ * @param $sAttribute
+ * @param $sPreviousValue
+ * @param $sNewValue
+ */
public function SetTraceValue($sAttribute, $sPreviousValue, $sNewValue)
{
// Search into the deleted node as well!
@@ -1274,7 +1477,13 @@ EOF
/**
* Get the document version of the delta
- */
+ *
+ * @param array $aNodesToIgnore
+ * @param null $aAttributes
+ *
+ * @return \MFDocument
+ * @throws \Exception
+ */
public function GetDeltaDocument($aNodesToIgnore = array(), $aAttributes = null)
{
$oDelta = new MFDocument();
@@ -1333,17 +1542,25 @@ EOF
/**
* Get the text/XML version of the delta
- */
+ *
+ * @param array $aNodesToIgnore
+ * @param null $aAttributes
+ *
+ * @return string
+ * @throws \Exception
+ */
public function GetDelta($aNodesToIgnore = array(), $aAttributes = null)
{
$oDelta = $this->GetDeltaDocument($aNodesToIgnore, $aAttributes);
return $oDelta->saveXML();
}
-
+
/**
* Searches on disk in the root directories for module description files
* and returns an array of MFModules
+ *
* @return array Array of MFModules
+ * @throws \Exception
*/
public function FindModules()
{
@@ -1372,9 +1589,13 @@ EOF
}
return $aResult;
}
-
+
public function TestAlteration()
{
+ $sDOMOriginal = 'undefined';
+ $sDOMModified = 'undefined';
+ $sDOMRebuilt = 'undefined';
+ $sDeltaXML = 'undefined';
try
{
$sHeader = '';
@@ -1428,7 +1649,7 @@ EOF;
$oNewC->Rename('blah');
$oNewC->Rename('foo');
$oNewC->AddChildNode($this->oDOMDocument->CreateElement('y', '(no flag)'));
- $oNewC->AddChildNode($this->oDOMDocument->CreateElement('x', 'To delete programatically'));
+ $oNewC->AddChildNode($this->oDOMDocument->CreateElement('x', 'To delete programmatically'));
$oSubNode = $oNewC->GetUniqueElement('z');
$oSubNode->Rename('abcdef');
$oSubNode = $oNewC->GetUniqueElement('x');
@@ -1447,7 +1668,7 @@ EOF;
$oSubnode->setAttribute('id', 'to be changed');
$oNewA->AddChildNode($oSubnode);
$oNewA->AddChildNode($this->oDOMDocument->CreateElement('f', 'Welcome to the newcomer'));
- $oNewA->AddChildNode($this->oDOMDocument->CreateElement('x', 'To delete programatically'));
+ $oNewA->AddChildNode($this->oDOMDocument->CreateElement('x', 'To delete programmatically'));
// Alter this "new a", as it is new, no flag should be set
$oNewA->Rename('new_a');
@@ -1469,7 +1690,7 @@ EOF;
//echo "\n";
//echo htmlentities($sDeltaXML);
//echo "
\n";
-
+
// Reiterating - try to remake the DOM by applying the computed delta
//
$this->oDOMDocument = new MFDocument();
@@ -1527,7 +1748,11 @@ EOF;
/**
* Extracts some nodes from the DOM
+ *
* @param string $sXPath A XPath expression
+ * @param null $oContextNode
+ * @param bool $bSafe
+ *
* @return DOMNodeList
*/
public function GetNodes($sXPath, $oContextNode = null, $bSafe = true)
@@ -1536,15 +1761,6 @@ EOF;
}
}
-
-/**
- * Allow the setup page to load and perform its checks (including the check about the required extensions)
- */
-if (!class_exists('DOMElement'))
-{
-class DOMElement {function __construct(){throw new Exception('The dom extension is not enabled');}}
-}
-
/**
* MFElement: helper to read/change the DOM
* @package ModelFactory
@@ -1553,17 +1769,23 @@ class MFElement extends Combodo\iTop\DesignElement
{
/**
* Extracts some nodes from the DOM
+ *
* @param string $sXPath A XPath expression
+ * @param bool $bSafe
+ *
* @return DOMNodeList
*/
public function GetNodes($sXPath, $bSafe = true)
{
return $this->ownerDocument->GetNodes($sXPath, $this, $bSafe);
}
-
+
/**
* Extracts some nodes from the DOM (active nodes only !!!)
+ *
* @param string $sXPath A XPath expression
+ * @param $sId
+ *
* @return DOMNodeList
*/
public function GetNodeById($sXPath, $sId)
@@ -1572,8 +1794,14 @@ class MFElement extends Combodo\iTop\DesignElement
}
/**
- * Returns the node directly under the given node
- */
+ * Returns the node directly under the given node
+ *
+ * @param $sTagName
+ * @param bool $bMustExist
+ *
+ * @return MFElement
+ * @throws \DOMFormatException
+ */
public function GetUniqueElement($sTagName, $bMustExist = true)
{
$oNode = null;
@@ -1591,16 +1819,21 @@ class MFElement extends Combodo\iTop\DesignElement
}
return $oNode;
}
-
+
/**
* Assumes the current node to be either a text or
*
* - value
-
*
- value
-
*
- * where value can be the either a text or an array of items... recursively
- * Returns a PHP array
- */
+ * where value can be the either a text or an array of items... recursively
+ * Returns a PHP array
+ *
+ * @param string $sElementName
+ *
+ * @return array|null|string
+ * @throws \DOMFormatException
+ */
public function GetNodeAsArrayOfItems($sElementName = 'items')
{
$oItems = $this->GetOptionalElement($sElementName);
@@ -1647,17 +1880,11 @@ class MFElement extends Combodo\iTop\DesignElement
return $res;
}
- public function SetNodeAsArrayOfItems($aList)
- {
- $oNewNode = $this->ownerDocument->CreateElement($this->tagName);
- if ($this->getAttribute('id') != '')
- {
- $oNewNode->setAttribute('id', $this->getAttribute('id'));
- }
- self::AddItemToNode($this->ownerDocument, $oNewNode, $aList);
- $this->parentNode->RedefineChildNode($oNewNode);
- }
-
+ /**
+ * @param $oXmlDoc
+ * @param $oXMLNode
+ * @param $itemValue
+ */
protected static function AddItemToNode($oXmlDoc, $oXMLNode, $itemValue)
{
if (is_array($itemValue))
@@ -1697,26 +1924,33 @@ class MFElement extends Combodo\iTop\DesignElement
}
$this->removeChild($this->firstChild);
}
- }
+ }
/**
* Find the child node matching the given node.
* UNSAFE: may return nodes marked as _alteration="removed"
* A method with the same signature MUST exist in MFDocument for the recursion to work fine
+ *
* @param MFElement $oRefNode The node to search for
- * @param string $sSearchId substitutes to the value of the 'id' attribute
- */
+ * @param string $sSearchId substitutes to the value of the 'id' attribute
+ *
+ * @return \DOMElement|null
+ * @throws \Exception
+ */
public function _FindChildNode(MFElement $oRefNode, $sSearchId = null)
{
return self::_FindNode($this, $oRefNode, $sSearchId);
}
-
+
/**
* Find the child node matching the given node under the specified parent.
* UNSAFE: may return nodes marked as _alteration="removed"
+ *
* @param DOMNode $oParent
* @param MFElement $oRefNode
* @param string $sSearchId
+ *
+ * @return \DOMElement|null
* @throws Exception
*/
public static function _FindNode(DOMNode $oParent, MFElement $oRefNode, $sSearchId = null)
@@ -1789,12 +2023,12 @@ class MFElement extends Combodo\iTop\DesignElement
}
return false;
}
-
+
static $aTraceAttributes = null;
/**
* Enable/disable the trace on changed nodes
*
- *@param aAttributes array Array of attributes (key => value) to be added onto any changed node
+ *@param array aAttributes Array of attributes (key => value) to be added onto any changed node
*/
static public function SetTrace($aAttributes = null)
{
@@ -1817,8 +2051,11 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Add a node and set the flags that will be used to compute the delta
+ *
* @param MFElement $oNode The node (including all subnodes) to add
- */
+ *
+ * @throws \MFException
+ */
public function AddChildNode(MFElement $oNode)
{
// First: cleanup any flag behind the new node, and eventually add trace data
@@ -1850,8 +2087,12 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Modify a node and set the flags that will be used to compute the delta
+ *
* @param MFElement $oNode The node (including all subnodes) to set
- */
+ * @param null $sSearchId
+ *
+ * @throws \MFException
+ */
public function RedefineChildNode(MFElement $oNode, $sSearchId = null)
{
// First: cleanup any flag behind the new node, and eventually add trace data
@@ -1870,7 +2111,6 @@ class MFElement extends Combodo\iTop\DesignElement
{
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
$iLine = $oNode->getLineNo();
- $sSourceNode = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(is_null($sSearchId) ? '' : "[$sSearchId]").' at line '.$this->getLineNo();
throw new MFException($sPath." at line $iLine: could not be modified (marked as deleted)", MFException::COULD_NOT_BE_MODIFIED_ALREADY_DELETED, $sPath, $iLine);
}
$oExisting->ReplaceWith($oNode);
@@ -1890,7 +2130,9 @@ class MFElement extends Combodo\iTop\DesignElement
* @param MFElement $oNode The node (including all subnodes) to set
* @param string $sSearchId Optional Id of the node to SearchMenuNode
* @param bool $bForce Force mode to dynamically add or replace nodes
- */
+ *
+ * @throws \Exception
+ */
public function SetChildNode(MFElement $oNode, $sSearchId = null, $bForce = false)
{
// First: cleanup any flag behind the new node, and eventually add trace data
@@ -1966,10 +2208,11 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Remove a node and set the flags that will be used to compute the delta
- */
+ *
+ * @throws \Exception
+ */
public function Delete()
{
- $oParent = $this->parentNode;
switch ($this->getAttribute('_alteration'))
{
case 'replaced':
@@ -2012,7 +2255,9 @@ class MFElement extends Combodo\iTop\DesignElement
* @param string $sSearchId The id to consider (could be blank)
* @param bool $bMustExist Throw an exception if the node must already be found (and not marked as deleted!)
* @param bool $bIfExists Return null if the node does not exists (or is marked as deleted)
+ *
* @return DOMNode|null
+ * @throws \Exception
*/
public function MergeInto($oContainer, $sSearchId, $bMustExist, $bIfExists = false)
{
@@ -2052,8 +2297,8 @@ class MFElement extends Combodo\iTop\DesignElement
/**
* Renames a node and set the flags that will be used to compute the delta
- * @param String $sNewId The new id
- */
+ * @param string $sId The new id
+ */
public function Rename($sId)
{
if (($this->getAttribute('_alteration') == 'replaced') || !$this->IsInDefinition())
@@ -2074,42 +2319,6 @@ class MFElement extends Combodo\iTop\DesignElement
$this->AddTrace();
}
- /**
- * Apply extensibility rules onto this node
- * @param array aRules Array of rules (strings)
- * @return void
- */
- public function RestrictExtensibility($aRules)
- {
- $oRulesNode = $this->GetOptionalElement('rules');
- if ($oRulesNode)
- {
- $aCurrentRules = $oRulesNode->GetNodeAsArrayOfItems();
- $aCurrentRules = array_merge($aCurrentRules, $aRules);
- $oRulesNode->SetNodeAsArrayOfItems($aCurrentRules);
- }
- else
- {
- $oNewNode = $this->ownerDocument->CreateElement('rules');
- $this->appendChild($oNewNode);
- $oNewNode->SetNodeAsArrayOfItems($aRules);
- }
- }
-
- /**
- * Read extensibility rules for this node
- * @return Array of rules (strings)
- */
- public function GetExtensibilityRules()
- {
- $aCurrentRules = array();
- $oRulesNode = $this->GetOptionalElement('rules');
- if ($oRulesNode)
- {
- $aCurrentRules = $oRulesNode->GetNodeAsArrayOfItems();
- }
- return $aCurrentRules;
- }
/**
* List changes below a given node (see also MFDocument::ListChanges)
@@ -2152,21 +2361,13 @@ class MFElement extends Combodo\iTop\DesignElement
}
/**
- * Allow the setup page to load and perform its checks (including the check about the required extensions)
- */
-if (!class_exists('DOMDocument'))
-{
- class DOMDocument {function __construct(){throw new Exception('The dom extension is not enabled');}}
-}
-
-/**
- * MFDocument - formating rules for XML input/output
+ * MFDocument - formatting rules for XML input/output
* @package ModelFactory
*/
class MFDocument extends \Combodo\iTop\DesignDocument
{
/**
- * Overloadable. Called prior to data loading.
+ * Over loadable. Called prior to data loading.
*/
protected function Init()
{
@@ -2176,6 +2377,11 @@ class MFDocument extends \Combodo\iTop\DesignDocument
/**
* Overload the standard API
+ *
+ * @param \DOMNode|null $node
+ * @param int $options
+ *
+ * @return string
*/
public function saveXML(DOMNode $node = null, $options = 0)
{
@@ -2189,12 +2395,19 @@ class MFDocument extends \Combodo\iTop\DesignDocument
}
return parent::saveXML($node);
}
-
+
/**
* Overload createElement to make sure (via new DOMText) that the XML entities are
* always properly escaped
* (non-PHPdoc)
+ *
* @see DOMDocument::createElement()
+ *
+ * @param $sName
+ * @param null $value
+ * @param null $namespaceURI
+ *
+ * @return \DOMNode
*/
function createElement($sName, $value = null, $namespaceURI = null)
{
@@ -2209,9 +2422,13 @@ class MFDocument extends \Combodo\iTop\DesignDocument
/**
* Find the child node matching the given node
* A method with the same signature MUST exist in MFElement for the recursion to work fine
+ *
* @param MFElement $oRefNode The node to search for
- * @param string $sSearchId substitutes to the value of the 'id' attribute
- */
+ * @param string $sSearchId substitutes to the value of the 'id' attribute
+ *
+ * @return \DOMElement|null
+ * @throws \Exception
+ */
public function _FindChildNode(MFElement $oRefNode, $sSearchId = null)
{
return MFElement::_FindNode($this, $oRefNode, $sSearchId);
@@ -2219,7 +2436,11 @@ class MFDocument extends \Combodo\iTop\DesignDocument
/**
* Extracts some nodes from the DOM
+ *
* @param string $sXPath A XPath expression
+ * @param null $oContextNode
+ * @param bool $bSafe
+ *
* @return DOMNodeList
*/
public function GetNodes($sXPath, $oContextNode = null, $bSafe = true)
@@ -2240,7 +2461,14 @@ class MFDocument extends \Combodo\iTop\DesignDocument
}
return $oResult;
}
-
+
+ /**
+ * @param $sXPath
+ * @param $sId
+ * @param null $oContextNode
+ *
+ * @return \DOMNodeList
+ */
public function GetNodeById($sXPath, $sId, $oContextNode = null)
{
$oXPath = new DOMXPath($this);
@@ -2267,12 +2495,25 @@ class MFParameters
{
protected $aData = null;
+ /**
+ * MFParameters constructor.
+ *
+ * @param \DOMNode $oNode
+ *
+ * @throws \Exception
+ */
public function __construct(DOMNode $oNode)
{
$this->aData = array();
$this->LoadFromDOM($oNode);
}
+ /**
+ * @param $sCode
+ * @param string $default
+ *
+ * @return mixed|string
+ */
public function Get($sCode, $default = '')
{
if (array_key_exists($sCode, $this->aData))
@@ -2282,11 +2523,19 @@ class MFParameters
return $default;
}
+ /**
+ * @return array|null
+ */
public function GetAll()
{
return $this->aData;
}
+ /**
+ * @param \DOMNode $oNode
+ *
+ * @throws \Exception
+ */
public function LoadFromDOM(DOMNode $oNode)
{
$this->aData = array();
@@ -2299,8 +2548,15 @@ class MFParameters
}
}
+ /**
+ * @param \DOMNode $oNode
+ *
+ * @return array|bool|int
+ * @throws \Exception
+ */
protected function ReadElement(DOMNode $oNode)
{
+ $value = null;
if ($oNode instanceof DOMElement)
{
$sDefaultNodeType = ($this->HasChildNodes($oNode)) ? 'hash' : 'string';
@@ -2379,9 +2635,17 @@ class MFParameters
{
$value = $oNode->wholeText;
}
+
return $value;
}
+ /**
+ * @param $sAttName
+ * @param $oNode
+ * @param $sDefaultValue
+ *
+ * @return mixed
+ */
protected function GetAttribute($sAttName, $oNode, $sDefaultValue)
{
$sRet = $sDefaultValue;
@@ -2398,7 +2662,12 @@ class MFParameters
}
/**
- * Returns the TEXT of the current node (possibly from several subnodes)
+ * Returns the TEXT of the current node (possibly from several sub nodes)
+ *
+ * @param $oNode
+ * @param null $sDefault
+ *
+ * @return null|string
*/
public function GetText($oNode, $sDefault = null)
{
@@ -2420,8 +2689,13 @@ class MFParameters
return $sText;
}
}
+
/**
* Check if a node has child nodes (apart from text nodes)
+ *
+ * @param $oNode
+ *
+ * @return bool
*/
public function HasChildNodes($oNode)
{
@@ -2437,6 +2711,10 @@ class MFParameters
}
return false;
}
+
+ /**
+ * @param \XMLParameters $oTask
+ */
function Merge(XMLParameters $oTask)
{
//todo: clarify the usage of this function that CANNOT work
@@ -2452,7 +2730,7 @@ class MFParameters
* 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.
+ * array_merge_recursive_distinct does not change the data types 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.:
*
diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php
index ae8f52b66..4a92f7ad5 100644
--- a/setup/modulediscovery.class.inc.php
+++ b/setup/modulediscovery.class.inc.php
@@ -1,26 +1,22 @@
-
/**
- * ModuleDiscovery: list available modules
+ * Copyright (c) 2010-2018 Combodo SARL
+ *
+ * This file is part of iTop.
+ *
+ * iTop is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * iTop is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with iTop. If not, see
*
- * @copyright Copyright (C) 2010-2012 Combodo SARL
- * @license http://opensource.org/licenses/AGPL-3.0
*/
class MissingDependencyException extends Exception
@@ -154,23 +150,28 @@ class ModuleDiscovery
}
/**
- * Get the list of "discovered" modules, ordered based on their (inter) dependencies
- * @param bool $bAbortOnMissingDependency ...
- * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
- */
+ * Get the list of "discovered" modules, ordered based on their (inter) dependencies
+ *
+ * @param bool $bAbortOnMissingDependency ...
+ * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
+ *
+ * @return array
+ * @throws \MissingDependencyException
+ */
protected static function GetModules($bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
// Order the modules to take into account their inter-dependencies
return self::OrderModulesByDependencies(self::$m_aModules, $bAbortOnMissingDependency, $aModulesToLoad);
}
-
+
/**
* Arrange an list of modules, based on their (inter) dependencies
- * @param hash $aModules The list of modules to process: 'id' => $aModuleInfo
- * @param bool $bAbortOnMissingDependency ...
- * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
- * @return hash
- */
+ * @param array $aModules The list of modules to process: 'id' => $aModuleInfo
+ * @param bool $bAbortOnMissingDependency ...
+ * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
+ * @return array
+ * @throws \MissingDependencyException
+*/
public static function OrderModulesByDependencies($aModules, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
// Order the modules to take into account their inter-dependencies
@@ -178,7 +179,7 @@ class ModuleDiscovery
$aSelectedModules = array();
foreach($aModules as $sId => $aModule)
{
- list($sModuleName, $sModuleVersion) = self::GetModuleName($sId);
+ list($sModuleName, ) = self::GetModuleName($sId);
if (is_null($aModulesToLoad) || in_array($sModuleName, $aModulesToLoad))
{
$aDependencies[$sId] = $aModule['dependencies'];
@@ -234,8 +235,8 @@ class ModuleDiscovery
/**
* Remove the duplicate modules (i.e. modules with the same name but with a different version) from the supplied list of modules
- * @param hash $aModules
- * @return hash The ordered modules as a duplicate-free list of modules
+ * @param array $aModules
+ * @return array The ordered modules as a duplicate-free list of modules
*/
public static function RemoveDuplicateModules($aModules)
{
@@ -340,10 +341,13 @@ class ModuleDiscovery
/**
* Search (on the disk) for all defined iTop modules, load them and returns the list (as an array)
* of the possible iTop modules to install
- * @param aSearchDirs Array of directories to search (absolute paths)
- * @param bool $bAbortOnMissingDependency ...
- * @param hash $aModulesToLoad List of modules to search for, defaults to all if ommitted
- * @return Hash A big array moduleID => ModuleData
+ *
+ * @param $aSearchDirs array of directories to search (absolute paths)
+ * @param bool $bAbortOnMissingDependency ...
+ * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
+ *
+ * @return array A big array moduleID => ModuleData
+ * @throws \Exception
*/
public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
{
@@ -404,13 +408,15 @@ class ModuleDiscovery
}
return array($sName, $sVersion);
}
-
+
/**
* Helper function to browse a directory and get the modules
+ *
* @param $sRelDir string Directory to start from
* @param $sRootDir string The root directory path
- * @return array(name, version)
- */
+ *
+ * @throws \Exception
+ */
protected static function ListModuleFiles($sRelDir, $sRootDir)
{
static $iDummyClassIndex = 0;