N°5341 - refactoring to have a dedicated ormcase log service

This commit is contained in:
odain
2023-04-06 17:24:32 +02:00
parent 8d711fb37b
commit 1b0dedaf31
4 changed files with 116 additions and 96 deletions

View File

@@ -3,7 +3,7 @@
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -19,36 +19,34 @@
define('CASELOG_VISIBLE_ITEMS', 2); define('CASELOG_VISIBLE_ITEMS', 2);
define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n"); define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n");
require_once('ormcaselogservice.inc.php');
/** /**
* Class to store a "case log" in a structured way, keeping track of its successive entries * Class to store a "case log" in a structured way, keeping track of its successive entries
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class ormCaseLog { class ormCaseLog {
const CASE_LOG_SEPARATOR_REGEX_FIND = "\r?\n?========== \w+-\d+-\d+ \d+:\d+:\d+ : .*\s\(\d+\) ============\r?\n\r?\n";
const CASE_LOG_SEPARATOR_REGEX_EXTRACT = "\r?\n?========== (?<date>\w+-\d+-\d+ \d+:\d+:\d+) : (?<user_name>.*)\s\((?<user_id>\d+)\) ============\r?\n\r?\n";
protected $m_sLog; protected $m_sLog;
protected $m_aIndex; protected $m_aIndex;
protected $m_bModified; protected $m_bModified;
protected \ormCaseLogService $oOrmCaseLogService;
/** /**
* Initializes the log with the first (initial) entry * Initializes the log with the first (initial) entry
* @param $sLog string The text of the whole case log * @param $sLog string The text of the whole case log
* @param $aIndex array The case log index * @param $aIndex array The case log index
*/ */
public function __construct($sLog = '', $aIndex = array()) public function __construct($sLog = '', $aIndex = [], \ormCaseLogService $oOrmCaseLogService=null)
{ {
$this->m_sLog = $sLog; $this->m_sLog = $sLog;
$this->m_aIndex = $this->RebuildIndex($sLog); $this->m_aIndex = $aIndex;
if (count($this->m_aIndex) === 0 && count($aIndex) !== 0) {
$this->m_aIndex = $aIndex;
}
$this->m_bModified = false; $this->m_bModified = false;
$this->oOrmCaseLogService = (is_null($oOrmCaseLogService)) ? new \ormCaseLogService() : $oOrmCaseLogService;
$this->RebuildIndex();
} }
public function GetText($bConvertToPlainText = false) public function GetText($bConvertToPlainText = false)
{ {
if ($bConvertToPlainText) if ($bConvertToPlainText)
@@ -61,7 +59,7 @@ class ormCaseLog {
return $this->m_sLog; return $this->m_sLog;
} }
} }
public static function FromJSON($oJson) public static function FromJSON($oJson)
{ {
if (!isset($oJson->items)) if (!isset($oJson->items))
@@ -77,8 +75,8 @@ class ormCaseLog {
} }
/** /**
* Return a value that will be further JSON encoded * Return a value that will be further JSON encoded
*/ */
public function GetForJSON() public function GetForJSON()
{ {
// Order by ascending date // Order by ascending date
@@ -188,9 +186,9 @@ class ormCaseLog {
$sSeparator = sprintf(CASELOG_SEPARATOR, $aData['date'], $aData['user_login'], $aData['user_id']); $sSeparator = sprintf(CASELOG_SEPARATOR, $aData['date'], $aData['user_login'], $aData['user_id']);
$sPlainText .= $sSeparator.$aData['message']; $sPlainText .= $sSeparator.$aData['message'];
} }
return $sPlainText; return $sPlainText;
} }
public function GetIndex() public function GetIndex()
{ {
return $this->m_aIndex; return $this->m_aIndex;
@@ -207,7 +205,7 @@ class ormCaseLog {
{ {
return ($this->m_sLog === null); return ($this->m_sLog === null);
} }
public function ClearModifiedFlag() public function ClearModifiedFlag()
{ {
$this->m_bModified = false; $this->m_bModified = false;
@@ -215,7 +213,7 @@ class ormCaseLog {
/** /**
* Produces an HTML representation, aimed at being used within an email * Produces an HTML representation, aimed at being used within an email
*/ */
public function GetAsEmailHtml() public function GetAsEmailHtml()
{ {
$sStyleCaseLogHeader = ''; $sStyleCaseLogHeader = '';
@@ -296,10 +294,10 @@ class ormCaseLog {
$sHtml .= '</td></tr></table>'; $sHtml .= '</td></tr></table>';
return $sHtml; return $sHtml;
} }
/** /**
* Produces an HTML representation, aimed at being used to produce a PDF with TCPDF (no table) * Produces an HTML representation, aimed at being used to produce a PDF with TCPDF (no table)
*/ */
public function GetAsSimpleHtml($aTransfoHandler = null) public function GetAsSimpleHtml($aTransfoHandler = null)
{ {
$sStyleCaseLogEntry = ''; $sStyleCaseLogEntry = '';
@@ -328,7 +326,7 @@ class ormCaseLog {
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry, true /* wiki "links" only */); $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry, true /* wiki "links" only */);
} }
$sTextEntry = InlineImage::FixUrls($sTextEntry); $sTextEntry = InlineImage::FixUrls($sTextEntry);
} }
$iPos += $aIndex[$index]['text_length']; $iPos += $aIndex[$index]['text_length'];
$sEntry = '<li>'; $sEntry = '<li>';
@@ -390,7 +388,7 @@ class ormCaseLog {
/** /**
* Produces an HTML representation, aimed at being used within the iTop framework * Produces an HTML representation, aimed at being used within the iTop framework
*/ */
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null) public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
{ {
$bPrintableVersion = (utils::ReadParam('printable', '0') == '1'); $bPrintableVersion = (utils::ReadParam('printable', '0') == '1');
@@ -510,11 +508,11 @@ class ormCaseLog {
$sHtml .= '</td></tr></table>'; $sHtml .= '</td></tr></table>';
return $sHtml; return $sHtml;
} }
/** /**
* Add a new entry to the log or merge the given text into the currently modified entry * Add a new entry to the log or merge the given text into the currently modified entry
* and updates the internal index * and updates the internal index
* @param $sText string The text of the new entry * @param $sText string The text of the new entry
*/ */
public function AddLogEntry($sText, $sOnBehalfOf = '') public function AddLogEntry($sText, $sOnBehalfOf = '')
{ {
@@ -546,23 +544,18 @@ class ormCaseLog {
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$aIndex = $this->RebuildIndex($this->m_sLog); // Rebuild failed
if (count($aIndex) === 0) { $iSepLength = strlen($sSeparator);
// Rebuild failed $iTextLength = strlen($sText);
$iSepLength = strlen($sSeparator); $this->m_aIndex[] = array(
$iTextLength = strlen($sText); 'user_name' => $sOnBehalfOf,
$this->m_aIndex[] = array( 'user_id' => $iUserId,
'user_name' => $sOnBehalfOf, 'date' => time(),
'user_id' => $iUserId, 'text_length' => $iTextLength,
'date' => time(), 'separator_length' => $iSepLength,
'text_length' => $iTextLength, 'format' => 'html',
'separator_length' => $iSepLength, );
'format' => 'html', $this->RebuildIndex();
);
} else {
$this->m_aIndex = $aIndex;
}
$this->m_bModified = true; $this->m_bModified = true;
} }
@@ -599,7 +592,7 @@ class ormCaseLog {
$iUserId = UserRights::GetUserId(); $iUserId = UserRights::GetUserId();
$sOnBehalfOf = UserRights::GetUserFriendlyName(); $sOnBehalfOf = UserRights::GetUserFriendlyName();
} }
if (isset($oJson->date)) if (isset($oJson->date))
{ {
$oDate = new DateTime($oJson->date); $oDate = new DateTime($oJson->date);
@@ -629,23 +622,18 @@ class ormCaseLog {
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId); $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$aIndex = $this->RebuildIndex($this->m_sLog); // Rebuild failed
if (count($aIndex) === 0) { $iSepLength = strlen($sSeparator);
// Rebuild failed $iTextLength = strlen($sText);
$iSepLength = strlen($sSeparator); $this->m_aIndex[] = array(
$iTextLength = strlen($sText); 'user_name' => $sOnBehalfOf,
$this->m_aIndex[] = array( 'user_id' => $iUserId,
'user_name' => $sOnBehalfOf, 'date' => time(),
'user_id' => $iUserId, 'text_length' => $iTextLength,
'date' => time(), 'separator_length' => $iSepLength,
'text_length' => $iTextLength, 'format' => 'html',
'separator_length' => $iSepLength, );
'format' => 'html', $this->RebuildIndex();
);
} else {
$this->m_aIndex = $aIndex;
}
$this->m_bModified = true; $this->m_bModified = true;
} }
@@ -682,7 +670,7 @@ class ormCaseLog {
$sRes = utils::HtmlToText($sRaw); $sRes = utils::HtmlToText($sRaw);
} }
break; break;
case 'html': case 'html':
if ($aLastEntry['format'] == 'text') if ($aLastEntry['format'] == 'text')
{ {
@@ -707,7 +695,7 @@ class ormCaseLog {
$iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference $iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
return $iLast; return $iLast;
} }
/** /**
* Get the text string corresponding to the given entry in the log (zero based index, older entries first) * Get the text string corresponding to the given entry in the log (zero based index, older entries first)
* @param integer $iIndex * @param integer $iIndex
@@ -728,39 +716,12 @@ class ormCaseLog {
return $sText; return $sText;
} }
public function RebuildIndex($sLog): array public function RebuildIndex(): void
{ {
$aTexts = preg_split('/'.self::CASE_LOG_SEPARATOR_REGEX_FIND.'/', $sLog, 0, PREG_SPLIT_NO_EMPTY); $aIndex = $this->oOrmCaseLogService->RebuildIndex($this->m_sLog, $this->m_aIndex);
preg_match_all('/'.self::CASE_LOG_SEPARATOR_REGEX_FIND.'/', $sLog, $aMatches); if (count($aIndex) !== 0) {
//index rebuild required
if (count($aTexts) != count($aMatches[0])) { $this->m_aIndex = $aIndex;
return [];
} }
$aIndex = [];
$iPrevDate = 0;
for ($index = count($aTexts) - 1; $index >= 0; $index--) {
$sSeparator = $aMatches[0][$index];
preg_match('/'.self::CASE_LOG_SEPARATOR_REGEX_EXTRACT.'/', $sSeparator, $aSeparatorParts);
try {
$iDate = (int)AttributeDateTime::GetAsUnixSeconds($aSeparatorParts['date']);
$iPrevDate = $iDate + 1;
}
catch (Exception $e) {
$iDate = $iPrevDate;
}
$aIndex[] = array(
'user_name' => $aSeparatorParts['user_name'],
'user_id' => $aSeparatorParts['user_id'],
'date' => $iDate,
'text_length' => strlen($aTexts[$index]),
'separator_length' => strlen($sSeparator),
'format' => 'html',
);
}
return $aIndex;
} }
} }

View File

@@ -0,0 +1,57 @@
<?php
/**
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ormCaseLogService
{
const CASE_LOG_SEPARATOR_REGEX_FIND = "\n?========== \w+-\d+-\d+ \d+:\d+:\d+ : .*\s\(\d+\) ============\n\n";
const CASE_LOG_SEPARATOR_REGEX_EXTRACT = "\n?========== (?<date>\w+-\d+-\d+ \d+:\d+:\d+) : (?<user_name>.*)\s\((?<user_id>\d+)\) ============\n\n";
public function __construct()
{
}
/**
* @param $sLog
*
* @return array
*/
public function RebuildIndex(string $sLog, array $aIndex)
{
$aTexts = preg_split('/'.self::CASE_LOG_SEPARATOR_REGEX_FIND.'/', $sLog, 0, PREG_SPLIT_NO_EMPTY);
preg_match_all('/'.self::CASE_LOG_SEPARATOR_REGEX_FIND.'/', $sLog, $aMatches);
if (count($aTexts) != count($aMatches[0])) {
return [];
}
$aRebuiltIndex = [];
$iPrevDate = 0;
for ($index = count($aTexts) - 1; $index >= 0; $index--) {
$sSeparator = $aMatches[0][$index];
preg_match('/'.self::CASE_LOG_SEPARATOR_REGEX_EXTRACT.'/', $sSeparator, $aSeparatorParts);
try {
$iDate = (int)AttributeDateTime::GetAsUnixSeconds($aSeparatorParts['date']);
$iPrevDate = $iDate + 1;
}
catch (Exception $e) {
$iDate = $iPrevDate;
}
$user_id = $aSeparatorParts['user_id'];
$aRebuiltIndex[] = array(
'user_name' => $aSeparatorParts['user_name'],
'user_id' => $user_id ==='0' ? null : $user_id,
'date' => $iDate,
'text_length' => strlen($aTexts[$index]),
'separator_length' => strlen($sSeparator),
'format' => 'html',
);
}
return $aRebuiltIndex;
}
}

View File

@@ -2740,6 +2740,7 @@ return array(
'iWorkingTimeComputer' => $baseDir . '/core/computing.inc.php', 'iWorkingTimeComputer' => $baseDir . '/core/computing.inc.php',
'lnkTriggerAction' => $baseDir . '/core/trigger.class.inc.php', 'lnkTriggerAction' => $baseDir . '/core/trigger.class.inc.php',
'ormCaseLog' => $baseDir . '/core/ormcaselog.class.inc.php', 'ormCaseLog' => $baseDir . '/core/ormcaselog.class.inc.php',
'ormCaseLogService' => $baseDir . '/core/ormcaselogservice.class.inc.php',
'ormCustomFieldsValue' => $baseDir . '/core/ormcustomfieldsvalue.class.inc.php', 'ormCustomFieldsValue' => $baseDir . '/core/ormcustomfieldsvalue.class.inc.php',
'ormDocument' => $baseDir . '/core/ormdocument.class.inc.php', 'ormDocument' => $baseDir . '/core/ormdocument.class.inc.php',
'ormLinkSet' => $baseDir . '/core/ormlinkset.class.inc.php', 'ormLinkSet' => $baseDir . '/core/ormlinkset.class.inc.php',

View File

@@ -3108,6 +3108,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'iWorkingTimeComputer' => __DIR__ . '/../..' . '/core/computing.inc.php', 'iWorkingTimeComputer' => __DIR__ . '/../..' . '/core/computing.inc.php',
'lnkTriggerAction' => __DIR__ . '/../..' . '/core/trigger.class.inc.php', 'lnkTriggerAction' => __DIR__ . '/../..' . '/core/trigger.class.inc.php',
'ormCaseLog' => __DIR__ . '/../..' . '/core/ormcaselog.class.inc.php', 'ormCaseLog' => __DIR__ . '/../..' . '/core/ormcaselog.class.inc.php',
'ormCaseLogService' => __DIR__ . '/../..' . '/core/ormcaselogservice.class.inc.php',
'ormCustomFieldsValue' => __DIR__ . '/../..' . '/core/ormcustomfieldsvalue.class.inc.php', 'ormCustomFieldsValue' => __DIR__ . '/../..' . '/core/ormcustomfieldsvalue.class.inc.php',
'ormDocument' => __DIR__ . '/../..' . '/core/ormdocument.class.inc.php', 'ormDocument' => __DIR__ . '/../..' . '/core/ormdocument.class.inc.php',
'ormLinkSet' => __DIR__ . '/../..' . '/core/ormlinkset.class.inc.php', 'ormLinkSet' => __DIR__ . '/../..' . '/core/ormlinkset.class.inc.php',