From e67d6e8a80fde18d8aba748f6e1e7d22a02ebcb2 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 25 Sep 2018 10:16:45 +0200 Subject: [PATCH] =?UTF-8?q?N=C2=B0917=20-=20Add=20new=20trigger=20on=20obj?= =?UTF-8?q?ect=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/cmdbabstract.class.inc.php | 14 +- core/attributedef.class.inc.php | 216 +++++++++++++++++++++++ core/dbobject.class.php | 10 ++ core/dict.class.inc.php | 2 +- core/trigger.class.inc.php | 63 ++++++- dictionaries/en.dictionary.itop.core.php | 11 ++ dictionaries/fr.dictionary.itop.core.php | 4 + 7 files changed, 316 insertions(+), 4 deletions(-) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 7f7ea9edc..ff0bc46c8 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1881,7 +1881,7 @@ EOF $sHTMLValue = UIExtKeyWidget::DisplayFromAttCode($oPage, $sAttCode, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $value, $iId, $bMandatory, $sFieldName, $sFormPrefix, $aExtKeyParams); $sHTMLValue .= "\n"; break; - + case 'RedundancySetting': $sHTMLValue = ''; $sHTMLValue .= ''; @@ -1945,6 +1945,18 @@ EOF $oPage->add_ready_script("$('#{$iId}').bind('validate', function(evt, sFormId) { return ValidateCustomFields('$iId', sFormId) } );"); // Custom validation function break; + case 'ObjectAttcode': + $iFieldSize = $oAttDef->GetMaxSize(); + if (is_array($sDisplayValue)) + { + $sDisplayValue = implode(', ', $sDisplayValue); + } + $sHTMLValue = "
{$sValidationSpan}{$sReloadSpan}"; + $aEventsList[] ='validate'; + $aEventsList[] ='keyup'; + $aEventsList[] ='change'; + break; + case 'String': default: $aEventsList[] ='validate'; diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 251ed5d27..f454d542c 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -7639,6 +7639,222 @@ class AttributePropertySet extends AttributeTable } } +class AttributeObjectAttCode extends AttributeDBFieldVoid +{ + static public function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array('is_null_allowed', 'class')); + } + + public function GetDefaultValue(DBObject $oHostObject = null) + { + return null; + } + + public function IsNullAllowed() + { + return $this->Get("is_null_allowed"); + } + + public function GetEditClass() + { + return "ObjectAttcode"; + } + + public function GetEditValue($value, $oHostObj = null) + { + if (is_string($value)) + { + return $value; + } + if (is_array($value)) + { + return implode(', ', $value); + } + return ''; + } + + protected function GetSQLCol($bFullSpec = false) + { + $iLen = $this->GetMaxSize(); + return "VARCHAR($iLen)" + .CMDBSource::GetSqlStringColumnDefinition() + .($bFullSpec ? $this->GetSQLColSpec() : ''); + } + + public function GetMaxSize() + { + return 255; + } + + /** + * @param array $aCols + * @param string $sPrefix + * + * @return mixed + * @throws \CoreException + * @throws \Exception + */ + public function FromSQLToValue($aCols, $sPrefix = '') + { + $sValue = $aCols["$sPrefix"]; + + return $this->MakeRealValue($sValue, null); + } + + /** + * @param $aCols + * @param string $sPrefix + * + * @return mixed + * @throws \Exception + */ + public function FromImportToValue($aCols, $sPrefix = '') + { + $sValue = $aCols["$sPrefix"]; + + return $this->MakeRealValue($sValue, null); + } + + /** + * force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing! + * + * @param $proposedValue + * @param \DBObject $oHostObj + * + * @return mixed + * @throws \Exception + */ + public function MakeRealValue($proposedValue, $oHostObj) + { + $aAllowedAttributes = array(); + $sClass = ''; + if (!empty($oHostObj)) + { + $sTargetClass = $this->Get('class'); + $sClass = $oHostObj->Get($sTargetClass); + $aAllowedAttributes = MetaModel::GetAttributesList($sClass); + } + if (is_string($proposedValue) && !empty($proposedValue)) + { + $proposedValue = trim("$proposedValue"); + $proposedValue = explode(',', $proposedValue); + $aValues = array(); + foreach($proposedValue as $sValue) + { + $sAttCode = trim($sValue); + if (empty($aAllowedAttributes) || in_array($sAttCode, $aAllowedAttributes)) + { + $aValues[] = $sAttCode; + } + else + { + throw new CoreUnexpectedValue("The attribute {$sAttCode} does not exist in class {$sClass}"); + } + } + return $aValues; + } + + return $proposedValue; + } + + /** + * Get the value from a given string (plain text, CSV import) + * + * @param string $sProposedValue + * @param bool $bLocalizedValue + * @param string $sSepItem + * @param string $sSepAttribute + * @param string $sSepValue + * @param string $sAttributeQualifier + * + * @return mixed null if no match could be found + * @throws \Exception + */ + public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null) + { + return $this->MakeRealValue($sProposedValue, null); + } + + public function GetNullValue() + { + return null; + } + + public function IsNull($proposedValue) + { + return empty($proposedValue); + } + + /** + * To be overloaded for localized enums + * + * @param $sValue + * + * @return string label corresponding to the given value (in plain text) + * @throws \CoreWarning + * @throws \Exception + */ + public function GetValueLabel($sValue) + { + if (is_array($sValue)) + { + return implode(', ', $sValue); + } + return $sValue; + } + + /** + * @param string $sValue + * @param null $oHostObj + * + * @return string + * @throws \CoreWarning + */ + public function GetAsPlainText($sValue, $oHostObj = null) + { + return $this->GetValueLabel($sValue); + } + + /** + * @param $value + * + * @return string + * @throws \CoreWarning + */ + public function ScalarToSQL($value) + { + if (empty($value)) + { + return ''; + } + if (is_array($value)) + { + return implode(', ', $value); + } + return $value; + } + + /** + * @param $value + * @param \DBObject $oHostObject + * @param bool $bLocalize + * + * @return string|null + * + * @throws \CoreException + * @throws \Exception + */ + public function GetAsHTML($value, $oHostObject = null, $bLocalize = true) + { + if (is_array($value)) + { + return implode(', ', $value); + } + return $value; + } +} + /** * The attribute dedicated to the friendly name automatic attribute (not written) * diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 1bc5f5e3a..f5d98b553 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1998,6 +1998,16 @@ abstract class DBObject implements iDisplay // Save the original values (will be reset to the new values when the object get written to the DB) $aOriginalValues = $this->m_aOrigValues; + // Activate any existing trigger + $sClass = get_class($this); + $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectUpdate AS t WHERE t.target_class IN ('$sClassList')")); + while ($oTrigger = $oSet->Fetch()) + { + /** @var \Trigger $oTrigger */ + $oTrigger->DoActivate($this->ToArgs('this')); + } + $bHasANewExternalKeyValue = false; $aHierarchicalKeys = array(); $aDBChanges = array(); diff --git a/core/dict.class.inc.php b/core/dict.class.inc.php index b792660e8..92e937210 100644 --- a/core/dict.class.inc.php +++ b/core/dict.class.inc.php @@ -197,7 +197,7 @@ class Dict /** * Initialize a the entries for a given language (replaces the former Add() method) * @param string $sLanguageCode Code identifying the language i.e. 'FR-FR', 'EN-US' - * @param hash $aEntries Hash array of dictionnary entries + * @param array $aEntries Hash array of dictionnary entries */ public static function SetEntries($sLanguageCode, $aEntries) { diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index 0b824a661..778813415 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -194,7 +194,7 @@ abstract class TriggerOnObject extends Trigger { /** @var \DBObject $oObject */ $oObject = $aContextArgs['this->object()']; - $bGo = $this->IsTargetObject($oObject->GetKey()); + $bGo = $this->IsTargetObject($oObject->GetKey(), $oObject->ListChanges()); } if ($bGo) { @@ -204,6 +204,7 @@ abstract class TriggerOnObject extends Trigger /** * @param $iObjectId + * @param array $aChanges * * @return bool * @throws \CoreException @@ -212,7 +213,7 @@ abstract class TriggerOnObject extends Trigger * @throws \MySQLHasGoneAwayException * @throws \OQLException */ - public function IsTargetObject($iObjectId) + public function IsTargetObject($iObjectId, $aChanges = array()) { $sFilter = trim($this->Get('filter')); if (strlen($sFilter) > 0) @@ -401,6 +402,64 @@ class TriggerOnObjectCreate extends TriggerOnObject } } +/** + * Class TriggerOnObjectCreate + */ +class TriggerOnObjectUpdate extends TriggerOnObject +{ + /** + * @throws \CoreException + * @throws \Exception + */ + public static function Init() + { + $aParams = array + ( + "category" => "grant_by_profile,core/cmdb,application", + "key_type" => "autoincrement", + "name_attcode" => "description", + "state_attcode" => "", + "reconc_keys" => array('description'), + "db_table" => "priv_trigger_onobjupdate", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeObjectAttCode('target_attcodes', array("allowed_values" => null, "class" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "depends_on" => array('target_class')))); + + // Display lists + MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'target_attcodes', '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 + } + + public function IsTargetObject($iObjectId, $aChanges = array()) + { + if (!parent::IsTargetObject($iObjectId, $aChanges)) + { + return false; + } + + // Check the attribute + $aAttCodes = $this->Get('target_attcodes'); + if (empty($aAttCodes)) + { + return true; + } + foreach($aAttCodes as $sAttCode) + { + if (array_key_exists($sAttCode, $aChanges)) + { + return true; + } + } + return false; + } +} + /** * Class lnkTriggerAction */ diff --git a/dictionaries/en.dictionary.itop.core.php b/dictionaries/en.dictionary.itop.core.php index 39ffe0999..e67683343 100644 --- a/dictionaries/en.dictionary.itop.core.php +++ b/dictionaries/en.dictionary.itop.core.php @@ -578,6 +578,17 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:TriggerOnObjectCreate+' => 'Trigger on object creation of [a child class of] the given class', )); +// +// Class: TriggerOnObjectUpdate +// + +Dict::Add('EN US', 'English', 'English', array( + 'Class:TriggerOnObjectUpdate' => 'Trigger (on object update)', + 'Class:TriggerOnObjectUpdate+' => 'Trigger on object update of [a child class of] the given class', + 'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Target attributes', + 'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '', +)); + // // Class: TriggerOnThresholdReached // diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php index e83db72d7..2f8b77ffc 100644 --- a/dictionaries/fr.dictionary.itop.core.php +++ b/dictionaries/fr.dictionary.itop.core.php @@ -61,6 +61,10 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Class:TriggerOnStateLeave+' => '', 'Class:TriggerOnObjectCreate' => 'Déclencheur sur la création d\'un objet', 'Class:TriggerOnObjectCreate+' => '', + 'Class:TriggerOnObjectUpdate' => 'Déclencheur sur la modification d\'un objet', + 'Class:TriggerOnObjectUpdate+' => '', + 'Class:TriggerOnObjectUpdate/Attribute:target_attcodes' => 'Attributs cible', + 'Class:TriggerOnObjectUpdate/Attribute:target_attcodes+' => '', 'Class:lnkTriggerAction' => 'Actions-Déclencheur', 'Class:lnkTriggerAction+' => '', 'Class:lnkTriggerAction/Attribute:action_id' => 'Action',