diff --git a/core/metamodel.class.php b/core/metamodel.class.php
index e99c9bdc5..f502b2359 100644
--- a/core/metamodel.class.php
+++ b/core/metamodel.class.php
@@ -1183,11 +1183,11 @@ abstract class MetaModel
{
if ($bDown)
{
- // The legacy convention is confusing with regard to the way we have conceptualized the relations:
- // In the former representation, the main stream was named after "up"
- // Now, the relation from A to B says that something is transmitted from A to B, thus going DOWNstream as described in a petri net.
- $sKey = "Relation:$sRelCode/DownStream";
- $sLegacy = Dict::S("Relation:$sRelCode/VerbUp", $sKey);
+ // The legacy convention is confusing with regard to the way we have conceptualized the relations:
+ // In the former representation, the main stream was named after "up"
+ // Now, the relation from A to B says that something is transmitted from A to B, thus going DOWNstream as described in a petri net.
+ $sKey = "Relation:$sRelCode/DownStream";
+ $sLegacy = Dict::S("Relation:$sRelCode/VerbUp", $sKey);
}
else
{
@@ -1265,17 +1265,25 @@ abstract class MetaModel
throw new Exception("Wrong definition for the relation $sRelCode/{$aNeighbourData['sDefinedInClass']}/{$aNeighbourData['sNeighbour']}: ".$e->getMessage());
}
+ if ($aNeighbourData['sDirection'] == 'down')
+ {
+ $aNeighbourData['sQueryUp'] = null;
+ }
+
$sArrowId = $aNeighbourData['sDefinedInClass'].'_'.$sNeighbourId;
$aQueries[$sClass]['down'][$sArrowId] = $aNeighbourData;
// Compute the reverse index
if ($aNeighbourData['sDefinedInClass'] == $sClass)
{
- $sFromClass = $aNeighbourData['sFromClass'];
- $sToClass = $aNeighbourData['sToClass'];
- foreach (self::EnumChildClasses($sToClass, ENUM_CHILD_CLASSES_ALL) as $sSubClass)
+ if ($aNeighbourData['sDirection'] == 'both')
{
- $aQueries[$sSubClass]['up'][$sArrowId] = $aNeighbourData;
+ $sFromClass = $aNeighbourData['sFromClass'];
+ $sToClass = $aNeighbourData['sToClass'];
+ foreach (self::EnumChildClasses($sToClass, ENUM_CHILD_CLASSES_ALL) as $sSubClass)
+ {
+ $aQueries[$sSubClass]['up'][$sArrowId] = $aNeighbourData;
+ }
}
}
}
@@ -1320,7 +1328,9 @@ abstract class MetaModel
'sDefinedInClass' => $sClass,
'sFromClass' => $sClass,
'sToClass' => $sRemoteClass,
+ 'sDirection' => 'down',
'sQueryDown' => $aLegacyEntry['sQuery'],
+ 'sQueryUp' => null,
'sNeighbour' => $sRemoteClass // Normalize the neighbour id
);
}
@@ -1354,6 +1364,8 @@ abstract class MetaModel
'sDefinedInClass' => $sRemoteClass,
'sFromClass' => $sRemoteClass,
'sToClass' => $sClass,
+ 'sDirection' => 'both',
+ 'sQueryDown' => null,
'sQueryUp' => $aLegacyEntry['sQuery'],
'sNeighbour' => $sClass// Normalize the neighbour id
);
@@ -1388,6 +1400,7 @@ abstract class MetaModel
if (isset($aQueries[$sRemoteClass]['down'][$sLocalClass]))
{
$aQueries[$sRemoteClass]['down'][$sLocalClass]['sQueryUp'] = $aNeighbourData['sQueryUp'];
+ $aQueries[$sRemoteClass]['down'][$sLocalClass]['sDirection'] = 'both';
}
else
{
@@ -1396,7 +1409,7 @@ abstract class MetaModel
}
}
}
- // Foreach "down" legacy query, update its "up" counterpart
+ // Foreach "down" legacy query, update its "up" counterpart (if any)
foreach ($aQueries[$sClass]['down'] as $sNeighbourId => $aNeighbourData)
{
if (!$aNeighbourData['_legacy_']) continue; // Skip modern definitions
@@ -1404,7 +1417,10 @@ abstract class MetaModel
$sLocalClass = $aNeighbourData['sFromClass'];
foreach (self::EnumChildClasses($aNeighbourData['sToClass'], ENUM_CHILD_CLASSES_ALL) as $sRemoteClass)
{
- //$aQueries[$sRemoteClass]['up'][$sLocalClass]['sQueryDown'] = $aNeighbourData['sQueryDown'];
+ if (isset($aQueries[$sRemoteClass]['up'][$sLocalClass]))
+ {
+ $aQueries[$sRemoteClass]['up'][$sLocalClass]['sQueryDown'] = $aNeighbourData['sQueryDown'];
+ }
}
}
}
diff --git a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
index 0b882122a..4c0d9369a 100755
--- a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
+++ b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml
@@ -1380,7 +1380,6 @@
-
@@ -1469,6 +1468,7 @@
contacts_list
+ down
applicationsolution_list
@@ -1743,7 +1743,6 @@
0
-
@@ -2208,7 +2207,6 @@
true
-
@@ -2522,7 +2520,6 @@
-
@@ -2835,7 +2832,6 @@
count
-
@@ -2976,7 +2972,6 @@
list
-
@@ -3138,7 +3133,6 @@
list
-
@@ -3268,7 +3262,6 @@
0
-
@@ -3416,7 +3409,6 @@
0
-
@@ -3564,7 +3556,6 @@
0
-
@@ -3946,7 +3937,6 @@
name
-
@@ -4067,7 +4057,6 @@
name
-
@@ -4194,7 +4183,6 @@
_blank
-
diff --git a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
index ec09b409c..740f9d146 100755
--- a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
+++ b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml
@@ -231,7 +231,18 @@
0
-
+
+
+ /**
+ * Placeholder for backward compatibility (iTop <= 2.1.0)
+ * in case an extension attempts to redefine this function...
+ */
+ true
+ public
+ Overload-DBObject
+
+
+
@@ -401,7 +412,18 @@
-
+
+
+ /**
+ * Placeholder for backward compatibility (iTop <= 2.1.0)
+ * in case an extension attempts to redefine this function...
+ */
+ true
+ public
+ Overload-DBObject
+
+
+
@@ -762,7 +784,6 @@
name
-
diff --git a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
index 03b9ac991..988eaa9c5 100644
--- a/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
+++ b/datamodels/2.x/itop-storage-mgmt/datamodel.itop-storage-mgmt.xml
@@ -34,7 +34,6 @@
0
-
@@ -299,7 +298,6 @@
-
@@ -560,7 +558,6 @@
0
-
@@ -821,7 +818,6 @@
0
-
@@ -1099,7 +1095,6 @@
name
-
@@ -1206,7 +1201,6 @@
name
-
@@ -1452,7 +1446,6 @@
-
diff --git a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
index 14f9c79e5..44f237708 100644
--- a/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
+++ b/datamodels/2.x/itop-virtualization-mgmt/datamodel.itop-virtualization-mgmt.xml
@@ -157,7 +157,6 @@
0
-
@@ -300,7 +299,6 @@
name
-
@@ -456,7 +454,6 @@
user
-
@@ -649,7 +646,6 @@
true
-
diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php
index 3bd43fe53..4450d1a90 100644
--- a/setup/compiler.class.inc.php
+++ b/setup/compiler.class.inc.php
@@ -1452,29 +1452,43 @@ EOF;
if ($oNeighbour->tagName != 'neighbour') continue;
$sNeighbourId = $oNeighbour->getAttribute('id');
- if (($oNeighbour->GetChildText('query_down') != '') && ($oNeighbour->GetChildText('query_up') == ''))
- {
- throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': missing the query_up specification");
- }
- if (($oNeighbour->GetChildText('query_up') != '') && ($oNeighbour->GetChildText('query_down') == ''))
- {
- throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': missing the query_down specification");
- }
- if (($oNeighbour->GetChildText('query_down') == '') && ($oNeighbour->GetChildText('attribute') == ''))
+ $sDirection = $oNeighbour->GetChildText('direction', 'both');
+ $sAttribute = $oNeighbour->GetChildText('attribute');
+ $sQueryDown = $oNeighbour->GetChildText('query_down');
+ $sQueryUp = $oNeighbour->GetChildText('query_up');
+
+ if (($sQueryDown == '') && ($sAttribute == ''))
{
throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': either a query or an attribute must be specified");
}
- if (($oNeighbour->GetChildText('query_down') != '') && ($oNeighbour->GetChildText('attribute') != ''))
+ if (($sQueryDown != '') && ($sAttribute != ''))
{
throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': both a query and and attribute have been specified... which one should be used?");
}
+
+ if ($sDirection == 'both')
+ {
+ if (($sAttribute == '') && ($sQueryUp == ''))
+ {
+ throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': missing the query_up specification");
+ }
+ }
+ elseif ($sDirection == 'down')
+ {
+ // Ok
+ }
+ else
+ {
+ throw new DOMFormatException("Relation '$sRelationId/$sNeighbourId': unknown direction ($sDirection), expecting 'both' or 'down'");
+ }
$aRelations[$sRelationId][$sNeighbourId] = array(
'_legacy_' => false,
+ 'sDirection' => $sDirection,
'sDefinedInClass' => $sClass,
'sNeighbour' => $sNeighbourId,
- 'sQueryDown' => $oNeighbour->GetChildText('query_down'),
- 'sQueryUp' => $oNeighbour->GetChildText('query_up'),
- 'sAttribute' => $oNeighbour->GetChildText('attribute'),
+ 'sQueryDown' => $sQueryDown,
+ 'sQueryUp' => $sQueryUp,
+ 'sAttribute' => $sAttribute,
);
}
}