diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index ac364f588..76f61d1b3 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -962,6 +962,106 @@ class AttributeLinkedSet extends AttributeDefinition return $oSet; } + /** + * Helper to get a value that will be JSON encoded + * The operation is the opposite to FromJSONToValue + */ + public function GetForJSON($value) + { + $aRet = array(); + if (is_object($value) && ($value instanceof DBObjectSet)) + { + $value->Rewind(); + while ($oObj = $value->Fetch()) + { + $sObjClass = get_class($oObj); + // Show only relevant information (hide the external key to the current object) + $aAttributes = array(); + foreach(MetaModel::ListAttributeDefs($sObjClass) as $sAttCode => $oAttDef) + { + if ($sAttCode == 'finalclass') + { + if ($sObjClass == $this->GetLinkedClass()) + { + // Simplify the output if the exact class could be determined implicitely + continue; + } + } + if ($sAttCode == $this->GetExtKeyToMe()) continue; + if ($oAttDef->IsExternalField()) continue; + if (!$oAttDef->IsDirectField()) continue; + if (!$oAttDef->IsScalar()) continue; + $attValue = $oObj->Get($sAttCode); + $aAttributes[$sAttCode] = $oAttDef->GetForJSON($attValue); + } + $aRet[] = $aAttributes; + } + } + return $aRet; + } + + /** + * Helper to form a value, given JSON decoded data + * The operation is the opposite to GetForJSON + */ + public function FromJSONToValue($json) + { + $sTargetClass = $this->Get('linked_class'); + + $aLinks = array(); + foreach($json as $aValues) + { + if (isset($aValues['finalclass'])) + { + $sLinkClass = $aValues['finalclass']; + if (!is_subclass_of($sLinkClass, $sTargetClass)) + { + throw new CoreException('Wrong class for link attribute specification', array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass)); + } + } + elseif (MetaModel::IsAbstract($sTargetClass)) + { + throw new CoreException('Missing finalclass for link attribute specification'); + } + else + { + $sLinkClass = $sTargetClass; + } + + $oLink = MetaModel::NewObject($sLinkClass); + foreach ($aValues as $sAttCode => $sValue) + { + $oLink->Set($sAttCode, $sValue); + } + + // Check (roughly) if such a link is valid + $aErrors = array(); + foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef) + { + if ($oAttDef->IsExternalKey()) + { + if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass()))) + { + continue; // Don't check the key to self + } + } + + if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed()) + { + $aErrors[] = $sAttCode; + } + } + if (count($aErrors) > 0) + { + throw new CoreException("Missing value for mandatory attribute(s): ".implode(', ', $aErrors)); + } + + $aLinks[] = $oLink; + } + $oSet = DBObjectSet::FromArray($sTargetClass, $aLinks); + return $oSet; + } + public function Equals($val1, $val2) { if ($val1 === $val2) return true;