itopdesignformat.class.inc.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. // Copyright (C) 2014 Combodo SARL
  3. //
  4. // This file is part of iTop.
  5. //
  6. // iTop is free software; you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // iTop is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with iTop. If not, see <http://www.gnu.org/licenses/>
  18. /**
  19. * Utility to upgrade the format of a given XML datamodel to the latest version
  20. * The datamodel is supplied as a loaded DOMDocument and modified in-place.
  21. *
  22. * Usage:
  23. *
  24. * $oDocument = new DOMDocument();
  25. * $oDocument->load($sXMLFile);
  26. * $aLog = array();
  27. * $oFormat = new iTopDesignFormat($oDocument);
  28. * if ($oFormat->Upgrade($aLog))
  29. * {
  30. * $oDocument->save($sXMLFile);
  31. * }
  32. * else
  33. * {
  34. * echo "Error, failed to upgrade the format, reason(s):\n".implode("\n", $aLog);
  35. * }
  36. */
  37. define('ITOP_DESIGN_LATEST_VERSION', '1.1');
  38. class iTopDesignFormat
  39. {
  40. /**
  41. * The Document to work on
  42. * @var DOMDocument
  43. */
  44. protected $oDocument;
  45. /**
  46. * Creation from a loaded DOMDocument
  47. * @param DOMDocument $oDocument The document to transform
  48. */
  49. public function __construct(DOMDocument $oDocument)
  50. {
  51. $this->oDocument = $oDocument;
  52. }
  53. /**
  54. * Make adjustements to the DOM to migrate it to the specified version (default is latest)
  55. * For now only the conversion from version 1.0 to 1.1 is supported.
  56. * @param Array $aLog Array (as a reference) to gather the log results (errors, etc)
  57. * @param string $sTargetVersion The desired version (or the latest possible version if not specified)
  58. */
  59. public function Upgrade(&$aLog, $sTargetVersion = ITOP_DESIGN_LATEST_VERSION)
  60. {
  61. $oXPath = new DOMXPath($this->oDocument);
  62. // Retrieve the version number
  63. $oNodeList = $oXPath->query('/itop_design');
  64. if ($oNodeList->length == 0)
  65. {
  66. // Hmm, not an iTop Data Model file...
  67. $aLog[] = "File format, no root <itop_design> tag found";
  68. return false;
  69. }
  70. else
  71. {
  72. $sVersion = $oNodeList->item(0)->getAttribute('version');
  73. switch($sVersion)
  74. {
  75. case '': // No version, assume 1.0 !!
  76. case '1.0':
  77. $bRet = $this->From10To11();
  78. if ($bRet)
  79. {
  80. // Update the version number
  81. $oNodeList->item(0)->setAttribute('version', '1.1');
  82. }
  83. return true;
  84. break;
  85. case '1.1':
  86. return true; // Nothing to do, the document is already at the most recent version
  87. break;
  88. default:
  89. $aLog[] = "Unknown format version: $sVersion";
  90. return false; // unknown versions are not supported
  91. }
  92. }
  93. }
  94. /**
  95. * Upgrade the format from version 1.0 to 1.1
  96. * @return boolean true on success, false otherwise
  97. */
  98. protected function From10To11()
  99. {
  100. // Adjust the XML to transparently add an id (=stimulus) on all life-cycle transitions
  101. // which don't already have one
  102. $oXPath = new DOMXPath($this->oDocument);
  103. $oNodeList = $oXPath->query('/itop_design/classes//class/lifecycle/states/state/transitions/transition/stimulus');
  104. foreach ($oNodeList as $oNode)
  105. {
  106. $oNode->parentNode->SetAttribute('id', $oNode->textContent);
  107. $this->DeleteNode($oNode);
  108. }
  109. // Adjust the XML to transparently add an id (=percent) on all thresholds of stopwatches
  110. // which don't already have one
  111. $oNodeList = $oXPath->query("/itop_design/classes//class/fields/field[@xsi:type='AttributeStopWatch']/thresholds/threshold/percent");
  112. foreach ($oNodeList as $oNode)
  113. {
  114. $oNode->parentNode->SetAttribute('id', $oNode->textContent);
  115. $this->DeleteNode($oNode);
  116. }
  117. // Adjust the XML to transparently add an id (=action:<type>) on all allowed actions (profiles)
  118. // which don't already have one
  119. $oNodeList = $oXPath->query('/itop_design/user_rights/profiles/profile/groups/group/actions/action');
  120. foreach ($oNodeList as $oNode)
  121. {
  122. if ($oNode->getAttribute('id') == '')
  123. {
  124. $oNode->SetAttribute('id', 'action:' . $oNode->getAttribute('xsi:type'));
  125. $oNode->removeAttribute('xsi:type');
  126. }
  127. elseif ($oNode->getAttribute('xsi:type') == 'stimulus')
  128. {
  129. $oNode->SetAttribute('id', 'stimulus:' . $oNode->getAttribute('id'));
  130. $oNode->removeAttribute('xsi:type');
  131. }
  132. }
  133. // Adjust the XML to transparently add an id (=value) on all values of an enum which don't already have one.
  134. // This enables altering an enum for just adding/removing one value, intead of redefining the whole list of values.
  135. $oNodeList = $oXPath->query("/itop_design/classes//class/fields/field[@xsi:type='AttributeEnum']/values/value");
  136. foreach ($oNodeList as $oNode)
  137. {
  138. if ($oNode->getAttribute('id') == '')
  139. {
  140. $oNode->SetAttribute('id', $oNode->textContent);
  141. }
  142. }
  143. return true;
  144. }
  145. /**
  146. * Delete a node from the DOM and make sure to also remove the immediately following line break (DOMText), if any.
  147. * This prevents generating empty lines in the middle of the XML
  148. * @param DOMNode $oNode
  149. */
  150. protected function DeleteNode($oNode)
  151. {
  152. if ( $oNode->nextSibling && ($oNode->nextSibling instanceof DOMText) && ($oNode->nextSibling->isWhitespaceInElementContent()) )
  153. {
  154. $oNode->parentNode->removeChild($oNode->nextSibling);
  155. }
  156. $oNode->parentNode->removeChild($oNode);
  157. }
  158. }