template.class.inc.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. public function __construct($sTemplate)
  11. {
  12. $this->m_aTags = array('itopblock', 'itoptabs', 'itoptab', 'itoptoggle');
  13. $this->m_sTemplate = $sTemplate;
  14. }
  15. public function Render(web_page $oPage, $aParams = array())
  16. {
  17. $this->ApplyParams($aParams);
  18. $iStart = 0;
  19. $iEnd = strlen($this->m_sTemplate);
  20. $iCount = 0;
  21. $iBeforeTagPos = $iStart;
  22. $iAfterTagPos = $iStart;
  23. while($sTag = $this->GetNextTag($iStart, $iEnd))
  24. {
  25. $sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
  26. $aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
  27. //$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
  28. $oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
  29. $this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
  30. $iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
  31. $iBeforeTagPos = $iAfterTagPos;
  32. $iStart = $iEnd;
  33. $iEnd = strlen($this->m_sTemplate);
  34. $iCount++;
  35. if ($iCount > 10) break;
  36. }
  37. $oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
  38. }
  39. /**
  40. * Replaces all the parameters by the values passed in the hash array
  41. */
  42. public function ApplyParams($aParams)
  43. {
  44. $aSearches = array();
  45. $aReplacements = array();
  46. foreach($aParams as $sSearch => $sReplace)
  47. {
  48. $aSearches[] = '$'.$sSearch.'$';
  49. $aReplacements[] = $sReplace;
  50. }
  51. $this->m_sTemplate = str_replace($aSearches, $aReplacements, $this->m_sTemplate);
  52. }
  53. public function GetNextTag(&$iStartPos, &$iEndPos)
  54. {
  55. $iChunkStartPos = $iStartPos;
  56. $sNextTag = null;
  57. $iStartPos = $iEndPos;
  58. foreach($this->m_aTags as $sTag)
  59. {
  60. // Search for the opening tag
  61. $iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
  62. if ($iOpeningPos === false)
  63. {
  64. $iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
  65. }
  66. if ($iOpeningPos !== false)
  67. {
  68. $iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
  69. }
  70. if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
  71. {
  72. if ($iOpeningPos < $iStartPos)
  73. {
  74. // This is the next tag
  75. $iStartPos = $iOpeningPos;
  76. $iEndPos = $iClosingPos;
  77. $sNextTag = $sTag;
  78. }
  79. }
  80. }
  81. return $sNextTag;
  82. }
  83. public function GetTagContent($sTag, $iStartPos, $iEndPos)
  84. {
  85. $sContent = "";
  86. $iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
  87. if ($iContentStart !== false)
  88. {
  89. $sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
  90. }
  91. return $sContent;
  92. }
  93. public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
  94. {
  95. $aAttr = array();
  96. $iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
  97. $iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
  98. if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
  99. {
  100. $sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
  101. $aAttributes = explode(' ', $sAttributes);
  102. foreach($aAttributes as $sAttr)
  103. {
  104. if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
  105. {
  106. $aAttr[strtolower($aMatches[1])] = $aMatches[2];
  107. }
  108. }
  109. }
  110. return $aAttr;
  111. }
  112. protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
  113. {
  114. static $iTabContainerCount = 0;
  115. static $iBlockCount = 0;
  116. switch($sTag)
  117. {
  118. case 'itoptabs':
  119. $oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
  120. $oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
  121. $iTabContainerCount++;
  122. //$oPage->p('Content:<pre>'.htmlentities($sContent).'</pre>');
  123. $oTemplate = new DisplayTemplate($sContent);
  124. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  125. $oPage->SetCurrentTabContainer('');
  126. break;
  127. case 'itoptab':
  128. $oPage->SetCurrentTab(str_replace('_', ' ', $aAttributes['name']));
  129. $oTemplate = new DisplayTemplate($sContent);
  130. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  131. //$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
  132. $oPage->SetCurrentTab('');
  133. break;
  134. case 'itoptoggle':
  135. $oPage->StartCollapsibleSection($aAttributes['name']);
  136. $oTemplate = new DisplayTemplate($sContent);
  137. $oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
  138. //$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent).'</pre>');
  139. $oPage->EndCollapsibleSection();
  140. break;
  141. case 'itopblock': // TO DO: Use DisplayBlock::FromTemplate here
  142. $sBlockClass = $aAttributes['blockclass'];
  143. $sBlockType = $aAttributes['type'];
  144. $aExtraParams = array();
  145. if (isset($aAttributes['link_attr']))
  146. {
  147. $aExtraParams['link_attr'] = $aAttributes['link_attr'];
  148. // Check that all mandatory parameters are present:
  149. if(empty($aAttributes['object_id']))
  150. {
  151. // if 'links' mode is requested the d of the object to link to must be specified
  152. throw new ApplicationException("Parameter object_id is mandatory when link_attr is specified. Check the definition of the display template.");
  153. }
  154. if(empty($aAttributes['target_attr']))
  155. {
  156. // if 'links' mode is requested the d of the object to link to must be specified
  157. throw new ApplicationException("Parameter target_attr is mandatory when link_attr is specified. Check the definition of the display template.");
  158. }
  159. $aExtraParams['object_id'] = $aAttributes['object_id'];
  160. $aExtraParams['target_attr'] = $aAttributes['target_attr'];
  161. }
  162. switch($aAttributes['encoding'])
  163. {
  164. case 'text/sibusql':
  165. $oFilter = CMDBSearchFilter::FromSibusQL($sContent);
  166. break;
  167. case 'text/oql':
  168. $oFilter = CMDBSearchFilter::FromOQL($sContent);
  169. break;
  170. case 'text/serialize':
  171. default:
  172. $oFilter = CMDBSearchFilter::unserialize($sContent);
  173. break;
  174. }
  175. $oBlock = new $sBlockClass($oFilter, $sBlockType, false, $aExtraParams);
  176. $oBlock->Display($oPage, 'block_'.$iBlockCount);
  177. $iBlockCount++;
  178. break;
  179. default:
  180. // Unknown tag, just ignore it or now -- output an HTML comment
  181. $oPage->add("<!-- unsupported tag: $sTag -->");
  182. }
  183. }
  184. /**
  185. * Unit test
  186. */
  187. static public function UnitTest()
  188. {
  189. require_once('../application/startup.inc.php');
  190. require_once("../application/itopwebpage.class.inc.php");
  191. $sTemplate = '<div class="page_header">
  192. <div class="actions_details"><a href="#"><span>Actions</span></a></div>
  193. <h1>$class$: <span class="hilite">$name$</span></h1>
  194. <itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $pkey$ AND objclass = \'$class$\'</itopblock>
  195. </div>
  196. <img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
  197. <itopblock blockclass="DisplayBlock" asynchronous="true" type="bare_details" encoding="text/sibusql">bizNetworkDevice: pkey = $pkey$</itopblock>
  198. <itoptabs>
  199. <itoptab name="Interfaces">
  200. <itopblock blockclass="DisplayBlock" type="list" encoding="text/sibusql">bizInterface: device_id = $pkey$</itopblock>
  201. </itoptab>
  202. <itoptab name="Contacts">
  203. <itopblock blockclass="DisplayBlock" type="list" encoding="text/sibusql">bizContact: PKEY IS contact_id IN (ContactsLinks: object_id = $pkey$)</itopblock>
  204. </itoptab>
  205. <itoptab name="Documents">
  206. <itopblock blockclass="DisplayBlock" type="list" encoding="text/sibusql">bizDocument: PKEY IS doc_id IN (lnkDocumentRealObject: object_id = $pkey$)</itopblock>
  207. </itoptab>
  208. </itoptabs>';
  209. $oPage = new iTopWebPage('Unit Test', 3);
  210. //$oPage->add("Template content: <pre>".htmlentities($sTemplate)."</pre>\n");
  211. $oTemplate = new DisplayTemplate($sTemplate);
  212. $oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
  213. $oPage->output();
  214. }
  215. }
  216. //DisplayTemplate::UnitTest();
  217. ?>