diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 8d7da1a58..05284a1de 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -3582,7 +3582,8 @@ abstract class DBObject implements iDisplay $oKPI->ComputeStatsForExtension($this, 'AfterUpdate'); // - TriggerOnObjectUpdate - $aParams = array('class_list' => MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL)); + $aClassList = MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL); + $aParams = array('class_list' => $aClassList); $oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnObjectUpdate AS t WHERE t.target_class IN (:class_list)'), array(), $aParams); while ($oTrigger = $oSet->Fetch()) { @@ -3596,6 +3597,44 @@ abstract class DBObject implements iDisplay } } + $sClass = get_class($this); + if (MetaModel::HasLifecycle($sClass)) + { + $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); + if (isset($this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode])) { + $sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode]; + // Change state triggers... + $aParams = array( + 'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL), + 'previous_state' => $sPreviousState, + 'new_state' => $this->Get($sStateAttCode), + ); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams); + while ($oTrigger = $oSet->Fetch()) { + /** @var \TriggerOnStateLeave $oTrigger */ + try { + $oTrigger->DoActivate($this->ToArgs('this')); + } + catch (Exception $e) { + $oTrigger->LogException($e, $this); + utils::EnrichRaisedException($oTrigger, $e); + } + } + + $oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams); + while ($oTrigger = $oSet->Fetch()) { + /** @var \TriggerOnStateEnter $oTrigger */ + try { + $oTrigger->DoActivate($this->ToArgs('this')); + } + catch (Exception $e) { + $oTrigger->LogException($e, $this); + utils::EnrichRaisedException($oTrigger, $e); + } + } + } + } + // Activate any existing trigger // - TriggerOnObjectMention // Forgotten by the fix of N°3245 @@ -4291,36 +4330,6 @@ abstract class DBObject implements iDisplay $this->DBWrite(); } - // Change state triggers... - $aParams = array( - 'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL), - 'previous_state' => $sPreviousState, - 'new_state' => $sNewState, - ); - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state"), array(), $aParams); - while ($oTrigger = $oSet->Fetch()) { - /** @var \TriggerOnStateLeave $oTrigger */ - try { - $oTrigger->DoActivate($this->ToArgs('this')); - } - catch (Exception $e) { - $oTrigger->LogException($e, $this); - utils::EnrichRaisedException($oTrigger, $e); - } - } - - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state"), array(), $aParams); - while ($oTrigger = $oSet->Fetch()) { - /** @var \TriggerOnStateEnter $oTrigger */ - try { - $oTrigger->DoActivate($this->ToArgs('this')); - } - catch (Exception $e) { - $oTrigger->LogException($e, $this); - utils::EnrichRaisedException($oTrigger, $e); - } - } - $this->FireEvent(EVENT_DB_AFTER_APPLY_STIMULUS, $aEventData); } else diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php index 91c335736..7ef5b612f 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php @@ -87,7 +87,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase /** * @return string Absolute path to the {@see \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase::GetTestEnvironment()} folder */ - final private function GetTestEnvironmentFolderAbsPath(): string + final protected function GetTestEnvironmentFolderAbsPath(): string { return APPROOT.'env-'.$this->GetTestEnvironment().'/'; } @@ -97,7 +97,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase * * @return void */ - final private function MarkEnvironmentReady(): void + private function MarkEnvironmentReady(): void { if (false === $this->IsEnvironmentReady()) { touch(static::GetTestEnvironmentFolderAbsPath()); @@ -109,7 +109,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase * * @details Having the environment ready means that it has been compiled for this global tests run, not that it is a relic from a previous global tests run */ - final private function IsEnvironmentReady(): bool + final protected function IsEnvironmentReady(): bool { // As these test cases run in separate processes, the best way we found to let know a process if its environment was already prepared for **this run** was to compare the modification times of: // - its own env- folder