Merge remote-tracking branch 'origin/support/3.1' into support/3.2

# Conflicts:
#	tests/php-unit-tests/unitary-tests/core/CRUDEventTest.php
#	tests/php-unit-tests/unitary-tests/core/DBObject/MockDBObjectWithCRUDEventListener.php
This commit is contained in:
Eric Espie
2024-05-24 10:04:40 +02:00
6 changed files with 507 additions and 536 deletions

View File

@@ -5956,7 +5956,7 @@ JS
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
{
$this->NotifyAttachedObjectsOnLinkClassModification();
$this->FireEventDbLinksChangedForCurrentObject();
$this->RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]);
}
@@ -6069,31 +6069,6 @@ JS
}
}
/**
* Fire the EVENT_DB_LINKS_CHANGED event if current object is registered
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
*
* @since 3.1.0 N°5906
*/
final protected function FireEventDbLinksChangedForCurrentObject(): void
{
if (true === static::IsEventDBLinksChangedBlocked()) {
return;
}
$sClass = get_class($this);
$sId = $this->GetKey();
$bIsObjectAwaitingEventDbLinksChanged = self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
if (false === $bIsObjectAwaitingEventDbLinksChanged) {
return;
}
self::FireEventDbLinksChangedForObject($this);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
/**
* Fire the EVENT_DB_LINKS_CHANGED event if given object is registered, and unregister it
*
@@ -6132,9 +6107,9 @@ JS
self::SetEventDBLinksChangedBlocked(true);
// N°6408 The object can have been deleted
if (!is_null($oObject)) {
MetaModel::StartReentranceProtection($oObject);
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
MetaModel::StopReentranceProtection($oObject);
// Update the object if needed
if (count($oObject->ListChanges()) !== 0) {
$oObject->DBUpdate();
}

View File

@@ -3334,6 +3334,9 @@ abstract class DBObject implements iDisplay
*/
public function DBInsertNoReload()
{
// Prevent DBUpdate at this point (reentrancy protection with temp id)
MetaModel::StartReentranceProtection($this);
$sClass = get_class($this);
$this->AddCurrentObjectInCrudStack('INSERT');
@@ -3380,6 +3383,8 @@ abstract class DBObject implements iDisplay
}
$this->ComputeStopWatchesDeadline(true);
// With temp id
MetaModel::StopReentranceProtection($this);
$iTransactionRetry = 1;
$bIsTransactionEnabled = MetaModel::GetConfig()->Get('db_core_transactions_enabled');
@@ -3572,6 +3577,12 @@ abstract class DBObject implements iDisplay
*/
public function DBUpdate()
{
if (!MetaModel::StartReentranceProtection($this)) {
$this->LogCRUDExit(__METHOD__, 'Rejected (reentrance)');
return false;
}
$this->LogCRUDEnter(__METHOD__);
if (!$this->m_bIsInDB)
{
@@ -3581,12 +3592,6 @@ abstract class DBObject implements iDisplay
$this->AddCurrentObjectInCrudStack('UPDATE');
if (!MetaModel::StartReentranceProtection($this)) {
$this->RemoveCurrentObjectInCrudStack();
$this->LogCRUDExit(__METHOD__, 'Rejected (reentrance)');
return false;
}
try {
// Protect against infinite loop
$this->iUpdateLoopCount++;

View File

@@ -231,6 +231,11 @@
<callback>OnLinksChangedTicket</callback>
<rank>0</rank>
</event_listener>
<event_listener id="UpdateImpactAnalysisLocal">
<event>EVENT_DB_BEFORE_WRITE</event>
<callback>OnBeforeWriteTicket</callback>
<rank>0</rank>
</event_listener>
</event_listeners>
<methods>
<method id="OnLinksChangedTicket">
@@ -241,6 +246,20 @@
public function OnLinksChangedTicket(Combodo\iTop\Service\Events\EventData $oEventData)
{
$this->UpdateImpactedItems();
}
]]></code>
</method>
<method id="OnBeforeWriteTicket">
<static>false</static>
<access>public</access>
<type>EventListener</type>
<code><![CDATA[
public function OnBeforeWriteTicket(Combodo\iTop\Service\Events\EventData $oEventData)
{
$aChanges = $this->ListChanges();
if ($this->IsNew() || array_key_exists('functionalcis_list', $aChanges) || array_key_exists('contacts_list', $aChanges)) {
$this->UpdateImpactedItems();
}
}
]]></code>
</method>

View File

@@ -1,89 +0,0 @@
<?php
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
class cmdbAbstractObjectTest extends ItopDataTestCase {
const USE_TRANSACTION = true;
const CREATE_TEST_ORG = true;
protected function setUp(): void
{
parent::setUp();
}
public function testProcessClassIdDeferredUpdate()
{
// Create the team
$oTeam = MetaModel::NewObject(Team::class, ['name' => 'TestTeam1', 'org_id' => $this->getTestOrgId()]);
$oTeam->DBInsert();
// --- Simulating modifications of :
// - lnkPersonToTeam:1 is sample data with : team_id=39 ; person_id=9 ; role_id=3
// - lnkPersonToTeam:2 is sample data with : team_id=39 ; person_id=14 ; role_id=0
$aLinkStack = [
'Team' => [$oTeam->GetKey() => 2],
'Person' => [
'9' => 1,
'14' => 1,
],
'ContactType' => [
'1' => 1,
'0' => 1,
],
];
$this->SetObjectsAwaitingFireEventDbLinksChanged($aLinkStack);
// Processing deferred updates for Team
$this->InvokeNonPublicMethod(get_class($oTeam), 'FireEventDbLinksChangedForCurrentObject', $oTeam, []);
$aLinkModificationsStack = $this->GetObjectsAwaitingFireEventDbLinksChanged();
$aExpectedLinkStack = [
'Team' => [],
'Person' => [
'9' => 1,
'14' => 1,
],
'ContactType' => [
'1' => 1,
'0' => 1,
],
];
self::assertSame($aExpectedLinkStack, $aLinkModificationsStack);
// --- Simulating modifications of :
// - lnkApplicationSolutionToFunctionalCI::2 : applicationsolution_id=13 ; functionalci_id=29
// - lnkApplicationSolutionToFunctionalCI::8 : applicationsolution_id=13 ; functionalci_id=27
// The lnkApplicationSolutionToFunctionalCI points on root classes, so we can test unstacking for a leaf class
$aLinkStack = [
'ApplicationSolution' => ['13' => 2],
'FunctionalCI' => [
'29' => 1,
'27' => 1,
],
];
$this->SetObjectsAwaitingFireEventDbLinksChanged($aLinkStack);
// Processing deferred updates for WebServer::29
/** @var \cmdbAbstractObject $oLinkPersonToTeam1 */
$oWebServer29 = MetaModel::GetObject(WebServer::class, 29);
$this->InvokeNonPublicMethod(get_class($oWebServer29), 'FireEventDbLinksChangedForCurrentObject', $oWebServer29, []);
$aLinkModificationsStack = $this->GetObjectsAwaitingFireEventDbLinksChanged();
$aExpectedLinkStack = [
'ApplicationSolution' => ['13' => 2],
'FunctionalCI' => [
'27' => 1,
],
];
self::assertSame($aExpectedLinkStack, $aLinkModificationsStack);
}
private function GetObjectsAwaitingFireEventDbLinksChanged(): array
{
return $this->GetNonPublicStaticProperty(cmdbAbstractObject::class, 'aObjectsAwaitingEventDbLinksChanged');
}
private function SetObjectsAwaitingFireEventDbLinksChanged(array $aObjects): void
{
$this->SetNonPublicStaticProperty(cmdbAbstractObject::class, 'aObjectsAwaitingEventDbLinksChanged', $aObjects);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace DBObject;
use Combodo\iTop\Service\Events\EventData;
use MetaModel;
class MockDBObjectWithCRUDEventListener extends \DBObject
{
const TEST_EVENT = 'test_event';
public $oEventDataReceived = null;
public static function Init()
{
$aParams = array
(
'category' => 'bizmodel, searchable',
'key_type' => 'autoincrement',
'name_attcode' => '',
'state_attcode' => '',
'reconc_keys' => [],
'db_table' => 'priv_unit_tests_mock',
'db_key_field' => 'id',
'db_finalclass_field' => '',
'display_template' => '',
'indexes' => [],
);
MetaModel::Init_Params($aParams);
}
protected function RegisterEventListeners()
{
$this->RegisterCRUDListener(self::TEST_EVENT, 'TestEventCallback', 0, 'unit-test');
}
public function TestEventCallback(EventData $oEventData)
{
$this->oEventDataReceived = $oEventData;
}
}