mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 06:18:44 +02:00
N°2875 - Invert TriggerOnObjectMention approach
- Trigger is now positioned on a specific "host" class (eg. Ticket) - Trigger now has a "mentioned objects" filter which determines the scope of mentioned objects which will activate the trigger
This commit is contained in:
@@ -3220,17 +3220,19 @@ abstract class DBObject implements iDisplay
|
||||
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.
|
||||
// This is due to the current implementation of triggers, the events will only be visible on the object the trigger's OQL is based on... 😕
|
||||
$aTriggerArgs = $this->ToArgs('source') + array('this->object()' => $oMentionedObject);
|
||||
$aTriggerArgs = $this->ToArgs('this') + array('mentioned->object()' => $oMentionedObject);
|
||||
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses($sMentionedClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"),
|
||||
array(), $aParams);
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
try {
|
||||
// Ensure to handle only mentioned object in the trigger's scope
|
||||
if ($oTrigger->IsMentionedObjectInScope($oMentionedObject) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oTrigger->DoActivate($aTriggerArgs);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
|
||||
@@ -239,7 +239,8 @@ abstract class TriggerOnObject extends Trigger
|
||||
* @param $iObjectId
|
||||
* @param array $aChanges
|
||||
*
|
||||
* @return bool
|
||||
* @return bool True if the object of ID $iObjectId is within the scope of the OQL defined by the "filter" attribute
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
@@ -583,13 +584,45 @@ class TriggerOnObjectMention extends TriggerOnObject
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
*
|
||||
* @return bool True if $oObject is within the scope of the OQL defined by the "mentioned_filter" attribute OR if no mentioned_filter defined. Otherwise, returns false.
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function IsMentionedObjectInScope(DBObject $oObject)
|
||||
{
|
||||
$sFilter = trim($this->Get('mentioned_filter'));
|
||||
if (strlen($sFilter) > 0)
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSearch->AddCondition('id', $oObject->GetKey(), '=');
|
||||
$oSearch->AddCondition('finalclass', get_class($oObject), '=');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$bRet = $oSet->CountExceeds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bRet = true;
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2412,8 +2412,9 @@ EOF
|
||||
// TODO 3.0.0: Move this to new ajax render controller?
|
||||
case 'cke_mentions':
|
||||
$oPage->SetContentType('application/json');
|
||||
$sMarker = utils::ReadParam('marker', '', false, 'raw_data');
|
||||
$sNeedle = utils::ReadParam('needle', '', false, 'raw_data');
|
||||
$sMarker = utils::ReadParam('marker', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$sNeedle = utils::ReadParam('needle', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$sHostClass = utils::ReadParam('host_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
|
||||
// Check parameters
|
||||
if($sMarker === '') {
|
||||
@@ -2427,12 +2428,46 @@ EOF
|
||||
|
||||
$aMatches = array();
|
||||
if ($sNeedle !== '') {
|
||||
// Retrieve scope from marker
|
||||
$sScope = $aMentionsAllowedClasses[$sMarker];
|
||||
if (MetaModel::IsValidClass($sScope)) {
|
||||
$sScope = "SELECT $sScope";
|
||||
// Retrieve mentioned class from marker
|
||||
$sMentionedClass = $aMentionsAllowedClasses[$sMarker];
|
||||
if (MetaModel::IsValidClass($sMentionedClass) === false) {
|
||||
throw new Exception('Invalid class "'.$sMentionedClass.'" for marker "'.$sMarker.'"');
|
||||
}
|
||||
|
||||
// Base search used when no trigger configured
|
||||
$oSearch = DBSearch::FromOQL("SELECT $sMentionedClass");
|
||||
|
||||
// Retrieve restricting scopes from triggers if any
|
||||
if (strlen($sHostClass) > 0) {
|
||||
$aTriggerMentionedSearches = [];
|
||||
|
||||
$aTriggerSetParams = array('class_list' => MetaModel::EnumParentClasses($sHostClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oTriggerSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aTriggerSetParams);
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
while ($oTrigger = $oTriggerSet->Fetch()) {
|
||||
$sTriggerMentionedOQL = $oTrigger->Get('mentioned_filter');
|
||||
|
||||
// No filter on mentioned objects, don't restrict the scope at all, it can be any object of $sMentionedClass
|
||||
if (strlen($sTriggerMentionedOQL) === 0) {
|
||||
$aTriggerMentionedSearches = [$oSearch];
|
||||
break;
|
||||
}
|
||||
|
||||
$oTriggerMentionedSearch = DBSearch::FromOQL($sTriggerMentionedOQL);
|
||||
$sTriggerMentionedClass = $oTriggerMentionedSearch->GetClass();
|
||||
|
||||
// Filter is not about the mentioned class, don't mind it
|
||||
if (is_a($sMentionedClass, $sTriggerMentionedClass, true) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aTriggerMentionedSearches[] = $oTriggerMentionedSearch;
|
||||
}
|
||||
|
||||
if (count($aTriggerMentionedSearches) > 0) {
|
||||
$oSearch = new DBUnionSearch($aTriggerMentionedSearches);
|
||||
}
|
||||
}
|
||||
$oSearch = DBSearch::FromOQL($sScope);
|
||||
|
||||
$sSearchMainClassName = $oSearch->GetClass();
|
||||
$sSearchMainClassAlias = $oSearch->GetClassAlias();
|
||||
@@ -2451,7 +2486,7 @@ EOF
|
||||
$oSet->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
while ($oObject = $oSet->Fetch()) {
|
||||
// Note $oObject finalclass might be different than $sTargetClass
|
||||
// Note $oObject finalclass might be different than $sMentionedClass
|
||||
$sObjectClass = get_class($oObject);
|
||||
$iObjectId = $oObject->GetKey();
|
||||
$aMatch = [
|
||||
|
||||
@@ -11,6 +11,7 @@ use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use DBObject;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class CaseLogEntryForm
|
||||
@@ -203,6 +204,17 @@ class CaseLogEntryForm extends UIContentBlock
|
||||
protected function InitTextInput()
|
||||
{
|
||||
$this->oTextInput = new RichText();
|
||||
|
||||
// Add the "host_class" to the mention endpoints so it can filter objects regarding the triggers
|
||||
$aConfig = $this->oTextInput->GetConfig();
|
||||
if (isset($aConfig['mentions'])) {
|
||||
foreach ($aConfig['mentions'] as $iIdx => $aData) {
|
||||
$sFeed = $aConfig['mentions'][$iIdx]['feed'];
|
||||
$aConfig['mentions'][$iIdx]['feed'] = utils::AddParameterToUrl($sFeed, 'host_class', $this->GetObjectClass());
|
||||
}
|
||||
}
|
||||
$this->oTextInput->SetConfig($aConfig);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user