mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-09 19:14:19 +01:00
N°2875 - Extract method to find mentioned objects into utils so it can used by extensions, not only the trigger
This commit is contained in:
@@ -90,12 +90,31 @@ class utils
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_VARIABLE_NAME = 'variable_name';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @used-by static::GetMentionedObjectsFromText
|
||||
*/
|
||||
public const ENUM_TEXT_FORMAT_PLAIN = 'text';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @used-by static::GetMentionedObjectsFromText
|
||||
*/
|
||||
public const ENUM_TEXT_FORMAT_HTML = 'html';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
* @used-by static::GetMentionedObjectsFromText
|
||||
*/
|
||||
public const ENUM_TEXT_FORMAT_MARKDOWN = 'markdown';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.0
|
||||
@@ -2867,4 +2886,56 @@ HTML;
|
||||
|
||||
return $sAcronym;
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// Text manipulation
|
||||
//----------------------------------------------
|
||||
|
||||
/**
|
||||
* @param string $sText Text containing the mentioned objects to be found
|
||||
* @param string $sFormat {@uses static::ENUM_TEXT_FORMAT_HTML, ...}
|
||||
*
|
||||
* @return array Array of object classes / IDs for the ones found in $sText
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMentionedObjectsFromText(string $sText, string $sFormat = self::ENUM_TEXT_FORMAT_HTML): array
|
||||
{
|
||||
// First transform text so it can be parsed
|
||||
switch ($sFormat) {
|
||||
case static::ENUM_TEXT_FORMAT_HTML:
|
||||
$sText = static::HtmlToText($sText);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Don't transform it
|
||||
break;
|
||||
}
|
||||
|
||||
// Then parse text to find objects
|
||||
$aMentionedObjects = array();
|
||||
$aMentionMatches = array();
|
||||
|
||||
// Note: As the sanitizer (or CKEditor autocomplete plugin? 🤔) removes data-* attributes from the hyperlink, we can't use the following (simpler) regexp: '/<a\s*([^>]*)data-object-class="([^"]*)"\s*data-object-id="([^"]*)">/i'
|
||||
// If we change the sanitizer, we might want to use this regexp as it's easier to read
|
||||
// Note 2: This is only working for backoffice URLs...
|
||||
$sAppRootUrlForRegExp = addcslashes(utils::GetAbsoluteUrlAppRoot(), '/&');
|
||||
preg_match_all("/\[([^\]]*)\]\({$sAppRootUrlForRegExp}[^\)]*\&class=([^\)\&]*)\&id=([\d]*)[^\)]*\)/i", $sText, $aMentionMatches);
|
||||
|
||||
foreach ($aMentionMatches[0] as $iMatchIdx => $sCompleteMatch) {
|
||||
$sMatchedClass = $aMentionMatches[2][$iMatchIdx];
|
||||
$sMatchedId = $aMentionMatches[3][$iMatchIdx];
|
||||
|
||||
// Prepare array for matched class if not already present
|
||||
if (!array_key_exists($sMatchedClass, $aMentionedObjects)) {
|
||||
$aMentionedObjects[$sMatchedClass] = array();
|
||||
}
|
||||
// Add matched ID if not already there
|
||||
if (!in_array($sMatchedId, $aMentionedObjects[$sMatchedClass])) {
|
||||
$aMentionedObjects[$sMatchedClass][] = $sMatchedId;
|
||||
}
|
||||
}
|
||||
|
||||
return $aMentionedObjects;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3136,39 +3136,15 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
// 2 - Find mentioned objects
|
||||
$aMentionedObjects = array();
|
||||
foreach($aUpdatedLogAttCodes as $sAttCode)
|
||||
{
|
||||
foreach ($aUpdatedLogAttCodes as $sAttCode) {
|
||||
/** @var \ormCaseLog $oUpdatedCaseLog */
|
||||
$oUpdatedCaseLog = $this->Get($sAttCode);
|
||||
$aMentionMatches = array();
|
||||
// Note: As the sanitizer (or CKEditor autocomplete plugin? 🤔) removes data-* attributes from the hyperlink, we can't use the following (simpler) regexp: '/<a\s*([^>]*)data-object-class="([^"]*)"\s*data-object-id="([^"]*)">/i'
|
||||
// If we change the sanitizer, we might want to use this regexp as it's easier to read
|
||||
// Note 2: This is only working for backoffice URLs...
|
||||
$sAppRootUrlForRegExp = addcslashes(utils::GetAbsoluteUrlAppRoot(), '/&');
|
||||
preg_match_all("/\[([^\]]*)\]\({$sAppRootUrlForRegExp}[^\)]*\&class=([^\)\&]*)\&id=([\d]*)[^\)]*\)/i", $oUpdatedCaseLog->GetModifiedEntry(), $aMentionMatches);
|
||||
|
||||
foreach($aMentionMatches[0] as $iMatchIdx => $sCompleteMatch)
|
||||
{
|
||||
$sMatchedClass = $aMentionMatches[2][$iMatchIdx];
|
||||
$sMatchedId = $aMentionMatches[3][$iMatchIdx];
|
||||
|
||||
// Prepare array for matched class if not already present
|
||||
if(!array_key_exists($sMatchedClass, $aMentionedObjects))
|
||||
{
|
||||
$aMentionedObjects[$sMatchedClass] = array();
|
||||
}
|
||||
// Add matched ID if not already there
|
||||
if(!in_array($sMatchedId, $aMentionedObjects[$sMatchedClass]))
|
||||
{
|
||||
$aMentionedObjects[$sMatchedClass][] = $sMatchedId;
|
||||
}
|
||||
}
|
||||
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
|
||||
}
|
||||
// 3 - Trigger for those objects
|
||||
foreach($aMentionedObjects as $sMentionedClass => $aMentionedIds)
|
||||
{
|
||||
foreach($aMentionedIds as $sMentionedId)
|
||||
{
|
||||
// TODO: This should be refactored and moved into the caselogs loop, otherwise, we won't be able to know which case log triggered the action.
|
||||
foreach ($aMentionedObjects as $sMentionedClass => $aMentionedIds) {
|
||||
foreach ($aMentionedIds as $sMentionedId) {
|
||||
/** @var \DBObject $oMentionedObject */
|
||||
$oMentionedObject = MetaModel::GetObject($sMentionedClass, $sMentionedId);
|
||||
// Important: Here the "$this->object()$" placeholder is actually the mentioned object and not the current object. The current object can be used through the $source->object()$ placeholder.
|
||||
|
||||
@@ -440,6 +440,9 @@ class UtilsTest extends \Combodo\iTop\Test\UnitTest\ItopTestCase
|
||||
$this->assertEquals($sTestedAcronym, $sExceptedAcronym, "Acronym for '$sInput' doesn't match. Got '$sTestedAcronym', expected '$sExceptedAcronym'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function ToAcronymProvider()
|
||||
{
|
||||
return [
|
||||
@@ -481,4 +484,72 @@ class UtilsTest extends \Combodo\iTop\Test\UnitTest\ItopTestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider GetMentionedObjectsFromTextProvider
|
||||
* @covers utils::GetMentionedObjectsFromText
|
||||
*
|
||||
* @param string $sInput
|
||||
* @param string $sFormat
|
||||
* @param array $aExceptedMentionedObjects
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testGetMentionedObjectsFromText(string $sInput, string $sFormat, array $aExceptedMentionedObjects)
|
||||
{
|
||||
$aTestedMentionedObjects = utils::GetMentionedObjectsFromText($sInput, $sFormat);
|
||||
|
||||
$sExpectedAsString = print_r($aExceptedMentionedObjects, true);
|
||||
$sTestedAsString = print_r($aTestedMentionedObjects, true);
|
||||
|
||||
$this->assertEquals($sTestedAsString, $sExpectedAsString, "Found mentioned objects don't match. Got: $sTestedAsString, expected $sExpectedAsString");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetMentionedObjectsFromTextProvider(): array
|
||||
{
|
||||
$sAbsUrlAppRoot = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
return [
|
||||
'No object' => [
|
||||
"Begining
|
||||
Second line
|
||||
End",
|
||||
utils::ENUM_TEXT_FORMAT_HTML,
|
||||
[],
|
||||
],
|
||||
'1 UserRequest' => [
|
||||
"Begining
|
||||
Before link <a href=\"$sAbsUrlAppRoot/pages/UI.php&operation=details&class=UserRequest&id=12345&foo=bar\">R-012345</a> After link
|
||||
End",
|
||||
utils::ENUM_TEXT_FORMAT_HTML,
|
||||
[
|
||||
'UserRequest' => ['12345'],
|
||||
],
|
||||
],
|
||||
'2 UserRequests' => [
|
||||
"Begining
|
||||
Before link <a href=\"$sAbsUrlAppRoot/pages/UI.php&operation=details&class=UserRequest&id=12345&foo=bar\">R-012345</a> After link
|
||||
And <a href=\"$sAbsUrlAppRoot/pages/UI.php&operation=details&class=UserRequest&id=987654&foo=bar\">R-987654</a>
|
||||
End",
|
||||
utils::ENUM_TEXT_FORMAT_HTML,
|
||||
[
|
||||
'UserRequest' => ['12345', '987654'],
|
||||
],
|
||||
],
|
||||
'1 UserRequest, 1 Person' => [
|
||||
"Begining
|
||||
Before link <a href=\"$sAbsUrlAppRoot/pages/UI.php&operation=details&class=UserRequest&id=12345&foo=bar\">R-012345</a> After link
|
||||
And <a href=\"$sAbsUrlAppRoot/pages/UI.php&operation=details&class=Person&id=3&foo=bar\">Claude Monet</a>
|
||||
End",
|
||||
utils::ENUM_TEXT_FORMAT_HTML,
|
||||
[
|
||||
'UserRequest' => ['12345'],
|
||||
'Person' => ['3'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user