mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-20 07:42:17 +02:00
Merge branch 'support/3.1' into saas/3.1
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
@@ -161,4 +161,4 @@ We have one sticker per contribution type. You might get multiple stickers with
|
|||||||
|
|
||||||
Here is the design of each stickers for year 2022:
|
Here is the design of each stickers for year 2022:
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -918,7 +918,7 @@ class RuntimeDashboard extends Dashboard
|
|||||||
{
|
{
|
||||||
$bCustomized = false;
|
$bCustomized = false;
|
||||||
|
|
||||||
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
|
$sDashboardFileSanitized = utils::RealPath(APPROOT.$sDashboardFile, APPROOT);
|
||||||
if (false === $sDashboardFileSanitized) {
|
if (false === $sDashboardFileSanitized) {
|
||||||
throw new SecurityException('Invalid dashboard file !');
|
throw new SecurityException('Invalid dashboard file !');
|
||||||
}
|
}
|
||||||
@@ -1141,7 +1141,7 @@ JS
|
|||||||
$oToolbar->AddSubBlock($oActionButton);
|
$oToolbar->AddSubBlock($oActionButton);
|
||||||
|
|
||||||
$aActions = array();
|
$aActions = array();
|
||||||
$sFile = addslashes($this->sDefinitionFile);
|
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
|
||||||
$sJSExtraParams = json_encode($aExtraParams);
|
$sJSExtraParams = json_encode($aExtraParams);
|
||||||
if ($this->HasCustomDashboard()) {
|
if ($this->HasCustomDashboard()) {
|
||||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class UIExtKeyWidget
|
|||||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||||
|
|
||||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_MODIFY) && $bAllowTargetCreation);
|
||||||
$bExtensions = true;
|
$bExtensions = true;
|
||||||
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||||
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
|
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||||
use Combodo\iTop\Service\Events\EventData;
|
use Combodo\iTop\Service\Events\EventData;
|
||||||
|
use Combodo\iTop\Service\Events\EventException;
|
||||||
use Combodo\iTop\Service\Events\EventService;
|
use Combodo\iTop\Service\Events\EventService;
|
||||||
|
use Combodo\iTop\Service\Events\EventServiceLog;
|
||||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager;
|
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,6 +205,8 @@ abstract class DBObject implements iDisplay
|
|||||||
|
|
||||||
const MAX_UPDATE_LOOP_COUNT = 10;
|
const MAX_UPDATE_LOOP_COUNT = 10;
|
||||||
|
|
||||||
|
private $aEventListeners = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DBObject constructor.
|
* DBObject constructor.
|
||||||
*
|
*
|
||||||
@@ -255,6 +259,10 @@ abstract class DBObject implements iDisplay
|
|||||||
$this->RegisterEventListeners();
|
$this->RegisterEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see RegisterCRUDListener
|
||||||
|
* @see EventService::RegisterListener()
|
||||||
|
*/
|
||||||
protected function RegisterEventListeners()
|
protected function RegisterEventListeners()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -6189,6 +6197,51 @@ abstract class DBObject implements iDisplay
|
|||||||
return OPT_ATT_NORMAL;
|
return OPT_ATT_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final function GetListeners(): array
|
||||||
|
{
|
||||||
|
$aListeners = [];
|
||||||
|
foreach ($this->aEventListeners as $aEventListener) {
|
||||||
|
$aListeners = array_merge($aListeners, $aEventListener);
|
||||||
|
}
|
||||||
|
return $aListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback for a specific event. The method to call will be saved in the object instance itself whereas calling {@see EventService::RegisterListener()} would
|
||||||
|
* save a callable (thus the method name AND the whole DBObject instance)
|
||||||
|
*
|
||||||
|
* @param string $sEvent corresponding event
|
||||||
|
* @param string $callback The callback method to call
|
||||||
|
* @param float $fPriority optional priority for callback order
|
||||||
|
* @param string $sModuleId
|
||||||
|
*
|
||||||
|
* @see EventService::RegisterListener()
|
||||||
|
*
|
||||||
|
* @since 3.1.0-3 3.1.1 3.2.0 N°6716
|
||||||
|
*/
|
||||||
|
final protected function RegisterCRUDListener(string $sEvent, string $callback, float $fPriority = 0.0, string $sModuleId = '')
|
||||||
|
{
|
||||||
|
$aEventCallbacks = $this->aEventListeners[$sEvent] ?? [];
|
||||||
|
|
||||||
|
$aEventCallbacks[] = array(
|
||||||
|
'event' => $sEvent,
|
||||||
|
'callback' => $callback,
|
||||||
|
'priority' => $fPriority,
|
||||||
|
'module' => $sModuleId,
|
||||||
|
);
|
||||||
|
usort($aEventCallbacks, function ($a, $b) {
|
||||||
|
$fPriorityA = $a['priority'];
|
||||||
|
$fPriorityB = $b['priority'];
|
||||||
|
if ($fPriorityA == $fPriorityB) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($fPriorityA < $fPriorityB) ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->aEventListeners[$sEvent] = $aEventCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sEvent
|
* @param string $sEvent
|
||||||
* @param array $aEventData
|
* @param array $aEventData
|
||||||
@@ -6200,15 +6253,53 @@ abstract class DBObject implements iDisplay
|
|||||||
*/
|
*/
|
||||||
public function FireEvent(string $sEvent, array $aEventData = array()): void
|
public function FireEvent(string $sEvent, array $aEventData = array()): void
|
||||||
{
|
{
|
||||||
if (EventService::IsEventRegistered($sEvent)) {
|
$aEventData['debug_info'] = 'from: '.get_class($this).':'.$this->GetKey();
|
||||||
$aEventData['debug_info'] = 'from: '.get_class($this).':'.$this->GetKey();
|
$aEventData['object'] = $this;
|
||||||
$aEventData['object'] = $this;
|
|
||||||
$aEventSources = [$this->m_sObjectUniqId];
|
// Call local listeners first
|
||||||
foreach (MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL, false) as $sClass) {
|
$aEventCallbacks = $this->aEventListeners[$sEvent] ?? [];
|
||||||
$aEventSources[] = $sClass;
|
$oFirstException = null;
|
||||||
|
$sFirstExceptionMessage = '';
|
||||||
|
foreach ($aEventCallbacks as $aEventCallback) {
|
||||||
|
$oKPI = new ExecutionKPI();
|
||||||
|
$sCallback = $aEventCallback['callback'];
|
||||||
|
if (!method_exists($this, $sCallback)) {
|
||||||
|
EventServiceLog::Error("Callback '".get_class($this).":$sCallback' does not exist");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EventServiceLog::Debug("Fire event '$sEvent' calling '".get_class($this).":$sCallback'");
|
||||||
|
try {
|
||||||
|
call_user_func([$this, $sCallback], new EventData($sEvent, null, $aEventData));
|
||||||
|
}
|
||||||
|
catch (EventException $e) {
|
||||||
|
EventServiceLog::Error("Event '$sEvent' for '$sCallback'} failed with blocking error: ".$e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
$sMessage = "Event '$sEvent' for '$sCallback'} failed with non-blocking error: ".$e->getMessage();
|
||||||
|
EventServiceLog::Error($sMessage);
|
||||||
|
if (is_null($oFirstException)) {
|
||||||
|
$sFirstExceptionMessage = $sMessage;
|
||||||
|
$oFirstException = $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$oKPI->ComputeStats('FireEvent', $sEvent);
|
||||||
}
|
}
|
||||||
EventService::FireEvent(new EventData($sEvent, $aEventSources, $aEventData));
|
|
||||||
}
|
}
|
||||||
|
if (!is_null($oFirstException)) {
|
||||||
|
throw new Exception($sFirstExceptionMessage, $oFirstException->getCode(), $oFirstException);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call global event listeners
|
||||||
|
if (!EventService::IsEventRegistered($sEvent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$aEventSources = [];
|
||||||
|
foreach (MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL, false) as $sClass) {
|
||||||
|
$aEventSources[] = $sClass;
|
||||||
|
}
|
||||||
|
EventService::FireEvent(new EventData($sEvent, $aEventSources, $aEventData));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
|||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
'iTopUpdate:Error:MissingFunction' => 'Lehetetlen elindítani a frissítést, hiányzó funkció',
|
'iTopUpdate:Error:MissingFunction' => 'Lehetetlen elindítani a frissítést, hiányzó funkció',
|
||||||
'iTopUpdate:Error:MissingFile' => 'Hiányzó fájl: %1$',
|
'iTopUpdate:Error:MissingFile' => 'Hiányzó fájl: %1$s',
|
||||||
'iTopUpdate:Error:CorruptedFile' => 'A %1$s fájl sérült',
|
'iTopUpdate:Error:CorruptedFile' => 'A %1$s fájl sérült',
|
||||||
'iTopUpdate:Error:BadFileFormat' => 'A frissítési fájl nem zip fájl',
|
'iTopUpdate:Error:BadFileFormat' => 'A frissítési fájl nem zip fájl',
|
||||||
'iTopUpdate:Error:BadFileContent' => 'A frissítési fájl nem alkalmazás archívum',
|
'iTopUpdate:Error:BadFileContent' => 'A frissítési fájl nem alkalmazás archívum',
|
||||||
|
|||||||
@@ -332,11 +332,14 @@ $(function()
|
|||||||
oParams.dashlet_class = sDashletClass;
|
oParams.dashlet_class = sDashletClass;
|
||||||
oParams.dashlet_id = sDashletId;
|
oParams.dashlet_id = sDashletId;
|
||||||
oParams.dashlet_type = options.dashlet_type;
|
oParams.dashlet_type = options.dashlet_type;
|
||||||
|
oParams.ajax_promise_id = 'ajax_promise_' + sDashletId;
|
||||||
var me = this;
|
var me = this;
|
||||||
$.post(this.options.render_to, oParams, function (data) {
|
$.post(this.options.render_to, oParams, function (data) {
|
||||||
me.ajax_div.html(data);
|
me.ajax_div.html(data);
|
||||||
me.add_dashlet_finalize(options, sDashletId, sDashletClass);
|
window[oParams.ajax_promise_id].then(function(){
|
||||||
me.mark_as_modified();
|
me.add_dashlet_finalize(options, sDashletId, sDashletClass);
|
||||||
|
me.mark_as_modified();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
on_dashlet_moved: function (oDashlet, oReceiver, bRefresh) {
|
on_dashlet_moved: function (oDashlet, oReceiver, bRefresh) {
|
||||||
|
|||||||
@@ -290,7 +290,6 @@ function DisplayEvents(WebPage $oPage, $sClass)
|
|||||||
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) {
|
foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sChildClass) {
|
||||||
if (!MetaModel::IsAbstract($sChildClass)) {
|
if (!MetaModel::IsAbstract($sChildClass)) {
|
||||||
$oObject = MetaModel::NewObject($sChildClass);
|
$oObject = MetaModel::NewObject($sChildClass);
|
||||||
$aSources[] = $oObject->GetObjectUniqId();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,7 +298,6 @@ function DisplayEvents(WebPage $oPage, $sClass)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$oObject = MetaModel::NewObject($sClass);
|
$oObject = MetaModel::NewObject($sClass);
|
||||||
$aSources[] = $oObject->GetObjectUniqId();
|
|
||||||
foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, false) as $sParentClass) {
|
foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, false) as $sParentClass) {
|
||||||
$aSources[] = $sParentClass;
|
$aSources[] = $sParentClass;
|
||||||
}
|
}
|
||||||
@@ -320,12 +318,19 @@ function DisplayEvents(WebPage $oPage, $sClass)
|
|||||||
});
|
});
|
||||||
$aColumns = [
|
$aColumns = [
|
||||||
'event' => ['label' => Dict::S('UI:Schema:Events:Event')],
|
'event' => ['label' => Dict::S('UI:Schema:Events:Event')],
|
||||||
'listener' => ['label' => Dict::S('UI:Schema:Events:Listener')],
|
'callback' => ['label' => Dict::S('UI:Schema:Events:Listener')],
|
||||||
'priority' => ['label' => Dict::S('UI:Schema:Events:Rank')],
|
'priority' => ['label' => Dict::S('UI:Schema:Events:Rank')],
|
||||||
'module' => ['label' => Dict::S('UI:Schema:Events:Module')],
|
'module' => ['label' => Dict::S('UI:Schema:Events:Module')],
|
||||||
];
|
];
|
||||||
|
// Get the object listeners first
|
||||||
$aRows = [];
|
$aRows = [];
|
||||||
$oReflectionClass = new ReflectionClass($sClass);
|
$oReflectionClass = new ReflectionClass($sClass);
|
||||||
|
if ($oReflectionClass->isInstantiable()) {
|
||||||
|
/** @var DBObject $oClass */
|
||||||
|
$oClass = new $sClass();
|
||||||
|
$aRows = $oClass->GetListeners();
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($aListeners as $aListener) {
|
foreach ($aListeners as $aListener) {
|
||||||
if (is_object($aListener['callback'][0])) {
|
if (is_object($aListener['callback'][0])) {
|
||||||
$sListenerClass = $sClass;
|
$sListenerClass = $sClass;
|
||||||
@@ -343,7 +348,7 @@ function DisplayEvents(WebPage $oPage, $sClass)
|
|||||||
}
|
}
|
||||||
$aRows[] = [
|
$aRows[] = [
|
||||||
'event' => $aListener['event'],
|
'event' => $aListener['event'],
|
||||||
'listener' => $sListener,
|
'callback' => $sListener,
|
||||||
'priority' => $aListener['priority'],
|
'priority' => $aListener['priority'],
|
||||||
'module' => $aListener['module'],
|
'module' => $aListener['module'],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1385,17 +1385,12 @@ EOF
|
|||||||
}
|
}
|
||||||
$sMethods .= "\n $sCallbackFct\n\n";
|
$sMethods .= "\n $sCallbackFct\n\n";
|
||||||
}
|
}
|
||||||
if (strpos($sCallback, '::') === false) {
|
|
||||||
$sEventListener = '[$this, \''.$sCallback.'\']';
|
|
||||||
} else {
|
|
||||||
$sEventListener = "'$sCallback'";
|
|
||||||
}
|
|
||||||
|
|
||||||
$sListenerRank = (float)($oListener->GetChildText('rank', '0'));
|
$sListenerRank = (float)($oListener->GetChildText('rank', '0'));
|
||||||
$sEvents .= <<<PHP
|
$sEvents .= <<<PHP
|
||||||
|
|
||||||
// listenerId = $sListenerId
|
// listenerId = $sListenerId
|
||||||
Combodo\iTop\Service\Events\EventService::RegisterListener("$sEventName", $sEventListener, \$this->m_sObjectUniqId, [], null, $sListenerRank, '$sModuleRelativeDir');
|
\$this->RegisterCRUDListener("$sEventName", '$sCallback', $sListenerRank, '$sModuleRelativeDir');
|
||||||
PHP;
|
PHP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Closure;
|
|||||||
use Combodo\iTop\Service\Events\Description\EventDescription;
|
use Combodo\iTop\Service\Events\Description\EventDescription;
|
||||||
use ContextTag;
|
use ContextTag;
|
||||||
use CoreException;
|
use CoreException;
|
||||||
|
use DBObject;
|
||||||
use Exception;
|
use Exception;
|
||||||
use ExecutionKPI;
|
use ExecutionKPI;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
@@ -53,6 +54,12 @@ final class EventService
|
|||||||
/**
|
/**
|
||||||
* Register a callback for a specific event
|
* Register a callback for a specific event
|
||||||
*
|
*
|
||||||
|
* **Warning** : be ultra careful on memory footprint ! each callback will be saved in {@see aEventListeners}, and a callback is
|
||||||
|
* made of the whole object instance and the method name ({@link https://www.php.net/manual/en/language.types.callable.php}).
|
||||||
|
* For example to register on DBObject instances, you should better use {@see DBObject::RegisterCRUDListener()}
|
||||||
|
*
|
||||||
|
* @uses aEventListeners
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
* @param string $sEvent corresponding event
|
* @param string $sEvent corresponding event
|
||||||
* @param callable $callback The callback to call
|
* @param callable $callback The callback to call
|
||||||
@@ -61,8 +68,12 @@ final class EventService
|
|||||||
* @param array|string|null $context context filter
|
* @param array|string|null $context context filter
|
||||||
* @param float $fPriority optional priority for callback order
|
* @param float $fPriority optional priority for callback order
|
||||||
*
|
*
|
||||||
* @return string Id of the registration
|
* @return string registration identifier
|
||||||
*
|
*
|
||||||
|
* @see DBObject::RegisterCRUDListener() to register in DBObject instances instead, to reduce memory footprint (callback saving)
|
||||||
|
*
|
||||||
|
* @since 3.1.0 method creation
|
||||||
|
* @since 3.1.0-3 3.1.1 3.2.0 N°6716 PHPDoc change to warn on memory footprint, and {@see DBObject::RegisterCRUDListener()} alternative
|
||||||
*/
|
*/
|
||||||
public static function RegisterListener(string $sEvent, callable $callback, $sEventSource = null, array $aCallbackData = [], $context = null, float $fPriority = 0.0, $sModuleId = ''): string
|
public static function RegisterListener(string $sEvent, callable $callback, $sEventSource = null, array $aCallbackData = [], $context = null, float $fPriority = 0.0, $sModuleId = ''): string
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ class DictionariesConsistencyAfterSetupTest extends ItopTestCase
|
|||||||
$aMismatchedKeys = [];
|
$aMismatchedKeys = [];
|
||||||
|
|
||||||
foreach ($aKeyArgsCountMap[$sReferenceLangCode] as $sKey => $iExpectedNbOfArgs){
|
foreach ($aKeyArgsCountMap[$sReferenceLangCode] as $sKey => $iExpectedNbOfArgs){
|
||||||
|
if (0 === $iExpectedNbOfArgs){
|
||||||
|
//no arg needed in EN.
|
||||||
|
//let s assume job has been done correctly in EN to simplify
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (in_array($sKey, self::$aLabelCodeNotToCheck)){
|
if (in_array($sKey, self::$aLabelCodeNotToCheck)){
|
||||||
//false positive: do not test
|
//false positive: do not test
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
|||||||
use ContactType;
|
use ContactType;
|
||||||
use CoreException;
|
use CoreException;
|
||||||
use DBObject;
|
use DBObject;
|
||||||
|
use DBObject\MockDBObjectWithCRUDEventListener;
|
||||||
use DBObjectSet;
|
use DBObjectSet;
|
||||||
use DBSearch;
|
use DBSearch;
|
||||||
use lnkPersonToTeam;
|
use lnkPersonToTeam;
|
||||||
@@ -518,6 +519,24 @@ class CRUDEventTest extends ItopDataTestCase
|
|||||||
|
|
||||||
$this->assertEquals(2, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
$this->assertEquals(2, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests with MockDBObject
|
||||||
|
public function testFireCRUDEvent()
|
||||||
|
{
|
||||||
|
$this->RequireOnceUnitTestFile('DBObject/MockDBObjectWithCRUDEventListener.php');
|
||||||
|
|
||||||
|
// For Metamodel list of classes
|
||||||
|
MockDBObjectWithCRUDEventListener::Init();
|
||||||
|
$oDBObject = new MockDBObjectWithCRUDEventListener();
|
||||||
|
$oDBObject2 = new MockDBObjectWithCRUDEventListener();
|
||||||
|
|
||||||
|
$oDBObject->FireEvent(MockDBObjectWithCRUDEventListener::TEST_EVENT);
|
||||||
|
|
||||||
|
$this->assertNotNull($oDBObject->oEventDataReceived);
|
||||||
|
$this->assertNull($oDBObject2->oEventDataReceived);
|
||||||
|
|
||||||
|
//echo($oDBObject->oEventDataReceived->Get('debug_info'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -941,4 +941,40 @@ class DBObjectTest extends ItopDataTestCase
|
|||||||
{
|
{
|
||||||
return $this->aReloadCount[$sClass][$sKey] ?? 0;
|
return $this->aReloadCount[$sClass][$sKey] ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.1.0-3 3.1.1 3.2.0 N°6716 test creation
|
||||||
|
*/
|
||||||
|
public function testConstructorMemoryFootprint():void
|
||||||
|
{
|
||||||
|
$idx = 0;
|
||||||
|
$fStart = microtime(true);
|
||||||
|
$fStartLoop = $fStart;
|
||||||
|
$iInitialPeak = 0;
|
||||||
|
$iMaxAllowedMemoryIncrease = 1 * 1024 * 1024;
|
||||||
|
|
||||||
|
for ($i = 0; $i < 5000; $i++) {
|
||||||
|
/** @noinspection PhpUnusedLocalVariableInspection We intentionally use a reference that will disappear on each loop */
|
||||||
|
$oPerson = new \Person();
|
||||||
|
if (0 == ($idx % 100)) {
|
||||||
|
$fDuration = microtime(true) - $fStartLoop;
|
||||||
|
$iMemoryPeakUsage = memory_get_peak_usage();
|
||||||
|
if ($iInitialPeak === 0) {
|
||||||
|
$iInitialPeak = $iMemoryPeakUsage;
|
||||||
|
$sInitialPeak = \utils::BytesToFriendlyFormat($iInitialPeak, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sCurrPeak = \utils::BytesToFriendlyFormat($iMemoryPeakUsage, 4);
|
||||||
|
echo "$idx ".sprintf('%.1f ms', $fDuration * 1000)." - Peak Memory Usage: $sCurrPeak\n";
|
||||||
|
|
||||||
|
$this->assertTrue(($iMemoryPeakUsage - $iInitialPeak) <= $iMaxAllowedMemoryIncrease , "Peak memory changed from $sInitialPeak to $sCurrPeak after $i loops");
|
||||||
|
|
||||||
|
$fStartLoop = microtime(true);
|
||||||
|
}
|
||||||
|
$idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fTotalDuration = microtime(true) - $fStart;
|
||||||
|
echo 'Total duration: '.sprintf('%.3f s', $fTotalDuration)."\n\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user