ormcaselog.class.inc.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. // Copyright (C) 2010-2012 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. define('CASELOG_VISIBLE_ITEMS', 2);
  19. define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n");
  20. /**
  21. * Class to store a "case log" in a structured way, keeping track of its successive entries
  22. *
  23. * @copyright Copyright (C) 2010-2012 Combodo SARL
  24. * @license http://opensource.org/licenses/AGPL-3.0
  25. */
  26. class ormCaseLog {
  27. protected $m_sLog;
  28. protected $m_aIndex;
  29. protected $m_bModified;
  30. /**
  31. * Initializes the log with the first (initial) entry
  32. * @param $sLog string The text of the whole case log
  33. * @param $aIndex hash The case log index
  34. */
  35. public function __construct($sLog = '', $aIndex = array())
  36. {
  37. $this->m_sLog = $sLog;
  38. $this->m_aIndex = $aIndex;
  39. $this->m_bModified = false;
  40. }
  41. public function GetText()
  42. {
  43. return $this->m_sLog;
  44. }
  45. public function GetIndex()
  46. {
  47. return $this->m_aIndex;
  48. }
  49. public function __toString()
  50. {
  51. return $this->m_sLog;
  52. }
  53. public function ClearModifiedFlag()
  54. {
  55. $this->m_bModified = false;
  56. }
  57. public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
  58. {
  59. $sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content
  60. $iPos = 0;
  61. $aIndex = $this->m_aIndex;
  62. if (($bEditMode) && (count($aIndex) > 0) && $this->m_bModified)
  63. {
  64. // Don't display the first element, that is still considered as editable
  65. $iPos = $aIndex[0]['separator_length'] + $aIndex[0]['text_length'];
  66. array_shift($aIndex);
  67. }
  68. for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
  69. {
  70. if ($index < count($aIndex) - CASELOG_VISIBLE_ITEMS)
  71. {
  72. $sOpen = '';
  73. $sDisplay = 'style="display:none;"';
  74. }
  75. else
  76. {
  77. $sOpen = ' open';
  78. $sDisplay = '';
  79. }
  80. $iPos += $aIndex[$index]['separator_length'];
  81. $sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
  82. $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
  83. if (!is_null($aTransfoHandler))
  84. {
  85. $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
  86. }
  87. $iPos += $aIndex[$index]['text_length'];
  88. $sEntry = '<div class="caselog_header'.$sOpen.'">';
  89. // Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
  90. // therefore we have changed the format. To preserve the compatibility with existing
  91. // installations of iTop, both format are allowed:
  92. // the 'date' item is either a DateTime object, or a unix timestamp
  93. if (is_int($aIndex[$index]['date']))
  94. {
  95. // Unix timestamp
  96. $sDate = date(Dict::S('UI:CaseLog:DateFormat'),$aIndex[$index]['date']);
  97. }
  98. elseif (is_object($aIndex[$index]['date']))
  99. {
  100. if (version_compare(phpversion(), '5.3.0', '>='))
  101. {
  102. // DateTime
  103. $sDate = $aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
  104. }
  105. else
  106. {
  107. // No Warning... but the date is unknown
  108. $sDate = '';
  109. }
  110. }
  111. $sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $aIndex[$index]['user_name']);
  112. $sEntry .= '</div>';
  113. $sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
  114. $sEntry .= $sTextEntry;
  115. $sEntry .= '</div>';
  116. $sHtml = $sHtml.$sEntry;
  117. }
  118. // Process the case of an eventual remainder (quick migration of AttributeText fields)
  119. if ($iPos < (strlen($this->m_sLog) - 1))
  120. {
  121. $sTextEntry = substr($this->m_sLog, $iPos);
  122. $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
  123. if (!is_null($aTransfoHandler))
  124. {
  125. $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
  126. }
  127. if (count($this->m_aIndex) == 0)
  128. {
  129. $sHtml .= '<div class="caselog_entry open">';
  130. $sHtml .= $sTextEntry;
  131. $sHtml .= '</div>';
  132. }
  133. else
  134. {
  135. if (count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS > 0)
  136. {
  137. $sOpen = '';
  138. $sDisplay = 'style="display:none;"';
  139. }
  140. else
  141. {
  142. $sOpen = ' open';
  143. $sDisplay = '';
  144. }
  145. $sHtml .= '<div class="caselog_header'.$sOpen.'">';
  146. $sHtml .= Dict::S('UI:CaseLog:InitialValue');
  147. $sHtml .= '</div>';
  148. $sHtml .= '<div class="caselog_entry"'.$sDisplay.'>';
  149. $sHtml .= $sTextEntry;
  150. $sHtml .= '</div>';
  151. }
  152. }
  153. $sHtml .= '</td></tr></table>';
  154. return $sHtml;
  155. }
  156. /**
  157. * Add a new entry to the log or merge the given text into the currently modified entry
  158. * and updates the internal index
  159. * @param $sText string The text of the new entry
  160. */
  161. public function AddLogEntry($sText, $sOnBehalfOf = '')
  162. {
  163. $bMergeEntries = false;
  164. $sDate = date(Dict::S('UI:CaseLog:DateFormat'));
  165. if ($sOnBehalfOf == '')
  166. {
  167. $sOnBehalfOf = UserRights::GetUserFriendlyName();
  168. $iUserId = UserRights::GetUserId();
  169. }
  170. else
  171. {
  172. $iUserId = null;
  173. }
  174. if ($this->m_bModified)
  175. {
  176. $aLatestEntry = end($this->m_aIndex);
  177. if ($aLatestEntry['user_name'] != $sOnBehalfOf)
  178. {
  179. $bMergeEntries = false;
  180. }
  181. else
  182. {
  183. $bMergeEntries = true;
  184. }
  185. }
  186. if ($bMergeEntries)
  187. {
  188. $aLatestEntry = end($this->m_aIndex);
  189. $this->m_sLog = substr($this->m_sLog, $aLatestEntry['separator_length']);
  190. $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
  191. $iSepLength = strlen($sSeparator);
  192. $iTextlength = strlen($sText."\n");
  193. $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
  194. $this->m_aIndex[] = array(
  195. 'user_name' => $sOnBehalfOf,
  196. 'user_id' => $iUserId,
  197. 'date' => time(),
  198. 'text_length' => $aLatestEntry['text_length'] + $iTextlength,
  199. 'separator_length' => $iSepLength,
  200. );
  201. }
  202. else
  203. {
  204. $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
  205. $iSepLength = strlen($sSeparator);
  206. $iTextlength = strlen($sText);
  207. $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
  208. $this->m_aIndex[] = array(
  209. 'user_name' => $sOnBehalfOf,
  210. 'user_id' => $iUserId,
  211. 'date' => time(),
  212. 'text_length' => $iTextlength,
  213. 'separator_length' => $iSepLength,
  214. );
  215. }
  216. $this->m_bModified = true;
  217. }
  218. public function GetModifiedEntry()
  219. {
  220. $sModifiedEntry = '';
  221. if ($this->m_bModified)
  222. {
  223. $sModifiedEntry = $this->GetLatestEntry();
  224. }
  225. return $sModifiedEntry;
  226. }
  227. /**
  228. * Get the latest entry from the log
  229. * @return string
  230. */
  231. public function GetLatestEntry()
  232. {
  233. $aLastEntry = end($this->m_aIndex);
  234. $sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
  235. return $sRes;
  236. }
  237. /**
  238. * Get the index of the latest entry from the log
  239. * @return integer
  240. */
  241. public function GetLatestEntryIndex()
  242. {
  243. $aKeys = array_keys($this->m_aIndex);
  244. $iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
  245. return $iLast;
  246. }
  247. }
  248. ?>