mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-22 16:52:16 +02:00
Compare commits
2 Commits
feature/95
...
faf/data_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f26d7e2c8d | ||
|
|
4aa1f8ae18 |
@@ -5356,6 +5356,7 @@ JS
|
||||
/**
|
||||
* @param array $aChanges
|
||||
* @param bool $bIsNew
|
||||
* @param string|null $sStimulusBeingApplied
|
||||
*
|
||||
* @return void
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -5369,6 +5370,21 @@ JS
|
||||
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges, 'stimulus_applied' => $sStimulusBeingApplied, 'cmdb_change' => self::GetCurrentChange()]);
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// READ
|
||||
///
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @since 3.3.0
|
||||
*/
|
||||
final public function FireEventReadDetails(): void
|
||||
{
|
||||
|
||||
$this->FireEvent(EVENT_DB_TRACEABILITY);
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// DELETE
|
||||
///
|
||||
|
||||
@@ -519,6 +519,27 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DATA_EXPORT" _delta="define">
|
||||
<name>Object details read from outside iTop</name>
|
||||
<description><![CDATA[An object details has been read during an export]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object unarchived</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="attributes">
|
||||
<description>Attribute codes exposed (empty means all attributes)</description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DOWNLOAD_DOCUMENT" _delta="define">
|
||||
<name>Document downloaded</name>
|
||||
<description><![CDATA[A document has been downloaded from the GUI]]></description>
|
||||
|
||||
@@ -340,6 +340,7 @@ EOF
|
||||
|
||||
$sField = '';
|
||||
$oObj = $aRow[$sAlias];
|
||||
$oObj->FireEventReadDetails();
|
||||
if ($oObj != null) {
|
||||
switch ($sAttCode) {
|
||||
case 'id':
|
||||
|
||||
@@ -6247,7 +6247,9 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aChanges
|
||||
* @param bool $bIsNew
|
||||
* @param string|null $sStimulusBeingApplied
|
||||
*
|
||||
* @return void
|
||||
* @since 3.1.0
|
||||
@@ -6256,6 +6258,18 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// READ
|
||||
///
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public function FireEventReadDetails(): void
|
||||
{
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// DELETE
|
||||
///
|
||||
|
||||
@@ -293,6 +293,7 @@ EOF
|
||||
$sAttCode = $aFieldSpec['sAttCode'];
|
||||
|
||||
$oObj = $aRow[$sAlias];
|
||||
$oObj->FireEventReadDetails();
|
||||
$sField = '';
|
||||
if ($oObj) {
|
||||
$sField = $this->GetValue($oObj, $sAttCode);
|
||||
|
||||
@@ -144,6 +144,7 @@ class HTMLBulkExport extends TabularBulkExport
|
||||
$sAttCode = $aFieldSpec['sAttCode'];
|
||||
|
||||
$oObj = $aRow[$sAlias];
|
||||
$oObj->FireEventReadDetails();
|
||||
$sField = '';
|
||||
if ($oObj) {
|
||||
$sField = $this->GetValue($oObj, $sAttCode);
|
||||
|
||||
@@ -531,6 +531,7 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
|
||||
}
|
||||
|
||||
while ($oObject = $oObjectSet->Fetch()) {
|
||||
$oObject->FireEventReadDetails();
|
||||
$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
|
||||
}
|
||||
$oResult->message = "Found: ".$oObjectSet->Count();
|
||||
@@ -605,6 +606,7 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
|
||||
if ($oElement instanceof RelationObjectNode) {
|
||||
$oObject = $oElement->GetProperty('object');
|
||||
if ($oObject) {
|
||||
$oObject->FireEventReadDetails();
|
||||
if ($bEnableRedundancy && $sDirection == 'down') {
|
||||
// Add only the "reached" objects
|
||||
if ($oElement->GetProperty('is_reached')) {
|
||||
|
||||
@@ -233,7 +233,6 @@ EOF
|
||||
public function GetNextChunk(&$aStatus)
|
||||
{
|
||||
$sRetCode = 'run';
|
||||
$iPercentage = 0;
|
||||
|
||||
$oSet = new DBObjectSet($this->oSearch);
|
||||
$oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']);
|
||||
@@ -261,6 +260,7 @@ EOF
|
||||
$sField = '';
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aRow[$sAlias];
|
||||
$oObj->FireEventReadDetails();
|
||||
if ($oObj == null) {
|
||||
$sData .= "<td x:str></td>";
|
||||
continue;
|
||||
|
||||
@@ -146,6 +146,7 @@ class XMLBulkExport extends BulkExport
|
||||
}
|
||||
foreach ($aAuthorizedClasses as $sAlias => $sClassName) {
|
||||
$oObj = $aObjects[$sAlias];
|
||||
$oObj->FireEventReadDetails();
|
||||
if (is_null($oObj)) {
|
||||
$sData .= "<$sClassName alias=\"$sAlias\" id=\"null\">\n";
|
||||
} else {
|
||||
|
||||
@@ -1480,19 +1480,19 @@
|
||||
<cell id="1" _delta="must_exist">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="ContainerApplication" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_43" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>5</rank>
|
||||
<class>ContainerApplication</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerHost" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_44" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>6</rank>
|
||||
<class>ContainerHost</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerCluster" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_45" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>7</rank>
|
||||
<class>ContainerCluster</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerImage" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_46" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>8</rank>
|
||||
<class>ContainerImage</class>
|
||||
</dashlet>
|
||||
@@ -1507,11 +1507,11 @@
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="ContainerType" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_21" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>21</rank>
|
||||
<class>ContainerType</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerImageType" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_22" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>22</rank>
|
||||
<class>ContainerImageType</class>
|
||||
</dashlet>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||
<classes>
|
||||
<class id="DataFlow" _delta="define">
|
||||
<parent>FunctionalCI</parent>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
@@ -14,10 +14,6 @@
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
<complementary_attributes>
|
||||
<attribute id="source_id"/>
|
||||
<attribute id="destination_id"/>
|
||||
</complementary_attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
@@ -36,9 +32,23 @@
|
||||
</fields_semantic>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="org_id" xsi:type="AttributeExternalKey">
|
||||
<sql>org_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>Organization</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="source_id" xsi:type="AttributeExternalKey">
|
||||
<sql>source_id</sql>
|
||||
<filter><![CDATA[SELECT FunctionalCI WHERE finalclass != 'DataFlow']]></filter>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
@@ -64,7 +74,7 @@
|
||||
</field>
|
||||
<field id="destination_id" xsi:type="AttributeExternalKey">
|
||||
<sql>destination_id</sql>
|
||||
<filter><![CDATA[SELECT FunctionalCI WHERE finalclass != 'DataFlow']]></filter>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
@@ -97,6 +107,12 @@
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="description" xsi:type="AttributeHTML">
|
||||
<sql>description</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sql>status</sql>
|
||||
<values>
|
||||
@@ -125,6 +141,27 @@
|
||||
<display_style>list</display_style>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="business_criticity" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="high">
|
||||
<code>high</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="medium">
|
||||
<code>medium</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
<value id="low">
|
||||
<code>low</code>
|
||||
<rank>30</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>business_criticity</sql>
|
||||
<default_value>low</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="execution_frequency" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
@@ -162,36 +199,24 @@
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="contacts_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkContactToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>contact_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
<field id="documents_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkDocumentToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>document_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
</fields>
|
||||
<event_listeners>
|
||||
<event_listener id="evtCheckSourceAndDestination">
|
||||
<event>EVENT_DB_CHECK_TO_WRITE</event>
|
||||
<rank>10</rank>
|
||||
<callback>evtCheckSourceAndDestination</callback>
|
||||
</event_listener>
|
||||
</event_listeners>
|
||||
<methods>
|
||||
<method id="evtCheckSourceAndDestination" _delta="define">
|
||||
<comment> /**
|
||||
* Ensure that the source and destination of a data flow are not DataFlow themselves
|
||||
*
|
||||
*/</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>EventListener</type>
|
||||
<code><![CDATA[ public function evtCheckSourceAndDestination(Combodo\iTop\Service\Events\EventData $oEventData)
|
||||
{
|
||||
$oSource = MetaModel::GetObject(FunctionalCI::class, $this->Get('source_id'), false, true);
|
||||
$oDestination = MetaModel::GetObject(FunctionalCI::class, $this->Get('destination_id'), false, true);
|
||||
if ($oSource instanceof DataFlow) {
|
||||
$this->AddCheckIssue(Dict::Format('Class:DataFlow/Error:CheckSource', $oSource->GetName()));
|
||||
}
|
||||
if ($oDestination instanceof DataFlow) {
|
||||
$this->AddCheckIssue(Dict::Format('Class:DataFlow/Error:CheckDestination', $oDestination->GetName()));
|
||||
}
|
||||
} ]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items>
|
||||
@@ -232,7 +257,7 @@
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:ConfigMgmt:baseinfo">
|
||||
<item id="fieldset:DataFlow:baseinfo">
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
@@ -277,24 +302,13 @@
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
<items>
|
||||
<item id="fieldset:ConfigMgmt:dates">
|
||||
<items>
|
||||
<item id="move2production">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="fieldset:ConfigMgmt:otherinfo">
|
||||
<item id="fieldset:DataFlow:otherinfo">
|
||||
<items>
|
||||
<item id="description">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="groups_list">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
@@ -328,46 +342,201 @@
|
||||
</default_search>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="business_criticity">
|
||||
<item id="org_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_id">
|
||||
<item id="description">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="execution_frequency">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<relations>
|
||||
<relation id="impacts">
|
||||
<neighbours>
|
||||
<neighbour id="functionalci">
|
||||
<neighbour id="functionalci ">
|
||||
<query_down><![CDATA[SELECT FunctionalCI WHERE :this->destination_impact = 'yes' AND id = :this->destination_id]]></query_down>
|
||||
<query_up><![CDATA[SELECT DataFlow AS f JOIN FunctionalCI AS ci ON f.destination_id = ci.id WHERE f.destination_impact = 'yes' AND ci.id=:this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
<neighbour id="contact">
|
||||
<neighbour id="contact ">
|
||||
<attribute>contacts_list</attribute>
|
||||
<direction>down</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
<relation id="dataflows">
|
||||
<neighbours>
|
||||
<neighbour id="functionalci">
|
||||
<query_down><![CDATA[SELECT FunctionalCI WHERE id = :this->destination_id]]></query_down>
|
||||
<query_up><![CDATA[SELECT DataFlow AS f WHERE f.destination_id = :this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="lnkDocumentToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkdocumenttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="document_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="document_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="document_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="document_id" xsi:type="AttributeExternalKey">
|
||||
<sql>document_id</sql>
|
||||
<target_class>Document</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="document_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="lnkContactToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkcontacttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="contact_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="contact_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="contact_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="DataFlowType" _delta="define">
|
||||
<parent>Typology</parent>
|
||||
<properties>
|
||||
@@ -385,16 +554,6 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="name">
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields/>
|
||||
<methods/>
|
||||
@@ -470,15 +629,6 @@
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
<relation id="dataflows" _delta="define">
|
||||
<neighbours>
|
||||
<neighbour id="flow">
|
||||
<query_down><![CDATA[SELECT DataFlow WHERE source_id = :this->id]]></query_down>
|
||||
<query_up><![CDATA[SELECT FunctionalCI AS ci JOIN DataFlow AS f ON f.source_id = ci.id WHERE f.id = :this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="ApplicationSolution" _delta="must_exist">
|
||||
@@ -576,7 +726,7 @@
|
||||
<cells>
|
||||
<cell id="3" delta="if_exists">
|
||||
<dashlets>
|
||||
<dashlet id="DataFlow" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="DataFlow_20" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>20</rank>
|
||||
<class>DataFlow</class>
|
||||
</dashlet>
|
||||
@@ -585,21 +735,6 @@
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
<menu id="Typology" xsi:type="DashboardMenuNode" _delta="must_exist">
|
||||
<definition>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="DataFlowType" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>23</rank>
|
||||
<class>DataFlowType</class>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
</menus>
|
||||
<user_rights>
|
||||
<groups>
|
||||
|
||||
@@ -9,25 +9,21 @@
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
|
||||
'Relation:dataflows/Description' => 'DataFlows between CIs',
|
||||
'Relation:dataflows/DownStream' => 'Outbound flows...',
|
||||
'Relation:dataflows/DownStream+' => 'Outbound flows map from',
|
||||
'Relation:dataflows/UpStream' => 'Inbound flows...',
|
||||
'Relation:dataflows/UpStream+' => 'Inbound flows map to',
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Data flows',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Data flows for which this object is the source or the destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Data flows',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Inbound flows',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Outbound flows',
|
||||
|
||||
'DataFlow:baseinfo' => 'General information',
|
||||
'DataFlow:otherinfo' => 'Other information',
|
||||
'DataFlow:moreinfo' => 'Flow specifics',
|
||||
|
||||
'Class:DataFlow' => 'Flow',
|
||||
'Class:DataFlow+' => 'For application flow for example',
|
||||
'Class:DataFlow/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Name',
|
||||
'Class:DataFlow/Attribute:name+' => 'Identify the transferred data flow',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Data that are transferred',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Source Ci of the flow',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impacts?',
|
||||
@@ -46,10 +42,22 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'If the flow stops, the destination is not impacted',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Flow type',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typology of Flow.',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Status',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'active',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactive',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organization',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Business criticality',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'high',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'low',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'medium',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Execution frequency',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'How often the data flow is executed',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'real-time',
|
||||
@@ -66,13 +74,10 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'yearly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
'Class:DataFlow/Error:CheckSource' => 'The source of a data flow cannot be a data flow itself. Choose another source CI than %1$s',
|
||||
'Class:DataFlow/Error:CheckDestination' => 'The destination of a data flow cannot be a data flow itself. Choose another destination CI than %1$s',
|
||||
|
||||
'Class:DataFlowType' => 'Data Flow Type',
|
||||
'Class:DataFlowType+' => 'Typology of Data Flow',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
|
||||
@@ -9,25 +9,21 @@
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
|
||||
'Relation:dataflows/Description' => 'Flux de données entre CIs',
|
||||
'Relation:dataflows/DownStream' => 'Flux sortants...',
|
||||
'Relation:dataflows/DownStream+' => 'Carte des flux sortants depuis',
|
||||
'Relation:dataflows/UpStream' => 'Flux entrants...',
|
||||
'Relation:dataflows/UpStream+' => 'Carte des flux entrants vers',
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Flux de données',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Flux de données dont cet objet est la source ou la destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Flux de données',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Flux entrants',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Flux sortants',
|
||||
|
||||
'DataFlow:baseinfo' => 'Informations générales',
|
||||
'DataFlow:otherinfo' => 'Autres informations',
|
||||
'DataFlow:moreinfo' => 'Spécificités du flux',
|
||||
|
||||
'Class:DataFlow' => 'Flux de Données',
|
||||
'Class:DataFlow+' => 'Modélise les données transférées entre instances d\'application ou plus généralement entre CIs.',
|
||||
'Class:DataFlow/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:DataFlow+' => 'Modélise les données transférées entre instances d\'application',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Nom',
|
||||
'Class:DataFlow/Attribute:name+' => 'Identifie le flux de données',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Type de données transferées',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Instance d\application à la source du flux de données',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impactante ?',
|
||||
@@ -46,10 +42,22 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'Si le flux s\'arrête, le destinataire n\'est pas impacté',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Type de flux',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typologie du flux',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Etat',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'actif',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactif',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organisation',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Criticité',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'haute',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'basse',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'moyenne',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Fréquence d\'exécution',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'À quelle fréquence le transfert de données est-il exécuté',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'temps réel',
|
||||
@@ -66,13 +74,10 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'annuelle',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
'Class:DataFlow/Error:CheckSource' => 'La source d\'un flux de données ne peut pas être un flux de données elle-même. Choisissez un autre CI source que %1$s',
|
||||
'Class:DataFlow/Error:CheckDestination' => 'La destination d\'un flux de données ne peut pas être un flux de données elle-même. Choisissez un autre CI destination que %1$s',
|
||||
|
||||
'Class:DataFlowType' => 'Type de flux',
|
||||
'Class:DataFlowType+' => 'Typologie des flux de données',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
|
||||
@@ -56,13 +56,46 @@ class TicketsInstaller extends ModuleInstallerAPI
|
||||
if (!MetaModel::IsValidClass($oTrigger->Get('target_class'))) {
|
||||
$oTrigger->DBDelete();
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
// Load localized structural data: predefined query phrases for notifications
|
||||
static::LoadLocalizedData($sPreviousVersion, $sCurrentVersion, $oConfiguration, '3.0.0', dirname(__FILE__)."/data/{{language_code}}.data.itop-tickets.xml");
|
||||
// It's not very clear if it make sense to test a particular version,
|
||||
// as the loading mechanism checks object existence using reconc_keys
|
||||
// and do not recreate them, nor update existing.
|
||||
// Without test, new entries added to the data files, would be automatically loaded
|
||||
if (($sPreviousVersion === '') ||
|
||||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
|
||||
&& version_compare($sPreviousVersion, '3.0.0', '<'))) {
|
||||
$oDataLoader = new XMLDataLoader();
|
||||
|
||||
CMDBObject::SetTrackInfo("Initialization TicketsInstaller");
|
||||
$oMyChange = CMDBObject::GetCurrentChange();
|
||||
|
||||
$sLang = null;
|
||||
// - Try to get app. language from configuration fil (app. upgrade)
|
||||
$sConfigFileName = APPCONF.'production/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sConfigFileName)) {
|
||||
$oFileConfig = new Config($sConfigFileName);
|
||||
if (is_object($oFileConfig)) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oFileConfig->GetDefaultLanguage()));
|
||||
}
|
||||
}
|
||||
|
||||
// - I still no language, get the default one
|
||||
if (null === $sLang) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oConfiguration->GetDefaultLanguage()));
|
||||
}
|
||||
|
||||
$sFileName = dirname(__FILE__)."/data/{$sLang}.data.itop-tickets.xml";
|
||||
SetupLog::Info("Searching file: $sFileName");
|
||||
if (!file_exists($sFileName)) {
|
||||
$sFileName = dirname(__FILE__)."/data/en_us.data.itop-tickets.xml";
|
||||
}
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
$oDataLoader->StartSession($oMyChange);
|
||||
$oDataLoader->LoadFile($sFileName, false, true);
|
||||
$oDataLoader->EndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -309,94 +309,4 @@ abstract class ModuleInstallerAPI
|
||||
|
||||
CMDBSource::CacheReset($sOrigTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPreviousVersion The previous version of the module (empty string will force the loading)
|
||||
* @param string $sCurrentVersion The current version of the module
|
||||
* @param \Config $oConfiguration
|
||||
* @param string $sFirstLoadingVersion The first module version for which the data loading should be performed (e.g. '3.0.0')
|
||||
* @param string $sFilePattern The pattern of the file to load, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
|
||||
*
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function LoadLocalizedData(string $sPreviousVersion, string $sCurrentVersion, Config $oConfiguration, string $sFirstLoadingVersion, string $sFilePattern): void
|
||||
{
|
||||
// It's not very clear if it makes sense to test a particular version,
|
||||
// as the loading mechanism checks object existence using reconc_keys
|
||||
// and do not recreate them, nor update existing.
|
||||
// Without test, new entries added to the data files, would be automatically loaded
|
||||
if (($sPreviousVersion === '') ||
|
||||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
|
||||
&& version_compare($sPreviousVersion, $sFirstLoadingVersion, '<'))) {
|
||||
|
||||
$sFileName = self::GetLocalizedFileName($oConfiguration, $sFilePattern);
|
||||
if ($sFileName !== '') {
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
self::XMLFileLoad($sFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $sFileName
|
||||
* @param \XMLDataLoader $oDataLoader
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function XMLFileLoad(string $sFileName): void
|
||||
{
|
||||
if (file_exists($sFileName)) {
|
||||
$oDataLoader = new XMLDataLoader();
|
||||
CMDBObject::SetTrackInfo("Loading XML data from $sFileName");
|
||||
$oMyChange = CMDBObject::GetCurrentChange();
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
$oDataLoader->StartSession($oMyChange);
|
||||
$oDataLoader->LoadFile($sFileName, false, true);
|
||||
$oDataLoader->EndSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Config $oConfiguration
|
||||
* @param string $sFilePattern The full path+name of the file to localize, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
|
||||
*
|
||||
* @return string The localized file name if found, or an empty string if not found
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function GetLocalizedFileName(Config $oConfiguration, string $sFilePattern): string
|
||||
{
|
||||
$sLang = null;
|
||||
if (is_object($oConfiguration)) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oConfiguration->GetDefaultLanguage()));
|
||||
}
|
||||
/** Old code relying on reading the file instead of using the configuration passed object
|
||||
* Try to get app. language from configuration fil (app. upgrade)
|
||||
$sConfigFileName = APPCONF.'production/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sConfigFileName)) {
|
||||
$oFileConfig = new Config($sConfigFileName);
|
||||
if (is_object($oFileConfig)) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oFileConfig->GetDefaultLanguage()));
|
||||
}
|
||||
}
|
||||
**/
|
||||
// - I still no language, get the default one
|
||||
if (null === $sLang) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oConfiguration->GetDefaultLanguage()));
|
||||
}
|
||||
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
|
||||
if (!file_exists($sFileName)) {
|
||||
$sLang = 'en_us';
|
||||
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
|
||||
}
|
||||
if (file_exists($sFileName)) {
|
||||
return $sFileName;
|
||||
} else {
|
||||
SetupLog::Warning("No data file matching the pattern $sFilePattern and language_code $sLang was found.");
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ namespace Combodo\iTop\Test\UnitTest\Setup;
|
||||
|
||||
use CMDBSource;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Config;
|
||||
use MetaModel;
|
||||
use ModuleInstallerAPI;
|
||||
|
||||
/**
|
||||
* Class ModuleInstallerAPI
|
||||
* Class ModuleInstallerAPITest
|
||||
*
|
||||
* @covers ModuleInstallerAPI
|
||||
*
|
||||
@@ -283,105 +282,4 @@ SQL
|
||||
|
||||
$this->assertEquals($sOrigValue, $sDstValue, "Data was not moved as expected");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \ModuleInstallerAPI::LoadLocalizedData
|
||||
*/
|
||||
public function testLoadLocalizedData_LoadsOnFirstInstall(): void
|
||||
{
|
||||
// Given
|
||||
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->PrepareLocalizedDataTestContext('XML_Load_FirstInstall_', 'fr_fr');
|
||||
$this->CreateLocalizedDataFile($sTmpDir, "en_us", $sOrgName);
|
||||
$this->CreateLocalizedDataFile($sTmpDir, "fr_fr", $sOrgName);
|
||||
// When no previous version, and current version higher than the first loading version
|
||||
ModuleInstallerAPI::LoadLocalizedData('', '3.3.0', $oConfig, '3.0.0', $sPattern);
|
||||
// Then data loaded
|
||||
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 0);
|
||||
$this->AssertOrganizationCountByName($sOrgName, 'fr_fr', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \ModuleInstallerAPI::LoadLocalizedData
|
||||
*/
|
||||
public function testLoadLocalizedData_DoesNotLoadWhenVersionConditionIsNotMet(): void
|
||||
{
|
||||
// Given
|
||||
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->PrepareLocalizedDataTestContext('XML_Load_NoLoad_', 'en_us');
|
||||
$this->CreateLocalizedDataFile($sTmpDir, "en_us", $sOrgName);
|
||||
|
||||
// When a previous version that is lower than the first loading version, but higher or equal to the current version
|
||||
ModuleInstallerAPI::LoadLocalizedData('3.0.0', '3.1.0', $oConfig, '3.0.0', $sPattern);
|
||||
// Then no data loaded
|
||||
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \ModuleInstallerAPI::LoadLocalizedData
|
||||
*/
|
||||
public function testLoadLocalizedData_FallbacksToEnUsWhenLanguageFileIsMissing(): void
|
||||
{
|
||||
[$oConfig, $sOrgName, $sTmpDir, $sPattern] = $this->PrepareLocalizedDataTestContext('XML_Load_Fallback_', 'fr_fr');
|
||||
// Intentionally create ONLY en_us file
|
||||
$this->CreateLocalizedDataFile($sTmpDir, 'en_us', $sOrgName);
|
||||
// When loading localized data in fr_fr, but only en_us file exists
|
||||
ModuleInstallerAPI::LoadLocalizedData('', '3.3.0', $oConfig, '3.0.0', $sPattern);
|
||||
|
||||
$this->AssertOrganizationCountByName($sOrgName, 'fr_fr', 0);
|
||||
$this->AssertOrganizationCountByName($sOrgName, 'en_us', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare common context for LoadLocalizedData tests.
|
||||
*
|
||||
* @return array{0: Config, 1: string, 2: string, 3: string, 4: string}
|
||||
*/
|
||||
private function PrepareLocalizedDataTestContext(string $sOrgNamePrefix, string $sLanguage): array
|
||||
{
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$oConfig->SetDefaultLanguage($sLanguage);
|
||||
$this->assertNotNull($oConfig);
|
||||
|
||||
$sOrgName = $sOrgNamePrefix.uniqid();
|
||||
|
||||
$sTmpDir = static::CreateTmpdir();
|
||||
$this->aFileToClean[] = $sTmpDir;
|
||||
$sPattern = $sTmpDir.DIRECTORY_SEPARATOR.'data.{{language_code}}.xml';
|
||||
|
||||
return [$oConfig, $sOrgName, $sTmpDir, $sPattern];
|
||||
}
|
||||
|
||||
private function CreateLocalizedDataFile(string $sDir, string $sLang, string $sOrgName): string
|
||||
{
|
||||
$sFilePath = $sDir.DIRECTORY_SEPARATOR.'data.'.$sLang.'.xml';
|
||||
file_put_contents($sFilePath, $this->BuildOrganizationXml($sOrgName, $sLang));
|
||||
|
||||
return $sFilePath;
|
||||
}
|
||||
|
||||
private function BuildOrganizationXml(string $sOrgName, string $sLang): string
|
||||
{
|
||||
$iId = random_int(100000, 999999);
|
||||
$sOrgNameXml = htmlspecialchars($sOrgName, ENT_XML1);
|
||||
|
||||
return <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<Organization alias="Organization" id="{$iId}">
|
||||
<name>{$sOrgNameXml}</name>
|
||||
<code>{$sLang}</code>
|
||||
<status>active</status>
|
||||
</Organization>
|
||||
</Set>
|
||||
XML;
|
||||
}
|
||||
|
||||
private function AssertOrganizationCountByName(string $sOrgName, string $sLanguage, int $iExpectedCount): void
|
||||
{
|
||||
$sOrgTable = MetaModel::DBGetTable('Organization');
|
||||
$iCount = (int) CMDBSource::QueryToScalar(
|
||||
"SELECT COUNT(*) FROM `{$sOrgTable}` WHERE `name` = ".CMDBSource::Quote($sOrgName)." AND `code` = ".CMDBSource::Quote($sLanguage)
|
||||
);
|
||||
|
||||
$this->assertEquals($iExpectedCount, $iCount);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user