Bladeren bron

Code refactoring: eliminated duplicate code between MFDocument and ModuleDesign

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3860 a333f486-631f-4898-b8df-5754b55c2be0
romainq 9 jaren geleden
bovenliggende
commit
00eca0fb97
3 gewijzigde bestanden met toevoegingen van 281 en 365 verwijderingen
  1. 265 0
      core/designdocument.class.inc.php
  2. 5 225
      core/moduledesign.class.inc.php
  3. 11 140
      setup/modelfactory.class.inc.php

+ 265 - 0
core/designdocument.class.inc.php

@@ -0,0 +1,265 @@
+<?php
+// Copyright (C) 2016 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 <http://www.gnu.org/licenses/>
+
+/**
+ * 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 "<pre>\n";
+			echo htmlentities($sXml);
+			echo "</pre>\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 "<pre>\n";
+			echo htmlentities($sXml);
+			echo "</pre>\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;
+	}
+}

+ 5 - 225
core/moduledesign.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2015 Combodo SARL
+// Copyright (C) 2015-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -24,6 +24,7 @@
  */
 
 require_once(APPROOT.'application/utils.inc.php');
+require_once(APPROOT.'core/designdocument.class.inc.php');
 
 
 /**
@@ -54,7 +55,7 @@ require_once(APPROOT.'application/utils.inc.php');
  *   ...
  * }
  */
-class ModuleDesign extends DOMDocument
+class ModuleDesign extends \Combodo\iTop\DesignDocument
 {
 	/**
 	 * @param string|null $sDesignSourceId Identifier of the section module_design (generally a module name), null to build an empty design
@@ -62,8 +63,7 @@ class ModuleDesign extends DOMDocument
 	 */
 	public function __construct($sDesignSourceId = null)
 	{
-		parent::__construct('1.0', 'UTF-8');
-		$this->Init();
+		parent::__construct();
 
 		if (!is_null($sDesignSourceId))
 		{
@@ -72,19 +72,8 @@ 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 "<pre>\n";
-			echo htmlentities($sXml);
-			echo "</pre>\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 "<pre>\n";
-			echo htmlentities($sXml);
-			echo "</pre>\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;
-	}
 }

+ 11 - 140
setup/modelfactory.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2013 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -19,13 +19,14 @@
 /**
  * ModelFactory: in-memory manipulation of the XML MetaModel
  *
- * @copyright   Copyright (C) 2010-2012 Combodo SARL
+ * @copyright   Copyright (C) 2010-2016 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.'core/designdocument.class.inc.php');
 
  /**
  * ModelFactoryModule: the representation of a Module (i.e. element that can be selected during the setup)
@@ -316,7 +317,7 @@ class ModelFactory
 				{
 					echo "Dumping target doc - looking for '$sParentId'<br/>\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
@@ -1339,28 +1340,6 @@ class MFElement extends DOMElement
 	}
 
 	/**
-	 * 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 "<pre>\n";
-			echo htmlentities($sXml);
-			echo "</pre>\n";	 	
-		}
-	}
-
-	/**
 	 * Returns the node directly under the given node 
 	 */ 
 	public function GetUniqueElement($sTagName, $bMustExist = true)
@@ -1382,52 +1361,6 @@ class MFElement extends DOMElement
 	}
 	
 	/**
-	 * 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
 	 * <items>
 	 *   <item [key]="..."]>value<item>
@@ -1979,38 +1912,22 @@ class MFElement extends DOMElement
  */
 if (!class_exists('DOMDocument'))
 {
-class DOMDocument {function __construct(){throw new Exception('The dom extension is not enabled');}}
+	class DOMDocument {function __construct(){throw new Exception('The dom extension is not enabled');}}
 }
 
 /**
  * MFDocument - formating rules for XML input/output
  * @package ModelFactory
  */
-class MFDocument extends DOMDocument
+class MFDocument extends \Combodo\iTop\DesignDocument
 {
-	public function __construct()
-	{
-		parent::__construct('1.0', 'UTF-8');
-		$this->registerNodeClass('DOMElement', 'MFElement');
-
-		$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	
+	 * Overloadable. Called prior to data loading.
 	 */
-	public function load($filename, $options = 0)
+	protected function Init()
 	{
-		parent::load($filename, LIBXML_NOBLANKS);
-	}
-
-	/**
-	 * Overload of the standard API	
-	 */
-	public function loadXML($source, $options = 0)
-	{
-		parent::loadXML($source, LIBXML_NOBLANKS);
+		parent::Init();
+		$this->registerNodeClass('DOMElement', 'MFElement');
 	}
 
 	/**
@@ -2046,24 +1963,6 @@ class MFDocument extends DOMDocument
 	}
 
 	/**
-	 * For debugging purposes
-	 */
-	public function Dump($bReturnRes = false)
-	{
-		$sXml = $this->saveXML();
-		if ($bReturnRes)
-		{
-			return $sXml;
-		}
-		else
-		{
-			echo "<pre>\n";
-			echo htmlentities($sXml);
-			echo "</pre>\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
 	 * @param MFElement $oRefNode The node to search for
@@ -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;
-	}	 	
-
 }
 
 /**