diff --git a/core/designdocument.class.inc.php b/core/designdocument.class.inc.php new file mode 100644 index 000000000..90017b48a --- /dev/null +++ b/core/designdocument.class.inc.php @@ -0,0 +1,265 @@ + + +/** + * Design document and associated nodes + * @package Core + */ + +namespace Combodo\iTop; + +/** + * Class \Combodo\iTop\DesignDocument + * + * A design document is the DOM tree that modelize behaviors. One of its + * characteristics is that it can be altered by the mean of the same kind of document. + * + */ +class DesignDocument extends \DOMDocument +{ + /** + * @throws \Exception + */ + public function __construct() + { + parent::__construct('1.0', 'UTF-8'); + $this->Init(); + } + + /** + * Overloadable. Called prior to data loading. + */ + protected function Init() + { + $this->registerNodeClass('DOMElement', '\Combodo\iTop\DesignElement'); + + $this->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS) + $this->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect + } + + /** + * Overload of the standard API + */ + public function load($filename, $options = 0) + { + parent::load($filename, LIBXML_NOBLANKS); + } + + /** + * Overload of the standard API + */ + public function save($filename, $options = 0) + { + $this->documentElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); + return parent::save($filename, LIBXML_NOBLANKS); + } + + /** + * 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 + */ + public function Dump($bReturnRes = false) + { + $sXml = $this->saveXML(); + if ($bReturnRes) + { + return $sXml; + } + else + { + echo "
\n"; + echo htmlentities($sXml); + echo "\n"; + } + } + + /** + * 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 + * @return string to be used within an XPath + */ + public static function XPathQuote($sValue) + { + if (strpos($sValue, '"') !== false) + { + $aParts = explode('"', $sValue); + $sRet = 'concat("'.implode('", \'"\', "', $aParts).'")'; + } + else + { + $sRet = '"'.$sValue.'"'; + } + return $sRet; + } + + /** + * Extracts some nodes from the DOM + * @param string $sXPath A XPath expression + * @param DesignNode|null $oContextNode The node to start the search from + * @return \DOMNodeList + */ + public function GetNodes($sXPath, $oContextNode = null) + { + $oXPath = new \DOMXPath($this); + if (is_null($oContextNode)) + { + $oResult = $oXPath->query($sXPath); + } + else + { + $oResult = $oXPath->query($sXPath, $oContextNode); + } + return $oResult; + } + + /** + * An alternative to getNodePath, that gives the id of nodes instead of the position within the children + * @param $oNode The node to describe + * @return string + */ + public static function GetItopNodePath($oNode) + { + if ($oNode instanceof \DOMDocument) return ''; + if (is_null($oNode)) return ''; + + $sId = $oNode->getAttribute('id'); + $sNodeDesc = ($sId != '') ? $oNode->nodeName.'['.$sId.']' : $oNode->nodeName; + return self::GetItopNodePath($oNode->parentNode).'/'.$sNodeDesc; + } +} + +/** + * DesignElement: helper to read/change the DOM + * @package ModelFactory + */ +class DesignElement extends \DOMElement +{ + /** + * Extracts some nodes from the DOM + * @param string $sXPath A XPath expression + * @return \DOMNodeList + */ + public function GetNodes($sXPath) + { + return $this->ownerDocument->GetNodes($sXPath, $this); + } + + /** + * 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 + */ + public function Dump($bReturnRes = false) + { + $oDoc = new DesignDocument(); + $oClone = $oDoc->importNode($this->cloneNode(true), true); + $oDoc->appendChild($oClone); + + $sXml = $oDoc->saveXML($oClone); + if ($bReturnRes) + { + return $sXml; + } + else + { + echo "
\n"; + echo htmlentities($sXml); + echo "\n"; + } + } + + /** + * Returns the node directly under the given node + * @param $sTagName + * @param bool|true $bMustExist + * @return null + * @throws DOMFormatException + */ + public function GetUniqueElement($sTagName, $bMustExist = true) + { + $oNode = null; + foreach($this->childNodes as $oChildNode) + { + if ($oChildNode->nodeName == $sTagName) + { + $oNode = $oChildNode; + break; + } + } + if ($bMustExist && is_null($oNode)) + { + throw new DOMFormatException('Missing unique tag: '.$sTagName); + } + return $oNode; + } + + /** + * Returns the node directly under the current node, or null if missing + * @param $sTagName + * @return null + * @throws DOMFormatException + */ + public function GetOptionalElement($sTagName) + { + return $this->GetUniqueElement($sTagName, false); + } + + /** + * Returns the TEXT of the current node (possibly from several child nodes) + * @param null $sDefault + * @return null|string + */ + public function GetText($sDefault = null) + { + $sText = null; + foreach($this->childNodes as $oChildNode) + { + if ($oChildNode instanceof \DOMText) + { + if (is_null($sText)) $sText = ''; + $sText .= $oChildNode->wholeText; + } + } + if (is_null($sText)) + { + return $sDefault; + } + else + { + return $sText; + } + } + + /** + * Get the TEXT value from a child node + * @param string $sTagName + * @param string|null $sDefault + * @return string + */ + public function GetChildText($sTagName, $sDefault = null) + { + $sRet = $sDefault; + if ($oChild = $this->GetOptionalElement($sTagName)) + { + $sRet = $oChild->GetText($sDefault); + } + return $sRet; + } +} diff --git a/core/moduledesign.class.inc.php b/core/moduledesign.class.inc.php index 90e3588e9..f210347e1 100644 --- a/core/moduledesign.class.inc.php +++ b/core/moduledesign.class.inc.php @@ -1,5 +1,5 @@ Init(); + parent::__construct(); if (!is_null($sDesignSourceId)) { @@ -71,20 +71,9 @@ class ModuleDesign extends DOMDocument } } - /** - * Overloadable. Called prior to data loading. - */ - protected function Init() - { - $this->registerNodeClass('DOMElement', 'ModuleDesignElement'); - - $this->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS) - $this->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect - } - /** * Gets the data where the compiler has left them... - * @param $sDesignSourceId Identifier of the section module_design (generally a module name) + * @param $sDesignSourceId String Identifier of the section module_design (generally a module name) * @throws Exception */ protected function LoadFromCompiledDesigns($sDesignSourceId) @@ -128,213 +117,4 @@ class ModuleDesign extends DOMDocument throw new Exception("Invalid XML in '$sFile'. Errors: ".implode(', ', $aDisplayErrors)); } } - - /** - * Overload of the standard API - */ - public function load($filename, $options = 0) - { - parent::load($filename, LIBXML_NOBLANKS); - } - - /** - * Overload of the standard API - */ - public function save($filename, $options = 0) - { - $this->documentElement->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance"); - return parent::save($filename, LIBXML_NOBLANKS); - } - - /** - * 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 - */ - public function Dump($bReturnRes = false) - { - $sXml = $this->saveXML(); - if ($bReturnRes) - { - return $sXml; - } - else - { - echo "
\n"; - echo htmlentities($sXml); - echo "\n"; - } - } - - /** - * 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 - * @return string to be used within an XPath - */ - public static function XPathQuote($sValue) - { - if (strpos($sValue, '"') !== false) - { - $aParts = explode('"', $sValue); - $sRet = 'concat("'.implode('", \'"\', "', $aParts).'")'; - } - else - { - $sRet = '"'.$sValue.'"'; - } - return $sRet; - } - - /** - * Extracts some nodes from the DOM - * @param string $sXPath A XPath expression - * @param DesignNode|null $oContextNode The node to start the search from - * @return DOMNodeList - */ - public function GetNodes($sXPath, $oContextNode = null) - { - $oXPath = new DOMXPath($this); - if (is_null($oContextNode)) - { - $oResult = $oXPath->query($sXPath); - } - else - { - $oResult = $oXPath->query($sXPath, $oContextNode); - } - return $oResult; - } - - /** - * An alternative to getNodePath, that gives the id of nodes instead of the position within the children - */ - public static function GetItopNodePath($oNode) - { - if ($oNode instanceof DOMDocument) return ''; - - $sId = $oNode->getAttribute('id'); - $sNodeDesc = ($sId != '') ? $oNode->nodeName.'['.$sId.']' : $oNode->nodeName; - return self::GetItopNodePath($oNode->parentNode).'/'.$sNodeDesc; - } -} - - -/** - * ModuleDesignElement: helper to read/change the DOM - * @package ModelFactory - */ -class ModuleDesignElement extends DOMElement -{ - /** - * Extracts some nodes from the DOM - * @param string $sXPath A XPath expression - * @return DOMNodeList - */ - public function GetNodes($sXPath) - { - return $this->ownerDocument->GetNodes($sXPath, $this); - } - - /** - * 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 - */ - public function Dump($bReturnRes = false) - { - $oDoc = new ModuleDesign(); - $oClone = $oDoc->importNode($this->cloneNode(true), true); - $oDoc->appendChild($oClone); - - $sXml = $oDoc->saveXML($oClone); - if ($bReturnRes) - { - return $sXml; - } - else - { - echo "
\n"; - echo htmlentities($sXml); - echo "\n"; - } - } - - /** - * Returns the node directly under the given node - * @param $sTagName - * @param bool|true $bMustExist - * @return null - * @throws DOMFormatException - */ - public function GetUniqueElement($sTagName, $bMustExist = true) - { - $oNode = null; - foreach($this->childNodes as $oChildNode) - { - if ($oChildNode->nodeName == $sTagName) - { - $oNode = $oChildNode; - break; - } - } - if ($bMustExist && is_null($oNode)) - { - throw new DOMFormatException('Missing unique tag: '.$sTagName); - } - return $oNode; - } - - /** - * Returns the node directly under the current node, or null if missing - * @param $sTagName - * @return null - * @throws DOMFormatException - */ - public function GetOptionalElement($sTagName) - { - return $this->GetUniqueElement($sTagName, false); - } - - /** - * Returns the TEXT of the current node (possibly from several child nodes) - * @param null $sDefault - * @return null|string - */ - public function GetText($sDefault = null) - { - $sText = null; - foreach($this->childNodes as $oChildNode) - { - if ($oChildNode instanceof DOMText) - { - if (is_null($sText)) $sText = ''; - $sText .= $oChildNode->wholeText; - } - } - if (is_null($sText)) - { - return $sDefault; - } - else - { - return $sText; - } - } - - /** - * Get the TEXT value from a child node - * @param string $sTagName - * @param string|null $sDefault - * @return string - */ - public function GetChildText($sTagName, $sDefault = null) - { - $sRet = $sDefault; - if ($oChild = $this->GetOptionalElement($sTagName)) - { - $sRet = $oChild->GetText($sDefault); - } - return $sRet; - } } diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php index ef6a95d94..01a22db0a 100644 --- a/setup/modelfactory.class.inc.php +++ b/setup/modelfactory.class.inc.php @@ -1,5 +1,5 @@ \n"; $this->oDOMDocument->firstChild->Dump(); - throw new Exception(MFDocument::GetItopNodePath($oSourceNode).' at line '.$oSourceNode->getLineNo().": could not find parent with id $sParentId"); + throw new Exception(MFDocument::GetItopNodePath($oSourceNode).' at line '.$oSourceNode->getLineNo().": could not find parent with id '$sParentId'"); } } else @@ -1316,7 +1317,7 @@ class DOMElement {function __construct(){throw new Exception('The dom extension * MFElement: helper to read/change the DOM * @package ModelFactory */ -class MFElement extends DOMElement +class MFElement extends Combodo\iTop\DesignElement { /** * Extracts some nodes from the DOM @@ -1338,28 +1339,6 @@ class MFElement extends DOMElement return $this->ownerDocument->GetNodeById($sXPath, $sId, $this); } - /** - * For debugging purposes - */ - public function Dump($bReturnRes = false) - { - $oMFDoc = new MFDocument(); - $oClone = $oMFDoc->importNode($this->cloneNode(true), true); - $oMFDoc->appendChild($oClone); - - $sXml = $oMFDoc->saveXML($oClone); - if ($bReturnRes) - { - return $sXml; - } - else - { - echo "
\n"; - echo htmlentities($sXml); - echo "\n"; - } - } - /** * Returns the node directly under the given node */ @@ -1381,52 +1360,6 @@ class MFElement extends DOMElement return $oNode; } - /** - * Returns the node directly under the current node, or null if missing - */ - public function GetOptionalElement($sTagName) - { - return $this->GetUniqueElement($sTagName, false); - } - - - /** - * Returns the TEXT of the current node (possibly from several subnodes) - */ - public function GetText($sDefault = null) - { - $sText = null; - foreach($this->childNodes as $oChildNode) - { - if ($oChildNode instanceof DOMText) - { - if (is_null($sText)) $sText = ''; - $sText .= $oChildNode->wholeText; - } - } - if (is_null($sText)) - { - return $sDefault; - } - else - { - return $sText; - } - } - - /** - * Get the TEXT value from the child node - */ - public function GetChildText($sTagName, $sDefault = null) - { - $sRet = $sDefault; - if ($oChild = $this->GetOptionalElement($sTagName)) - { - $sRet = $oChild->GetText($sDefault); - } - return $sRet; - } - /** * Assumes the current node to be either a text or *
\n"; - echo htmlentities($sXml); - echo "\n"; - } - } - /** * Find the child node matching the given node * A method with the same signature MUST exist in MFElement for the recursion to work fine @@ -2113,34 +2012,6 @@ class MFDocument extends DOMDocument return $oXPath->query($sXPath, $oContextNode); } } - - public static function XPathQuote($sValue) - { - if (strpos($sValue, '"') !== false) - { - $aParts = explode('"', $sValue); - $sRet = 'concat("'.implode('", \'"\', "', $aParts).'")'; - } - else - { - $sRet = '"'.$sValue.'"'; - } - return $sRet; - } - - /** - * An alternative to getNodePath, that gives the id of nodes instead of the position within the children - */ - public static function GetItopNodePath($oNode) - { - if ($oNode instanceof DOMDocument) return ''; - if (is_null($oNode)) return ''; - - $sId = $oNode->getAttribute('id'); - $sNodeDesc = ($sId != '') ? $oNode->nodeName.'['.$sId.']' : $oNode->nodeName; - return self::GetItopNodePath($oNode->parentNode).'/'.$sNodeDesc; - } - } /**