ormcaselog.class.inc.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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. /**
  46. * Return a value that will be further JSON encoded
  47. */
  48. public function GetForJSON()
  49. {
  50. $aEntries = array();
  51. $iPos = 0;
  52. for($index=count($this->m_aIndex)-1 ; $index >= 0 ; $index--)
  53. {
  54. $iPos += $this->m_aIndex[$index]['separator_length'];
  55. $sTextEntry = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
  56. $iPos += $this->m_aIndex[$index]['text_length'];
  57. // Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
  58. // therefore we have changed the format. To preserve the compatibility with existing
  59. // installations of iTop, both format are allowed:
  60. // the 'date' item is either a DateTime object, or a unix timestamp
  61. if (is_int($this->m_aIndex[$index]['date']))
  62. {
  63. // Unix timestamp
  64. $sDate = date(Dict::S('UI:CaseLog:DateFormat'),$this->m_aIndex[$index]['date']);
  65. }
  66. elseif (is_object($this->m_aIndex[$index]['date']))
  67. {
  68. if (version_compare(phpversion(), '5.3.0', '>='))
  69. {
  70. // DateTime
  71. $sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
  72. }
  73. else
  74. {
  75. // No Warning... but the date is unknown
  76. $sDate = '';
  77. }
  78. }
  79. $aEntries[] = array(
  80. 'date' => $sDate,
  81. 'user_login' => $this->m_aIndex[$index]['user_name'],
  82. 'message' => $sTextEntry
  83. );
  84. }
  85. // Process the case of an eventual remainder (quick migration of AttributeText fields)
  86. if ($iPos < (strlen($this->m_sLog) - 1))
  87. {
  88. $sTextEntry = substr($this->m_sLog, $iPos);
  89. $aEntries[] = array(
  90. 'date' => '',
  91. 'user_login' => '',
  92. 'message' => $sTextEntry
  93. );
  94. }
  95. // Order by ascending date
  96. $aRet = array('entries' => array_reverse($aEntries));
  97. return $aRet;
  98. }
  99. public function GetIndex()
  100. {
  101. return $this->m_aIndex;
  102. }
  103. public function __toString()
  104. {
  105. return $this->m_sLog;
  106. }
  107. public function ClearModifiedFlag()
  108. {
  109. $this->m_bModified = false;
  110. }
  111. public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
  112. {
  113. $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
  114. $iPos = 0;
  115. $aIndex = $this->m_aIndex;
  116. if (($bEditMode) && (count($aIndex) > 0) && $this->m_bModified)
  117. {
  118. // Don't display the first element, that is still considered as editable
  119. $iPos = $aIndex[0]['separator_length'] + $aIndex[0]['text_length'];
  120. array_shift($aIndex);
  121. }
  122. for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
  123. {
  124. if ($index < count($aIndex) - CASELOG_VISIBLE_ITEMS)
  125. {
  126. $sOpen = '';
  127. $sDisplay = 'style="display:none;"';
  128. }
  129. else
  130. {
  131. $sOpen = ' open';
  132. $sDisplay = '';
  133. }
  134. $iPos += $aIndex[$index]['separator_length'];
  135. $sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
  136. $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
  137. if (!is_null($aTransfoHandler))
  138. {
  139. $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
  140. }
  141. $iPos += $aIndex[$index]['text_length'];
  142. $sEntry = '<div class="caselog_header'.$sOpen.'">';
  143. // Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
  144. // therefore we have changed the format. To preserve the compatibility with existing
  145. // installations of iTop, both format are allowed:
  146. // the 'date' item is either a DateTime object, or a unix timestamp
  147. if (is_int($aIndex[$index]['date']))
  148. {
  149. // Unix timestamp
  150. $sDate = date(Dict::S('UI:CaseLog:DateFormat'),$aIndex[$index]['date']);
  151. }
  152. elseif (is_object($aIndex[$index]['date']))
  153. {
  154. if (version_compare(phpversion(), '5.3.0', '>='))
  155. {
  156. // DateTime
  157. $sDate = $aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
  158. }
  159. else
  160. {
  161. // No Warning... but the date is unknown
  162. $sDate = '';
  163. }
  164. }
  165. $sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $aIndex[$index]['user_name']);
  166. $sEntry .= '</div>';
  167. $sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
  168. $sEntry .= $sTextEntry;
  169. $sEntry .= '</div>';
  170. $sHtml = $sHtml.$sEntry;
  171. }
  172. // Process the case of an eventual remainder (quick migration of AttributeText fields)
  173. if ($iPos < (strlen($this->m_sLog) - 1))
  174. {
  175. $sTextEntry = substr($this->m_sLog, $iPos);
  176. $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
  177. if (!is_null($aTransfoHandler))
  178. {
  179. $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
  180. }
  181. if (count($this->m_aIndex) == 0)
  182. {
  183. $sHtml .= '<div class="caselog_entry open">';
  184. $sHtml .= $sTextEntry;
  185. $sHtml .= '</div>';
  186. }
  187. else
  188. {
  189. if (count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS > 0)
  190. {
  191. $sOpen = '';
  192. $sDisplay = 'style="display:none;"';
  193. }
  194. else
  195. {
  196. $sOpen = ' open';
  197. $sDisplay = '';
  198. }
  199. $sHtml .= '<div class="caselog_header'.$sOpen.'">';
  200. $sHtml .= Dict::S('UI:CaseLog:InitialValue');
  201. $sHtml .= '</div>';
  202. $sHtml .= '<div class="caselog_entry"'.$sDisplay.'>';
  203. $sHtml .= $sTextEntry;
  204. $sHtml .= '</div>';
  205. }
  206. }
  207. $sHtml .= '</td></tr></table>';
  208. return $sHtml;
  209. }
  210. /**
  211. * Add a new entry to the log or merge the given text into the currently modified entry
  212. * and updates the internal index
  213. * @param $sText string The text of the new entry
  214. */
  215. public function AddLogEntry($sText, $sOnBehalfOf = '')
  216. {
  217. $bMergeEntries = false;
  218. $sDate = date(Dict::S('UI:CaseLog:DateFormat'));
  219. if ($sOnBehalfOf == '')
  220. {
  221. $sOnBehalfOf = UserRights::GetUserFriendlyName();
  222. $iUserId = UserRights::GetUserId();
  223. }
  224. else
  225. {
  226. $iUserId = null;
  227. }
  228. if ($this->m_bModified)
  229. {
  230. $aLatestEntry = end($this->m_aIndex);
  231. if ($aLatestEntry['user_name'] != $sOnBehalfOf)
  232. {
  233. $bMergeEntries = false;
  234. }
  235. else
  236. {
  237. $bMergeEntries = true;
  238. }
  239. }
  240. if ($bMergeEntries)
  241. {
  242. $aLatestEntry = end($this->m_aIndex);
  243. $this->m_sLog = substr($this->m_sLog, $aLatestEntry['separator_length']);
  244. $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
  245. $iSepLength = strlen($sSeparator);
  246. $iTextlength = strlen($sText."\n");
  247. $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
  248. $this->m_aIndex[] = array(
  249. 'user_name' => $sOnBehalfOf,
  250. 'user_id' => $iUserId,
  251. 'date' => time(),
  252. 'text_length' => $aLatestEntry['text_length'] + $iTextlength,
  253. 'separator_length' => $iSepLength,
  254. );
  255. }
  256. else
  257. {
  258. $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
  259. $iSepLength = strlen($sSeparator);
  260. $iTextlength = strlen($sText);
  261. $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
  262. $this->m_aIndex[] = array(
  263. 'user_name' => $sOnBehalfOf,
  264. 'user_id' => $iUserId,
  265. 'date' => time(),
  266. 'text_length' => $iTextlength,
  267. 'separator_length' => $iSepLength,
  268. );
  269. }
  270. $this->m_bModified = true;
  271. }
  272. public function GetModifiedEntry()
  273. {
  274. $sModifiedEntry = '';
  275. if ($this->m_bModified)
  276. {
  277. $sModifiedEntry = $this->GetLatestEntry();
  278. }
  279. return $sModifiedEntry;
  280. }
  281. /**
  282. * Get the latest entry from the log
  283. * @return string
  284. */
  285. public function GetLatestEntry()
  286. {
  287. $aLastEntry = end($this->m_aIndex);
  288. $sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
  289. return $sRes;
  290. }
  291. /**
  292. * Get the index of the latest entry from the log
  293. * @return integer
  294. */
  295. public function GetLatestEntryIndex()
  296. {
  297. $aKeys = array_keys($this->m_aIndex);
  298. $iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
  299. return $iLast;
  300. }
  301. }
  302. ?>