template.class.inc.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. require_once('../application/displayblock.class.inc.php');
  3. /**
  4. * This class manages the special template format used internally to build the iTop web pages
  5. */
  6. class DisplayTemplate
  7. {
  8. protected $m_sTemplate;
  9. protected $m_aTags;
  10. static protected $iBlockCount = 0;
  11. public function __construct($sTemplate)
  12. {
  13. $this->m_aTags = array('itopblock', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring');
  14. $this->m_sTemplate = $sTemplate;
  15. }
  16. public function Render(WebPage $oPage, $aParams = array())
  17. {
  18. $this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
  19. $iStart = 0;
  20. $iEnd = strlen($this->m_sTemplate);
  21. $iCount = 0;
  22. $iBeforeTagPos = $iStart;
  23. $iAfterTagPos = $iStart;
  24. while($sTag = $this->GetNextTag($iStart, $iEnd))
  25. {
  26. $sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
  27. $iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
  28. $sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
  29. $oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
  30. if ($sTag == DisplayBlock::TAG_BLOCK)
  31. {
  32. try
  33. {
  34. $oBlock = DisplayBlock::FromTemplate($sOuterTag);
  35. if (is_object($oBlock))
  36. {
  37. $oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
  38. }
  39. }
  40. catch(OQLException $e)
  41. {
  42. $oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
  43. }
  44. catch(Exception $e)
  45. {
  46. $oPage->p('Error in template (please contact your administrator)<!--'.$sOuterTag.'-->');
  47. }
  48. self::$iBlockCount++;
  49. }
  50. else
  51. {
  52. $aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
  53. //$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
  54. $this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
  55. }
  56. $iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
  57. $iBeforeTagPos = $iAfterTagPos;
  58. $iStart = $iEnd;
  59. $iEnd = strlen($this->m_sTemplate);
  60. $iCount++;
  61. if ($iCount > 10) break; //@@@ Why ?? Debug ??
  62. }
  63. $oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
  64. }
  65. public function GetNextTag(&$iStartPos, &$iEndPos)
  66. {
  67. $iChunkStartPos = $iStartPos;
  68. $sNextTag = null;
  69. $iStartPos = $iEndPos;
  70. foreach($this->m_aTags as $sTag)
  71. {
  72. // Search for the opening tag
  73. $iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
  74. if ($iOpeningPos === false)
  75. {
  76. $iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
  77. }
  78. if ($iOpeningPos !== false)
  79. {
  80. $iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
  81. }
  82. if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
  83. {
  84. if ($iOpeningPos < $iStartPos)
  85. {
  86. // This is the next tag
  87. $iStartPos = $iOpeningPos;
  88. $iEndPos = $iClosingPos;
  89. $sNextTag = $sTag;
  90. }
  91. }
  92. }
  93. return $sNextTag;
  94. }
  95. public function GetTagContent($sTag, $iStartPos, $iEndPos)
  96. {
  97. $sContent = "";
  98. $iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
  99. if ($iContentStart !== false)
  100. {
  101. $sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
  102. }
  103. return $sContent;
  104. }
  105. public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
  106. {
  107. $aAttr = array();
  108. $iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
  109. $iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
  110. if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
  111. {
  112. $sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
  113. $aAttributes = explode(' ', $sAttributes);
  114. foreach($aAttributes as $sAttr)
  115. {
  116. if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
  117. {
  118. $aAttr[strtolower($aMatches[1])] = $aMatches[2];
  119. }
  120. }
  121. }
  122. return $aAttr;
  123. }
  124. protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
  125. {
  126. static $iTabContainerCount = 0;
  127. switch($sTag)
  128. {
  129. case 'itoptabs':
  130. $oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
  131. $oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
  132. $iTabContainerCount++;
  133. //$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
  134. $oTemplate = new DisplayTemplate($sContent);
  135. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  136. $oPage->SetCurrentTabContainer('');
  137. break;
  138. case 'itoptab':
  139. $oPage->SetCurrentTab(str_replace('_', ' ', $aAttributes['name']));
  140. $oTemplate = new DisplayTemplate($sContent);
  141. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  142. //$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
  143. $oPage->SetCurrentTab('');
  144. break;
  145. case 'itoptoggle':
  146. $sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
  147. $bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
  148. $oPage->StartCollapsibleSection($sName, $bOpen);
  149. $oTemplate = new DisplayTemplate($sContent);
  150. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  151. //$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
  152. $oPage->EndCollapsibleSection();
  153. break;
  154. case 'itopstring':
  155. $oPage->add(Dict::S($sContent));
  156. break;
  157. case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
  158. $oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
  159. break;
  160. default:
  161. // Unknown tag, just ignore it or now -- output an HTML comment
  162. $oPage->add("<!-- unsupported tag: $sTag -->");
  163. }
  164. }
  165. /**
  166. * Unit test
  167. */
  168. static public function UnitTest()
  169. {
  170. require_once('../application/startup.inc.php');
  171. require_once("../application/itopwebpage.class.inc.php");
  172. $sTemplate = '<div class="page_header">
  173. <div class="actions_details"><a href="#"><span>Actions</span></a></div>
  174. <h1>$class$: <span class="hilite">$name$</span></h1>
  175. <itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
  176. </div>
  177. <img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
  178. <itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT bizNetworkDevice AS d WHERE d.id = $id$</itopblock>
  179. <itoptabs>
  180. <itoptab name="Interfaces">
  181. <itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT bizInterface AS i WHERE i.device_id = $id$</itopblock>
  182. </itoptab>
  183. <itoptab name="Contacts">
  184. <itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT bizContact AS c JOIN ContactsLinks AS l ON l.contact_id = c.id WHERE l.object_id = $id$</itopblock>
  185. </itoptab>
  186. <itoptab name="Documents">
  187. <itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT bizDocument AS d JOIN lnkDocumentRealObject as l ON l.document_id = d.id WHERE l.object_id = $id$)</itopblock>
  188. </itoptab>
  189. </itoptabs>';
  190. $oPage = new iTopWebPage('Unit Test', 3);
  191. //$oPage->add("Template content: <pre>".htmlentities($sTemplate)."</pre>\n");
  192. $oTemplate = new DisplayTemplate($sTemplate);
  193. $oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
  194. $oPage->output();
  195. }
  196. }
  197. //DisplayTemplate::UnitTest();
  198. ?>