XML Modelization of the relations, with full support of the previous way (by implementing a method GetRelationQueries). Still, the standard data model has not been migrated to the new format.

SVN:trunk[3519]
This commit is contained in:
Romain Quetiez
2015-03-26 11:12:25 +00:00
parent 8b36699893
commit 3cf0fa3ee2
5 changed files with 198 additions and 41 deletions

View File

@@ -2531,41 +2531,66 @@ abstract class DBObject implements iDisplay
}
// Return an empty set for the parent of all
// May be overloaded.
// Anyhow, this way of implementing the relations suffers limitations (not handling the redundancy)
// and you should consider defining those things in XML.
public static function GetRelationQueries($sRelCode)
{
return array();
}
// Reserved: do not overload
public static function GetRelationQueriesEx($sRelCode)
{
return array();
}
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99, &$aResults = array())
{
foreach (MetaModel::EnumRelationQueries(get_class($this), $sRelCode) as $sDummy => $aQueryInfo)
{
MetaModel::DbgTrace("object=".$this->GetKey().", depth=$iMaxDepth, rel=".$aQueryInfo["sQuery"]);
$sQuery = $aQueryInfo["sQuery"];
$bPropagate = $aQueryInfo["bPropagate"];
$iDistance = $aQueryInfo["iDistance"];
//$bPropagate = $aQueryInfo["bPropagate"];
//$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
$iDepth = $iMaxDepth - 1;
$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
$oFlt = DBObjectSearch::FromOQL($sQuery);
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgsForQuery());
while ($oObj = $oObjSet->Fetch())
// Note: the loop over the result set has been written in an unusual way for error reporting purposes
// In the case of a wrong query parameter name, the error occurs on the first call to Fetch,
// thus we need to have this first call into the try/catch, but
// we do NOT want to nest the try/catch for the error message to be clear
try
{
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
$sObjKey = $oObj->GetKey();
if (array_key_exists($sRootClass, $aResults))
$oFlt = DBObjectSearch::FromOQL($sQuery);
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgsForQuery());
$oObj = $oObjSet->Fetch();
}
catch (Exception $e)
{
$sClassOfDefinition = $aQueryInfo['_legacy_'] ? get_class($this).'(or a parent)::GetRelationQueries()' : $aQueryInfo['sDefinedInClass'];
throw new Exception("Wrong query for the relation $sRelCode/$sClassOfDefinition/{$aQueryInfo['sNeighbour']}: ".$e->getMessage());
}
if ($oObj)
{
do
{
if (array_key_exists($sObjKey, $aResults[$sRootClass]))
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
$sObjKey = $oObj->GetKey();
if (array_key_exists($sRootClass, $aResults))
{
continue; // already visited, skip
if (array_key_exists($sObjKey, $aResults[$sRootClass]))
{
continue; // already visited, skip
}
}
$aResults[$sRootClass][$sObjKey] = $oObj;
if ($iDepth > 0)
{
$oObj->GetRelatedObjects($sRelCode, $iDepth, $aResults);
}
}
$aResults[$sRootClass][$sObjKey] = $oObj;
if ($iDepth > 0)
{
$oObj->GetRelatedObjects($sRelCode, $iDepth, $aResults);
}
while ($oObj = $oObjSet->Fetch());
}
}
return $aResults;

View File

@@ -1124,31 +1124,77 @@ abstract class MetaModel
return $aResult;
}
public static function EnumRelationProperties($sRelCode)
{
MyHelpers::CheckKeyInArray('relation code', $sRelCode, self::$m_aRelationInfos);
return self::$m_aRelationInfos[$sRelCode];
}
final static public function GetRelationDescription($sRelCode)
{
return Dict::S("Relation:$sRelCode/Description");
}
final static public function GetRelationVerbUp($sRelCode)
final static public function GetRelationLabel($sRelCode)
{
return Dict::S("Relation:$sRelCode/VerbUp");
}
final static public function GetRelationVerbDown($sRelCode)
{
return Dict::S("Relation:$sRelCode/VerbDown");
}
public static function EnumRelationQueries($sClass, $sRelCode)
{
MyHelpers::CheckKeyInArray('relation code', $sRelCode, self::$m_aRelationInfos);
return call_user_func_array(array($sClass, 'GetRelationQueries'), array($sRelCode));
$aNeighbours = call_user_func_array(array($sClass, 'GetRelationQueriesEx'), array($sRelCode));
// Translate attributes into queries (new style of spec only)
foreach($aNeighbours as $trash => &$aNeighbourData)
{
try
{
if (strlen($aNeighbourData['sQuery']) == 0)
{
$oAttDef = self::GetAttributeDef($sClass, $aNeighbourData['sAttribute']);
if ($oAttDef instanceof AttributeExternalKey)
{
$sTargetClass = $oAttDef->GetTargetClass();
$aNeighbourData['sQuery'] = 'SELECT '.$sTargetClass.' AS o WHERE o.id = :this->'.$aNeighbourData['sAttribute'];
}
elseif ($oAttDef instanceof AttributeLinkedSet)
{
$sLinkedClass = $oAttDef->GetLinkedClass();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
if ($oAttDef->IsIndirect())
{
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
$oRemoteAttDef = self::GetAttributeDef($sLinkedClass, $sExtKeyToRemote);
$sRemoteClass = $oRemoteAttDef->GetTargetClass();
$aNeighbourData['sQuery'] = "SELECT $sRemoteClass AS o JOIN $sLinkedClass AS lnk ON lnk.$sExtKeyToRemote = o.id WHERE lnk.$sExtKeyToMe = :this->id";
}
else
{
$aNeighbourData['sQuery'] = "SELECT $sLinkedClass AS o WHERE o.$sExtKeyToMe = :this->id";
}
}
else
{
throw new Exception("Unexpected attribute type for '{$aNeighbourData['sAttribute']}'. Expecting a link set or external key.");
}
}
}
catch (Exception $e)
{
$sClassOfDefinition = $aNeighbourData['_legacy_'] ? $sClass.'(or a parent)::GetRelationQueries()' : $aNeighbourData['sDefinedInClass'];
throw new Exception("Wrong definition for the relation $sRelCode/$sClassOfDefinition/{$aNeighbourData['sNeighbour']}: ".$e->getMessage());
}
}
// Merge legacy and new specs
$aLegacy = call_user_func_array(array($sClass, 'GetRelationQueries'), array($sRelCode));
foreach($aLegacy as $sId => $aLegacyEntry)
{
$aLegacyEntry['_legacy_'] = true;
$aNeighbours[] = array(
'_legacy_' => true,
'sQuery' => $aLegacyEntry['sQuery'],
'sNeighbour' => $sId
);
}
return $aNeighbours;
}
//