mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
Merge branch 'support/3.2' into develop
This commit is contained in:
@@ -199,7 +199,7 @@ class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
|
|||||||
libxml_clear_errors();
|
libxml_clear_errors();
|
||||||
$oFileXml->formatOutput = true;
|
$oFileXml->formatOutput = true;
|
||||||
$oFileXml->preserveWhiteSpace = false;
|
$oFileXml->preserveWhiteSpace = false;
|
||||||
$oFileXml->loadXML($sFileContent);
|
$oFileXml->loadXML($sFileContent, LIBXML_BIGLINES);
|
||||||
|
|
||||||
$oFileItopFormat = new iTopDesignFormat($oFileXml);
|
$oFileItopFormat = new iTopDesignFormat($oFileXml);
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ EOF
|
|||||||
if ($sIntroduction != null) {
|
if ($sIntroduction != null) {
|
||||||
$oPage->add('<div class="ui-dialog-header">'.$sIntroduction.'</div>');
|
$oPage->add('<div class="ui-dialog-header">'.$sIntroduction.'</div>');
|
||||||
}
|
}
|
||||||
|
$oPage->add('<div class="designer-dialog-error"></div>');
|
||||||
$this->Render($oPage);
|
$this->Render($oPage);
|
||||||
$oPage->add('</div>');
|
$oPage->add('</div>');
|
||||||
|
|
||||||
|
|||||||
@@ -584,12 +584,12 @@ class CMDBSource
|
|||||||
$oResult = DbConnectionWrapper::GetDbConnection(true)->query($sSql);
|
$oResult = DbConnectionWrapper::GetDbConnection(true)->query($sSql);
|
||||||
} catch (mysqli_sql_exception $e) {
|
} catch (mysqli_sql_exception $e) {
|
||||||
self::LogDeadLock($e, true);
|
self::LogDeadLock($e, true);
|
||||||
throw new MySQLException('Failed to issue SQL query', ['query' => $sSql, $e]);
|
throw new MySQLException('Failed to issue SQL query', ['query' => $sSql, $e, 'stack' => $e->getTraceAsString()]);
|
||||||
} finally {
|
} finally {
|
||||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||||
}
|
}
|
||||||
if ($oResult === false) {
|
if ($oResult === false) {
|
||||||
$aContext = ['query' => $sSql];
|
$aContext = ["\nstack" => (new Exception(''))->getTraceAsString(), "\nquery" => $sSql];
|
||||||
|
|
||||||
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection(true)->errno;
|
$iMySqlErrorNo = DbConnectionWrapper::GetDbConnection(true)->errno;
|
||||||
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();
|
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||||
<classes>
|
<classes>
|
||||||
<class id="lnkActionNotificationToContact" _delta="define">
|
<class id="lnkActionNotificationToContact" _delta="define">
|
||||||
<parent>cmdbAbstractObject</parent>
|
<parent>DBObject</parent>
|
||||||
<properties>
|
<properties>
|
||||||
<category>core/cmdb,application</category>
|
<is_link>1</is_link>
|
||||||
|
<category>core/cmdb,view_in_gui</category>
|
||||||
<abstract>false</abstract>
|
<abstract>false</abstract>
|
||||||
<key_type>autoincrement</key_type>
|
<key_type>autoincrement</key_type>
|
||||||
<db_table>priv_lnk_action_notif_to_contact</db_table>
|
<db_table>priv_lnk_action_notif_to_contact</db_table>
|
||||||
@@ -42,18 +43,21 @@
|
|||||||
<target_class>ActionNotification</target_class>
|
<target_class>ActionNotification</target_class>
|
||||||
<default_value/>
|
<default_value/>
|
||||||
<is_null_allowed>false</is_null_allowed>
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||||
</field>
|
</field>
|
||||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||||
<sql>contact_id</sql>
|
<sql>contact_id</sql>
|
||||||
<target_class>Contact</target_class>
|
<target_class>Contact</target_class>
|
||||||
<default_value/>
|
<default_value/>
|
||||||
<is_null_allowed>false</is_null_allowed>
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||||
</field>
|
</field>
|
||||||
<field id="trigger_id" xsi:type="AttributeExternalKey">
|
<field id="trigger_id" xsi:type="AttributeExternalKey">
|
||||||
<sql>trigger_id</sql>
|
<sql>trigger_id</sql>
|
||||||
<target_class>Trigger</target_class>
|
<target_class>Trigger</target_class>
|
||||||
<default_value/>
|
<default_value/>
|
||||||
<is_null_allowed>false</is_null_allowed>
|
<is_null_allowed>false</is_null_allowed>
|
||||||
|
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||||
</field>
|
</field>
|
||||||
<field id="subscribed" xsi:type="AttributeBoolean">
|
<field id="subscribed" xsi:type="AttributeBoolean">
|
||||||
<sql>subscribed</sql>
|
<sql>subscribed</sql>
|
||||||
@@ -65,8 +69,6 @@
|
|||||||
<details>
|
<details>
|
||||||
<items>
|
<items>
|
||||||
<item id="col:col1">
|
<item id="col:col1">
|
||||||
<items>
|
|
||||||
<item id="fieldset:lnkActionNotificationToContact:content">
|
|
||||||
<items>
|
<items>
|
||||||
<item id="action_id">
|
<item id="action_id">
|
||||||
<rank>10</rank>
|
<rank>10</rank>
|
||||||
@@ -74,10 +76,11 @@
|
|||||||
<item id="contact_id">
|
<item id="contact_id">
|
||||||
<rank>20</rank>
|
<rank>20</rank>
|
||||||
</item>
|
</item>
|
||||||
<item id="title">
|
<item id="trigger_id">
|
||||||
<rank>30</rank>
|
<rank>30</rank>
|
||||||
</item>
|
</item>
|
||||||
</items>
|
<item id="subscribed">
|
||||||
|
<rank>40</rank>
|
||||||
</item>
|
</item>
|
||||||
</items>
|
</items>
|
||||||
</item>
|
</item>
|
||||||
@@ -91,11 +94,30 @@
|
|||||||
<item id="contact_id">
|
<item id="contact_id">
|
||||||
<rank>20</rank>
|
<rank>20</rank>
|
||||||
</item>
|
</item>
|
||||||
<item id="title">
|
<item id="trigger_id">
|
||||||
<rank>30</rank>
|
<rank>30</rank>
|
||||||
</item>
|
</item>
|
||||||
|
<item id="subscribed">
|
||||||
|
<rank>40</rank>
|
||||||
|
</item>
|
||||||
</items>
|
</items>
|
||||||
</list>
|
</list>
|
||||||
|
<default_search>
|
||||||
|
<items>
|
||||||
|
<item id="contact_id">
|
||||||
|
<rank>10</rank>
|
||||||
|
</item>
|
||||||
|
<item id="action_id">
|
||||||
|
<rank>20</rank>
|
||||||
|
</item>
|
||||||
|
<item id="trigger_id">
|
||||||
|
<rank>30</rank>
|
||||||
|
</item>
|
||||||
|
<item id="subscribed">
|
||||||
|
<rank>40</rank>
|
||||||
|
</item>
|
||||||
|
</items>
|
||||||
|
</default_search>
|
||||||
</presentation>
|
</presentation>
|
||||||
<methods/>
|
<methods/>
|
||||||
</class>
|
</class>
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ class DesignDocument extends DOMDocument
|
|||||||
$this->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
$this->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function loadXML(string $source, int $options = 0)
|
||||||
|
{
|
||||||
|
return parent::loadXML($source, $options | LIBXML_BIGLINES);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overload of the standard API
|
* Overload of the standard API
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6119,12 +6119,14 @@ abstract class MetaModel
|
|||||||
|
|
||||||
if ($bMustBeFound && empty($aRow)) {
|
if ($bMustBeFound && empty($aRow)) {
|
||||||
$sNotFoundErrorMessage = "No result for the single row query";
|
$sNotFoundErrorMessage = "No result for the single row query";
|
||||||
IssueLog::Info($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
|
$e = new CoreException($sNotFoundErrorMessage);
|
||||||
|
IssueLog::Error($sNotFoundErrorMessage, LogChannels::CMDB_SOURCE, [
|
||||||
'class' => $sClass,
|
'class' => $sClass,
|
||||||
'key' => $iKey,
|
'key' => $iKey,
|
||||||
'sql_query' => $sSQL,
|
'sql_query' => $sSQL,
|
||||||
|
'stack' => $e->getTraceAsString(),
|
||||||
]);
|
]);
|
||||||
throw new CoreException($sNotFoundErrorMessage);
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $aRow;
|
return $aRow;
|
||||||
|
|||||||
@@ -562,7 +562,24 @@ Dict::Add('EN US', 'English', 'English', [
|
|||||||
'Class:ActionNotification' => 'Notification Action',
|
'Class:ActionNotification' => 'Notification Action',
|
||||||
'Class:ActionNotification+' => 'Notification Action (abstract)',
|
'Class:ActionNotification+' => 'Notification Action (abstract)',
|
||||||
'Class:ActionNotification/Attribute:language' => 'Language',
|
'Class:ActionNotification/Attribute:language' => 'Language',
|
||||||
'Class:ActionNotification/Attribute:language+' => '',
|
'Class:ActionNotification/Attribute:language+' => 'Language to use for placeholders ($xxx$) inside the message (state, importance, priority, etc)',
|
||||||
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Class: lnkActionNotificationToContact
|
||||||
|
//
|
||||||
|
|
||||||
|
Dict::Add('EN US', 'English', 'English', [
|
||||||
|
'Class:lnkActionNotificationToContact' => 'Link ActionNotification / Contact',
|
||||||
|
'Class:lnkActionNotificationToContact+' => 'Contact subscription to Notification Action',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id' => 'Contact',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id+' => 'Contact who subscribed (or not) to the notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id' => 'Action',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id+' => 'The notification that the contact received at least once, and to which he can subscribe or unsubscribe',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id' => 'Trigger',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id+' => 'The trigger that fired the notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed' => 'Subscribed',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed+' => 'If the contact unsubscribed (no) or is subscribed (yes and default) to the notification',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -545,7 +545,24 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
|||||||
'Class:ActionNotification' => 'Notification Action',
|
'Class:ActionNotification' => 'Notification Action',
|
||||||
'Class:ActionNotification+' => 'Notification Action (abstract)',
|
'Class:ActionNotification+' => 'Notification Action (abstract)',
|
||||||
'Class:ActionNotification/Attribute:language' => 'Language',
|
'Class:ActionNotification/Attribute:language' => 'Language',
|
||||||
'Class:ActionNotification/Attribute:language+' => '',
|
'Class:ActionNotification/Attribute:language+' => 'Language to use for placeholders ($xxx$) inside the message (state, importance, priority, etc)',
|
||||||
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Class: lnkActionNotificationToContact
|
||||||
|
//
|
||||||
|
|
||||||
|
Dict::Add('EN GB', 'British English', 'British English', [
|
||||||
|
'Class:lnkActionNotificationToContact' => 'Link ActionNotification / Contact',
|
||||||
|
'Class:lnkActionNotificationToContact+' => 'Contact subscription to Notification Action',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id' => 'Contact',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id+' => 'Contact who subscribed (or not) to the notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id' => 'Action',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id+' => 'The notification that the contact received at least once, and to which he can subscribe or unsubscribe',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id' => 'Trigger',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id+' => 'The trigger that fired the notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed' => 'Subscribed',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed+' => 'If the contact unsubscribed (no) or is subscribed (yes and default) to the notification',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -503,7 +503,24 @@ Dict::Add('FR FR', 'French', 'Français', [
|
|||||||
'Class:ActionNotification' => 'Action de notification',
|
'Class:ActionNotification' => 'Action de notification',
|
||||||
'Class:ActionNotification+' => '',
|
'Class:ActionNotification+' => '',
|
||||||
'Class:ActionNotification/Attribute:language' => 'Langue',
|
'Class:ActionNotification/Attribute:language' => 'Langue',
|
||||||
'Class:ActionNotification/Attribute:language+' => '',
|
'Class:ActionNotification/Attribute:language+' => 'Langue utilisée pour les placeholders ($xxx$) dans le message (statut, importance, priorité, etc)',
|
||||||
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Class: lnkActionNotificationToContact
|
||||||
|
//
|
||||||
|
|
||||||
|
Dict::Add('FR FR', 'French', 'Français', [
|
||||||
|
'Class:lnkActionNotificationToContact' => 'Lien Action de Notification / Contact',
|
||||||
|
'Class:lnkActionNotificationToContact+' => 'Abonnement des contacts aux notifications',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id' => 'Contact',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id+' => 'Contact abonné à la notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id' => 'Action',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id+' => 'La notification à laquelle le contact est abonné',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id' => 'Déclencheur',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id+' => 'Le déclencheur à l\'origine de cette notification',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed' => 'Abonné',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed+' => 'Si le contact est abonné ou non à cette notification',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -505,6 +505,23 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
|||||||
'Class:ActionNotification/Attribute:language+' => '',
|
'Class:ActionNotification/Attribute:language+' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Class: lnkActionNotificationToContact
|
||||||
|
//
|
||||||
|
|
||||||
|
Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||||
|
'Class:lnkActionNotificationToContact' => 'Link ActionNotification / Contact~~',
|
||||||
|
'Class:lnkActionNotificationToContact+' => 'Contact subscription to Notification Action~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id' => 'Contact~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:contact_id+' => 'Contact who subscribed (or not) to the notification~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id' => 'Action~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:action_id+' => 'The notification that the contact received at least once, and to which he can subscribe or unsubscribe~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id' => 'Trigger~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:trigger_id+' => 'The trigger that fired the notification~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed' => 'Subscribed~~',
|
||||||
|
'Class:lnkActionNotificationToContact/Attribute:subscribed+' => 'If the contact unsubscribed (no) or is subscribed (yes and default) to the notification~~',
|
||||||
|
]);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class: ActionEmail
|
// Class: ActionEmail
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -390,7 +390,8 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH
|
|||||||
|
|
||||||
this.RegisterChange = function () {
|
this.RegisterChange = function () {
|
||||||
// Listen only used inputs
|
// Listen only used inputs
|
||||||
$('#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]').off('change').on('change', function () {
|
$('body').off('change', '#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]')
|
||||||
|
.on('change', '#linkedset_'+me.id+' :input[name^="attr_'+me.sAttCode+'["]', function () {
|
||||||
if (!($(this).hasClass('selection')))
|
if (!($(this).hasClass('selection')))
|
||||||
{
|
{
|
||||||
let oCheckbox = $(this).closest('tr').find('.selection');
|
let oCheckbox = $(this).closest('tr').find('.selection');
|
||||||
|
|||||||
@@ -548,6 +548,7 @@ function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId, aForbidden
|
|||||||
if (sMessage)
|
if (sMessage)
|
||||||
{
|
{
|
||||||
$('#'+sFieldId).attr('data-tooltip-content', sMessage);
|
$('#'+sFieldId).attr('data-tooltip-content', sMessage);
|
||||||
|
$('#'+sFieldId).attr('data-tooltip-theme', 'error');
|
||||||
CombodoTooltip.InitTooltipFromMarkup($('#'+sFieldId), true);
|
CombodoTooltip.InitTooltipFromMarkup($('#'+sFieldId), true);
|
||||||
$('#'+sFieldId)[0]._tippy.show();
|
$('#'+sFieldId)[0]._tippy.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -595,13 +595,13 @@ EOF;
|
|||||||
$sMySQLCommand = $sCmd;
|
$sMySQLCommand = $sCmd;
|
||||||
} else {
|
} else {
|
||||||
$sMySQLBinDir = escapeshellcmd($sMySQLBinDir);
|
$sMySQLBinDir = escapeshellcmd($sMySQLBinDir);
|
||||||
$sMySQLCommand = '"'.$sMySQLBinDir.'/$sCmd"';
|
$sMySQLCommand = $sMySQLBinDir.'/'.$sCmd;
|
||||||
if (!file_exists($sMySQLCommand)) {
|
if (!file_exists($sMySQLCommand)) {
|
||||||
throw new BackupException("$sCmd not found in $sMySQLBinDir");
|
throw new BackupException("$sCmd not found in $sMySQLBinDir");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sMySQLCommand;
|
return '"'.$sMySQLCommand.'"';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,14 +70,37 @@ class MFException extends Exception
|
|||||||
* MFException constructor.
|
* MFException constructor.
|
||||||
*
|
*
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
|
*
|
||||||
|
* @param $message
|
||||||
|
* @param $code: error code
|
||||||
|
* @param $oNode: dom node
|
||||||
|
* @param $sXPath: XML xpath: if provided used in exception message. otherwise computed via $oNode
|
||||||
|
* @param $sExtraInfo: additional information stored in exception
|
||||||
|
* @param $oParentFallbackNode: fallback dom node (usually parent). in case $oNode XML line is wrong (set to 0), line number computed/displayed in error message comes from $oParentFallbackNode
|
||||||
*/
|
*/
|
||||||
public function __construct($message = null, $code = 0, $iSourceLineNumber = 0, $sXPath = '', $sExtraInfo = '', $previous = null)
|
public function __construct($message = null, $code = 0, $oNode, $sXPath = null, $sExtraInfo = '', $oParentFallbackNode = null)
|
||||||
{
|
{
|
||||||
parent::__construct($message, $code, $previous);
|
$iSourceLineNumber = ModelFactory::GetXMLLineNumber($oNode);
|
||||||
|
if ($iSourceLineNumber == 0 && ! is_null($oParentFallbackNode)) {
|
||||||
|
$iSourceLineNumber = ModelFactory::GetXMLLineNumber($oParentFallbackNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($sXPath)) {
|
||||||
|
$sXPath = DesignDocument::GetItopNodePath($oNode);
|
||||||
|
}
|
||||||
|
|
||||||
$this->iSourceLineNumber = $iSourceLineNumber;
|
$this->iSourceLineNumber = $iSourceLineNumber;
|
||||||
$this->iSourceLineOffset = 0;
|
$this->iSourceLineOffset = 0;
|
||||||
$this->sXPath = $sXPath;
|
$this->sXPath = $sXPath;
|
||||||
$this->sExtraInfo = $sExtraInfo;
|
$this->sExtraInfo = $sExtraInfo;
|
||||||
|
parent::__construct("$sXPath at line $iSourceLineNumber: $message", $code);
|
||||||
|
|
||||||
|
$aContext = [
|
||||||
|
'error' => $code,
|
||||||
|
'stack' => $this->getTraceAsString(),
|
||||||
|
'extra_info' => $sExtraInfo,
|
||||||
|
];
|
||||||
|
\IssueLog::Error($this->getMessage(), null, $aContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,6 +219,10 @@ class MFModule
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_dir($sRootDir)) {
|
||||||
|
$sRootDir = APPROOT.$sRootDir;
|
||||||
|
}
|
||||||
|
|
||||||
// Scan the module's root directory to find the datamodel(*).xml files
|
// Scan the module's root directory to find the datamodel(*).xml files
|
||||||
if ($hDir = opendir($sRootDir)) {
|
if ($hDir = opendir($sRootDir)) {
|
||||||
// This is the correct way to loop over the directory. (according to the documentation)
|
// This is the correct way to loop over the directory. (according to the documentation)
|
||||||
@@ -735,14 +762,7 @@ class ModelFactory
|
|||||||
case 'define_if_not_exists':
|
case 'define_if_not_exists':
|
||||||
/** @var \MFElement $oParentNode */
|
/** @var \MFElement $oParentNode */
|
||||||
$oParentNode = $oSubClassNode->parentNode;
|
$oParentNode = $oSubClassNode->parentNode;
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oParentNode);
|
throw new MFException("_delta=\"$sParentDeltaSpec\" not supported for classes in hierarchy", MFException::NOT_FOUND, $oParentNode);
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oParentNode);
|
|
||||||
throw new MFException(
|
|
||||||
"$sItopNodePath at line $iLine: _delta=\"$sParentDeltaSpec\" not supported for classes in hierarchy",
|
|
||||||
MFException::NOT_FOUND,
|
|
||||||
$iLine,
|
|
||||||
$sItopNodePath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -798,14 +818,7 @@ class ModelFactory
|
|||||||
// Move class after new parent class (before its next sibling)
|
// Move class after new parent class (before its next sibling)
|
||||||
$oNodeForTargetParent = $oTargetDocument->GetNodes("/itop_design/classes/class[@id=\"$sParentClassName\"]")->item(0);
|
$oNodeForTargetParent = $oTargetDocument->GetNodes("/itop_design/classes/class[@id=\"$sParentClassName\"]")->item(0);
|
||||||
if (is_null($oNodeForTargetParent)) {
|
if (is_null($oNodeForTargetParent)) {
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oSourceParentClassNode);
|
throw new MFException("invalid parent class '$sParentClassName'", MFException::NOT_FOUND, $oSourceParentClassNode);
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceParentClassNode);
|
|
||||||
throw new MFException(
|
|
||||||
$sItopNodePath." at line $iLine: invalid parent class '$sParentClassName'",
|
|
||||||
MFException::NOT_FOUND,
|
|
||||||
$iLine,
|
|
||||||
$sItopNodePath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$oNextParentSibling = $oNodeForTargetParent->nextSibling;
|
$oNextParentSibling = $oNodeForTargetParent->nextSibling;
|
||||||
if ($oNextParentSibling) {
|
if ($oNextParentSibling) {
|
||||||
@@ -833,29 +846,14 @@ class ModelFactory
|
|||||||
if (!$oTargetNode || $oTargetNode->IsRemoved()) {
|
if (!$oTargetNode || $oTargetNode->IsRemoved()) {
|
||||||
// The node does not exist or is marked as removed
|
// The node does not exist or is marked as removed
|
||||||
if ($bMustExist) {
|
if ($bMustExist) {
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
|
throw new MFException("could not be found or marked as removed", MFException::NOT_FOUND, $oSourceNode);
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
|
|
||||||
throw new MFException(
|
|
||||||
$sItopNodePath.' at line '.$iLine.': could not be found or marked as removed',
|
|
||||||
MFException::NOT_FOUND,
|
|
||||||
$iLine,
|
|
||||||
$sItopNodePath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ($bIfExists) {
|
if ($bIfExists) {
|
||||||
// Do not continue deeper
|
// Do not continue deeper
|
||||||
$oTargetNode = null;
|
$oTargetNode = null;
|
||||||
} else {
|
} else {
|
||||||
if (!$bSpecifiedMerge && $sMode === self::LOAD_DELTA_MODE_STRICT && ($sSearchId !== '' || is_null($oSourceNode->GetFirstElementChild()))) {
|
if (!$bSpecifiedMerge && $sMode === self::LOAD_DELTA_MODE_STRICT && ($sSearchId !== '' || is_null($oSourceNode->GetFirstElementChild()))) {
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
|
throw new MFException("could not be found or marked as removed (strict mode)", MFException::NOT_FOUND, $oSourceNode, null, 'strict mode');
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
|
|
||||||
throw new MFException(
|
|
||||||
$sItopNodePath.' at line '.$iLine.': could not be found or marked as removed (strict mode)',
|
|
||||||
MFException::NOT_FOUND,
|
|
||||||
$iLine,
|
|
||||||
$sItopNodePath,
|
|
||||||
'strict mode'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore renaming non-existant node
|
// Ignore renaming non-existant node
|
||||||
@@ -904,15 +902,7 @@ class ModelFactory
|
|||||||
if (is_null($oSourceNode->GetFirstElementChild()) && $oTargetParentNode instanceof MFElement) {
|
if (is_null($oSourceNode->GetFirstElementChild()) && $oTargetParentNode instanceof MFElement) {
|
||||||
// Leaf node
|
// Leaf node
|
||||||
if ($sMode === self::LOAD_DELTA_MODE_STRICT && !$oSourceNode->hasAttribute('_rename_from') && trim($oSourceNode->GetText('')) !== '') {
|
if ($sMode === self::LOAD_DELTA_MODE_STRICT && !$oSourceNode->hasAttribute('_rename_from') && trim($oSourceNode->GetText('')) !== '') {
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oSourceNode);
|
throw new MFException("cannot be modified without _delta flag (strict mode)", MFException::AMBIGUOUS_LEAF, $oSourceNode, null, 'strict mode');
|
||||||
$sItopNodePath = DesignDocument::GetItopNodePath($oSourceNode);
|
|
||||||
throw new MFException(
|
|
||||||
$sItopNodePath.' at line '.$iLine.': cannot be modified without _delta flag (strict mode)',
|
|
||||||
MFException::AMBIGUOUS_LEAF,
|
|
||||||
$iLine,
|
|
||||||
$sItopNodePath,
|
|
||||||
'strict mode'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Lax mode: same as redefine
|
// Lax mode: same as redefine
|
||||||
// Replace the existing node by the given node - copy child nodes as well
|
// Replace the existing node by the given node - copy child nodes as well
|
||||||
@@ -920,7 +910,7 @@ class ModelFactory
|
|||||||
if (trim($oSourceNode->GetText('')) !== '') {
|
if (trim($oSourceNode->GetText('')) !== '') {
|
||||||
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
|
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
|
||||||
$sSearchId = $oSourceNode->hasAttribute('_rename_from') ? $oSourceNode->getAttribute('_rename_from') : $oSourceNode->getAttribute('id');
|
$sSearchId = $oSourceNode->hasAttribute('_rename_from') ? $oSourceNode->getAttribute('_rename_from') : $oSourceNode->getAttribute('id');
|
||||||
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId);
|
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId, $oSourceNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -964,7 +954,7 @@ class ModelFactory
|
|||||||
// Replace the existing node by the given node - copy child nodes as well
|
// Replace the existing node by the given node - copy child nodes as well
|
||||||
/** @var \MFElement $oTargetNode */
|
/** @var \MFElement $oTargetNode */
|
||||||
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
|
$oTargetNode = $oTargetDocument->importNode($oSourceNode, true);
|
||||||
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId);
|
$oTargetParentNode->RedefineChildNode($oTargetNode, $sSearchId, $oSourceNode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'delete_if_exists':
|
case 'delete_if_exists':
|
||||||
@@ -984,38 +974,18 @@ class ModelFactory
|
|||||||
case 'delete':
|
case 'delete':
|
||||||
/** @var \MFElement $oTargetNode */
|
/** @var \MFElement $oTargetNode */
|
||||||
$oTargetNode = $oTargetParentNode->_FindChildNode($oSourceNode, $sSearchId);
|
$oTargetNode = $oTargetParentNode->_FindChildNode($oSourceNode, $sSearchId);
|
||||||
$sPath = MFDocument::GetItopNodePath($oSourceNode);
|
|
||||||
$iLine = $this->GetXMLLineNumber($oSourceNode);
|
|
||||||
|
|
||||||
if ($oTargetNode == null) {
|
if ($oTargetNode == null) {
|
||||||
throw new MFException(
|
throw new MFException("could not be deleted (not found)", MFException::COULD_NOT_BE_DELETED, $oSourceNode);
|
||||||
$sPath.' at line '.$iLine.": could not be deleted (not found)",
|
|
||||||
MFException::COULD_NOT_BE_DELETED,
|
|
||||||
$iLine,
|
|
||||||
$sPath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ($oTargetNode->IsRemoved()) {
|
if ($oTargetNode->IsRemoved()) {
|
||||||
throw new MFException(
|
throw new MFException("could not be deleted (already marked as deleted)", MFException::ALREADY_DELETED, $oSourceNode);
|
||||||
$sPath.' at line '.$iLine.": could not be deleted (already marked as deleted)",
|
|
||||||
MFException::ALREADY_DELETED,
|
|
||||||
$iLine,
|
|
||||||
$sPath
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$oTargetNode->Delete();
|
$oTargetNode->Delete();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$sPath = MFDocument::GetItopNodePath($oSourceNode);
|
throw new MFException("unexpected value for attribute _delta: '".$sDeltaSpec."'", MFException::INVALID_DELTA, $oSourceNode, null, $sDeltaSpec);
|
||||||
$iLine = $this->GetXMLLineNumber($oSourceNode);
|
|
||||||
throw new MFException(
|
|
||||||
$sPath.' at line '.$iLine.": unexpected value for attribute _delta: '".$sDeltaSpec."'",
|
|
||||||
MFException::INVALID_DELTA,
|
|
||||||
$iLine,
|
|
||||||
$sPath,
|
|
||||||
$sDeltaSpec
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oTargetNode && $oTargetNode->parentNode) {
|
if ($oTargetNode && $oTargetNode->parentNode) {
|
||||||
@@ -2116,14 +2086,12 @@ class MFElement extends Combodo\iTop\DesignElement
|
|||||||
$oExisting = $this->_FindChildNode($oNode);
|
$oExisting = $this->_FindChildNode($oNode);
|
||||||
if ($oExisting) {
|
if ($oExisting) {
|
||||||
if (!$oExisting->IsRemoved()) {
|
if (!$oExisting->IsRemoved()) {
|
||||||
$sPath = MFDocument::GetItopNodePath($oNode);
|
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oNode);
|
|
||||||
$sExistingPath = MFDocument::GetItopNodePath($oExisting).' created_in: ['.$oExisting->getAttribute('_created_in').']';
|
$sExistingPath = MFDocument::GetItopNodePath($oExisting).' created_in: ['.$oExisting->getAttribute('_created_in').']';
|
||||||
$iExistingLine = ModelFactory::GetXMLLineNumber($oExisting);
|
$iExistingLine = ModelFactory::GetXMLLineNumber($oExisting);
|
||||||
$sExceptionMessage = <<<EOF
|
$sExceptionMessage = <<<EOF
|
||||||
`{$sPath}` at line {$iLine} could not be added : already exists in `{$sExistingPath}` at line {$iExistingLine}
|
could not be added : already exists in `{$sExistingPath}` at line {$iExistingLine}
|
||||||
EOF;
|
EOF;
|
||||||
throw new MFException($sExceptionMessage, MFException::COULD_NOT_BE_ADDED, $iLine, $sPath);
|
throw new MFException($sExceptionMessage, MFException::COULD_NOT_BE_ADDED, $oNode);
|
||||||
}
|
}
|
||||||
$oExisting->ReplaceWithSingleNode($oNode);
|
$oExisting->ReplaceWithSingleNode($oNode);
|
||||||
$sFlag = 'replaced';
|
$sFlag = 'replaced';
|
||||||
@@ -2141,13 +2109,14 @@ EOF;
|
|||||||
*
|
*
|
||||||
* @param MFElement $oNode The node (including all subnodes) to set
|
* @param MFElement $oNode The node (including all subnodes) to set
|
||||||
* @param string|null $sSearchId
|
* @param string|null $sSearchId
|
||||||
|
* @param mixed $oParentFallbackNode: provided to print accurate line number in case $oNode line is 0
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*
|
*
|
||||||
* @throws MFException
|
* @throws MFException
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function RedefineChildNode(MFElement $oNode, $sSearchId = null)
|
public function RedefineChildNode(MFElement $oNode, $sSearchId = null, $oParentFallbackNode = null)
|
||||||
{
|
{
|
||||||
// First: cleanup any flag behind the new node, and eventually add trace data
|
// First: cleanup any flag behind the new node, and eventually add trace data
|
||||||
$oNode->ApplyChanges();
|
$oNode->ApplyChanges();
|
||||||
@@ -2156,25 +2125,13 @@ EOF;
|
|||||||
$oExisting = $this->_FindChildNode($oNode, $sSearchId);
|
$oExisting = $this->_FindChildNode($oNode, $sSearchId);
|
||||||
if (!$oExisting) {
|
if (!$oExisting) {
|
||||||
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
|
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oNode);
|
throw new MFException('could not be modified (not found)', MFException::COULD_NOT_BE_MODIFIED_NOT_FOUND, $oNode, $sPath, $oParentFallbackNode);
|
||||||
throw new MFException(
|
|
||||||
$sPath." at line $iLine: could not be modified (not found)",
|
|
||||||
MFException::COULD_NOT_BE_MODIFIED_NOT_FOUND,
|
|
||||||
$sPath,
|
|
||||||
$iLine
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$sPrevFlag = $oExisting->GetAlteration();
|
$sPrevFlag = $oExisting->GetAlteration();
|
||||||
$sOldId = $oExisting->getAttribute('_old_id');
|
$sOldId = $oExisting->getAttribute('_old_id');
|
||||||
if ($oExisting->IsRemoved()) {
|
if ($oExisting->IsRemoved()) {
|
||||||
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
|
$sPath = MFDocument::GetItopNodePath($this)."/".$oNode->tagName.(empty($sSearchId) ? '' : "[$sSearchId]");
|
||||||
$iLine = ModelFactory::GetXMLLineNumber($oNode);
|
throw new MFException('could not be modified (marked as deleted)', MFException::COULD_NOT_BE_MODIFIED_ALREADY_DELETED, $oNode, $sPath, $oParentFallbackNode);
|
||||||
throw new MFException(
|
|
||||||
$sPath." at line $iLine: could not be modified (marked as deleted)",
|
|
||||||
MFException::COULD_NOT_BE_MODIFIED_ALREADY_DELETED,
|
|
||||||
$sPath,
|
|
||||||
$iLine
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$oExisting->ReplaceWithSingleNode($oNode);
|
$oExisting->ReplaceWithSingleNode($oNode);
|
||||||
if (!$this->IsInDefinition()) {
|
if (!$this->IsInDefinition()) {
|
||||||
|
|||||||
@@ -130,9 +130,6 @@ class ModuleDiscovery
|
|||||||
$aArgs['module_file'] = $sFilePath;
|
$aArgs['module_file'] = $sFilePath;
|
||||||
|
|
||||||
list($sModuleName, $sModuleVersion) = static::GetModuleName($sId);
|
list($sModuleName, $sModuleVersion) = static::GetModuleName($sId);
|
||||||
if ($sModuleVersion == '') {
|
|
||||||
$sModuleVersion = '1.0.0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists($sModuleName, self::$m_aModuleVersionByName)) {
|
if (array_key_exists($sModuleName, self::$m_aModuleVersionByName)) {
|
||||||
if (version_compare($sModuleVersion, self::$m_aModuleVersionByName[$sModuleName]['version'], '>')) {
|
if (version_compare($sModuleVersion, self::$m_aModuleVersionByName[$sModuleName]['version'], '>')) {
|
||||||
@@ -229,7 +226,7 @@ class ModuleDiscovery
|
|||||||
}
|
}
|
||||||
ksort($aDependencies);
|
ksort($aDependencies);
|
||||||
$aOrderedModules = [];
|
$aOrderedModules = [];
|
||||||
$iLoopCount = 1;
|
$iLoopCount = 0;
|
||||||
while (($iLoopCount < count($aModules)) && (count($aDependencies) > 0)) {
|
while (($iLoopCount < count($aModules)) && (count($aDependencies) > 0)) {
|
||||||
foreach ($aDependencies as $sId => $aRemainingDeps) {
|
foreach ($aDependencies as $sId => $aRemainingDeps) {
|
||||||
$bDependenciesSolved = true;
|
$bDependenciesSolved = true;
|
||||||
@@ -301,13 +298,8 @@ class ModuleDiscovery
|
|||||||
$aModuleVersions = [];
|
$aModuleVersions = [];
|
||||||
// Separate the module names from their version for an easier comparison later
|
// Separate the module names from their version for an easier comparison later
|
||||||
foreach ($aOrderedModules as $sModuleId) {
|
foreach ($aOrderedModules as $sModuleId) {
|
||||||
$aMatches = [];
|
list($sModuleName, $sVersion) = self::GetModuleName($sModuleId);
|
||||||
if (preg_match('|^([^/]+)/(.*)$|', $sModuleId, $aMatches)) {
|
$aModuleVersions[$sModuleName] = $sVersion;
|
||||||
$aModuleVersions[$aMatches[1]] = $aMatches[2];
|
|
||||||
} else {
|
|
||||||
// No version number found, assume 1.0.0
|
|
||||||
$aModuleVersions[$sModuleId] = '1.0.0';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (preg_match_all('/([^\(\)&| ]+)/', $sDepString, $aMatches)) {
|
if (preg_match_all('/([^\(\)&| ]+)/', $sDepString, $aMatches)) {
|
||||||
$aReplacements = [];
|
$aReplacements = [];
|
||||||
@@ -422,10 +414,14 @@ class ModuleDiscovery
|
|||||||
if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches)) {
|
if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches)) {
|
||||||
$sName = $aMatches[1];
|
$sName = $aMatches[1];
|
||||||
$sVersion = $aMatches[2];
|
$sVersion = $aMatches[2];
|
||||||
|
if ($sVersion === "") {
|
||||||
|
$sVersion = "1.0.0";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$sName = $sModuleId;
|
$sName = $sModuleId;
|
||||||
$sVersion = "";
|
$sVersion = "1.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$sName, $sVersion];
|
return [$sName, $sVersion];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -632,6 +632,7 @@ JS;
|
|||||||
$aResult['data'] = ['error_message' => $e->getHtmlMessage()];
|
$aResult['data'] = ['error_message' => $e->getHtmlMessage()];
|
||||||
} else {
|
} else {
|
||||||
$oPage->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
|
$oPage->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
|
||||||
|
$oObj->Reload();
|
||||||
$oObj->DisplayModifyForm(
|
$oObj->DisplayModifyForm(
|
||||||
$oPage,
|
$oPage,
|
||||||
['wizard_container' => true]
|
['wizard_container' => true]
|
||||||
|
|||||||
@@ -2400,7 +2400,9 @@ class SynchroReplica extends DBObject implements iDisplay
|
|||||||
}
|
}
|
||||||
// Really modified ?
|
// Really modified ?
|
||||||
if ($oDestObj->IsModified()) {
|
if ($oDestObj->IsModified()) {
|
||||||
|
if (method_exists(get_class($oDestObj), "SetCurrentChange")) {
|
||||||
$oDestObj::SetCurrentChange($oChange);
|
$oDestObj::SetCurrentChange($oChange);
|
||||||
|
}
|
||||||
$oDestObj->DBUpdate();
|
$oDestObj->DBUpdate();
|
||||||
$bModified = true;
|
$bModified = true;
|
||||||
$oStatLog->AddTrace('Updated object - Values: {'.implode(', ', $aValueTrace).'}', $this);
|
$oStatLog->AddTrace('Updated object - Values: {'.implode(', ', $aValueTrace).'}', $this);
|
||||||
@@ -2450,7 +2452,10 @@ class SynchroReplica extends DBObject implements iDisplay
|
|||||||
$aValueTrace[] = "$sAttCode: $value";
|
$aValueTrace[] = "$sAttCode: $value";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method_exists(get_class($oDestObj), "SetCurrentChange")) {
|
||||||
$oDestObj::SetCurrentChange($oChange);
|
$oDestObj::SetCurrentChange($oChange);
|
||||||
|
}
|
||||||
$iNew = $oDestObj->DBInsert();
|
$iNew = $oDestObj->DBInsert();
|
||||||
|
|
||||||
$this->Set('dest_id', $oDestObj->GetKey());
|
$this->Set('dest_id', $oDestObj->GetKey());
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Combodo\iTop\Test\UnitTest\Setup;
|
||||||
|
|
||||||
|
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||||
|
|
||||||
|
class ModuleDiscoveryTest extends ItopTestCase
|
||||||
|
{
|
||||||
|
public function GetModuleNameProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'nominal' => [
|
||||||
|
'sModuleId' => 'a/1.2.3',
|
||||||
|
'name' => 'a',
|
||||||
|
'version' => '1.2.3',
|
||||||
|
],
|
||||||
|
'develop' => [
|
||||||
|
'sModuleId' => 'a/1.2.3-dev',
|
||||||
|
'name' => 'a',
|
||||||
|
'version' => '1.2.3-dev',
|
||||||
|
],
|
||||||
|
'missing version => 1.0.0' => [
|
||||||
|
'sModuleId' => 'a/',
|
||||||
|
'name' => 'a',
|
||||||
|
'version' => '1.0.0',
|
||||||
|
],
|
||||||
|
'missing everything except name' => [
|
||||||
|
'sModuleId' => 'a',
|
||||||
|
'name' => 'a',
|
||||||
|
'version' => '1.0.0',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->RequireOnceItopFile('setup/modulediscovery.class.inc.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider GetModuleNameProvider
|
||||||
|
*/
|
||||||
|
public function testGetModuleName($sModuleId, $expectedName, $expectedVersion)
|
||||||
|
{
|
||||||
|
$this->assertEquals([$expectedName, $expectedVersion], \ModuleDiscovery::GetModuleName($sModuleId));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user