/** * Enumerate services delivered by this class * @param string $sVersion The version (e.g. 1.0) supported by the services * @return RestResult The standardized result structure (at least a message) * @throws Exception in case of internal failure. */ public function ExecOperation($sVersion, $sVerb, $aParams) { $oResult = new RestResultWithObjects(); switch ($sVerb) { case 'core/create': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObject = RestUtils::MakeObjectFromFields($sClass, $aFields); $oObject->DBInsert(); $oResult->AddObject(0, 'created', $oObject, $aShowFields, $bExtendedOutput); break; case 'core/update': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObject = RestUtils::FindObjectFromKey($sClass, $key); RestUtils::UpdateObjectFromFields($oObject, $aFields); $oObject->DBUpdate(); $oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput); break; case 'core/apply_stimulus': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $sStimulus = RestUtils::GetMandatoryParam($aParams, 'stimulus'); $oObject = RestUtils::FindObjectFromKey($sClass, $key); RestUtils::UpdateObjectFromFields($oObject, $aFields); $aTransitions = $oObject->EnumTransitions(); $aStimuli = MetaModel::EnumStimuli(get_class($oObject)); if (!isset($aTransitions[$sStimulus])) { // Invalid stimulus $oResult->code = RestResult::INTERNAL_ERROR; $oResult->message = "Invalid stimulus: '{$sStimulus}' on the object " . $oObject->GetName() . " in state '" . $oObject->GetState() . "'"; } else { $aTransition = $aTransitions[$sStimulus]; $sTargetState = $aTransition['target_state']; $aStates = MetaModel::EnumStates($sClass); $aTargetStateDef = $aStates[$sTargetState]; $aExpectedAttributes = $aTargetStateDef['attribute_list']; $aMissingMandatory = array(); foreach ($aExpectedAttributes as $sAttCode => $iExpectCode) { if ($iExpectCode & OPT_ATT_MANDATORY && $oObject->Get($sAttCode) == '') { $aMissingMandatory[] = $sAttCode; } } if (count($aMissingMandatory) == 0) { // If all the mandatory fields are already present, just apply the transition silently... if ($oObject->ApplyStimulus($sStimulus)) { $oObject->DBUpdate(); $oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput); } } else { // Missing mandatory attributes for the transition $oResult->code = RestResult::INTERNAL_ERROR; $oResult->message = 'Missing mandatory attribute(s) for applying the stimulus: ' . implode(', ', $aMissingMandatory) . '.'; } } break; case 'core/get': $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); while ($oObject = $oObjectSet->Fetch()) { $oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput); } $oResult->message = "Found: " . $oObjectSet->Count(); break; case 'core/delete': $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $bSimulate = RestUtils::GetOptionalParam($aParams, 'simulate', false); $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); $aObjects = $oObjectSet->ToArray(); $this->DeleteObjects($oResult, $aObjects, $bSimulate); break; case 'core/get_related': $oResult = new RestResultWithRelations(); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $sRelation = RestUtils::GetMandatoryParam($aParams, 'relation'); $iMaxRecursionDepth = RestUtils::GetOptionalParam($aParams, 'depth', 20); $sDirection = RestUtils::GetOptionalParam($aParams, 'direction', null); $bEnableRedundancy = RestUtils::GetOptionalParam($aParams, 'redundancy', false); $bReverse = false; if (is_null($sDirection) && $sRelation == 'depends on') { // Legacy behavior, consider "depends on" as a forward relation $sRelation = 'impacts'; $sDirection = 'up'; $bReverse = true; // emulate the legacy behavior by returning the edges } else { if (is_null($sDirection)) { $sDirection = 'down'; } } $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); if ($sDirection == 'down') { $oRelationGraph = $oObjectSet->GetRelatedObjectsDown($sRelation, $iMaxRecursionDepth, $bEnableRedundancy); } else { if ($sDirection == 'up') { $oRelationGraph = $oObjectSet->GetRelatedObjectsUp($sRelation, $iMaxRecursionDepth, $bEnableRedundancy); } else { $oResult->code = RestResult::INTERNAL_ERROR; $oResult->message = "Invalid value: '{$sDirection}' for the parameter 'direction'. Valid values are 'up' and 'down'"; return $oResult; } } if ($bEnableRedundancy) { // Remove the redundancy nodes from the output $oIterator = new RelationTypeIterator($oRelationGraph, 'Node'); foreach ($oIterator as $oNode) { if ($oNode instanceof RelationRedundancyNode) { $oRelationGraph->FilterNode($oNode); } } } $aIndexByClass = array(); $oIterator = new RelationTypeIterator($oRelationGraph); foreach ($oIterator as $oElement) { if ($oElement instanceof RelationObjectNode) { $oObject = $oElement->GetProperty('object'); if ($oObject) { if ($bEnableRedundancy) { // Add only the "reached" objects if ($oElement->GetProperty('is_reached')) { $aIndexByClass[get_class($oObject)][$oObject->GetKey()] = null; $oResult->AddObject(0, '', $oObject); } } else { $aIndexByClass[get_class($oObject)][$oObject->GetKey()] = null; $oResult->AddObject(0, '', $oObject); } } } else { if ($oElement instanceof RelationEdge) { $oSrcObj = $oElement->GetSourceNode()->GetProperty('object'); $oDestObj = $oElement->GetSinkNode()->GetProperty('object'); $sSrcKey = get_class($oSrcObj) . '::' . $oSrcObj->GetKey(); $sDestKey = get_class($oDestObj) . '::' . $oDestObj->GetKey(); if ($bEnableRedundancy) { // Add only the edges where both source and destination are "reached" if ($oElement->GetSourceNode()->GetProperty('is_reached') && $oElement->GetSinkNode()->GetProperty('is_reached')) { if ($bReverse) { $oResult->AddRelation($sDestKey, $sSrcKey); } else { $oResult->AddRelation($sSrcKey, $sDestKey); } } } else { if ($bReverse) { $oResult->AddRelation($sDestKey, $sSrcKey); } else { $oResult->AddRelation($sSrcKey, $sDestKey); } } } } } if (count($aIndexByClass) > 0) { $aStats = array(); foreach ($aIndexByClass as $sClass => $aIds) { $aStats[] = $sClass . '= ' . count($aIds); } $oResult->message = "Scope: " . $oObjectSet->Count() . "; Related objects: " . implode(', ', $aStats); } else { $oResult->message = "Nothing found"; } break; case 'core/check_credentials': $oResult = new RestResult(); $sUser = RestUtils::GetMandatoryParam($aParams, 'user'); $sPassword = RestUtils::GetMandatoryParam($aParams, 'password'); if (UserRights::CheckCredentials($sUser, $sPassword) !== true) { $oResult->authorized = false; } else { $oResult->authorized = true; } break; default: // unknown operation: handled at a higher level } return $oResult; }
/** * Enumerate services delivered by this class * @param string $sVersion The version (e.g. 1.0) supported by the services * @return RestResult The standardized result structure (at least a message) * @throws Exception in case of internal failure. */ public function ExecOperation($sVersion, $sVerb, $aParams) { $oResult = new RestResultWithObjects(); switch ($sVerb) { case 'core/create': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObject = RestUtils::MakeObjectFromFields($sClass, $aFields); $oObject->DBInsert(); $oResult->AddObject(0, 'created', $oObject, $aShowFields, $bExtendedOutput); break; case 'core/update': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObject = RestUtils::FindObjectFromKey($sClass, $key); RestUtils::UpdateObjectFromFields($oObject, $aFields); $oObject->DBUpdate(); $oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput); break; case 'core/apply_stimulus': RestUtils::InitTrackingComment($aParams); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aFields = RestUtils::GetMandatoryParam($aParams, 'fields'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $sStimulus = RestUtils::GetMandatoryParam($aParams, 'stimulus'); $oObject = RestUtils::FindObjectFromKey($sClass, $key); RestUtils::UpdateObjectFromFields($oObject, $aFields); $aTransitions = $oObject->EnumTransitions(); $aStimuli = MetaModel::EnumStimuli(get_class($oObject)); if (!isset($aTransitions[$sStimulus])) { // Invalid stimulus $oResult->code = RestResult::INTERNAL_ERROR; $oResult->message = "Invalid stimulus: '{$sStimulus}' on the object " . $oObject->GetName() . " in state '" . $oObject->GetState() . "'"; } else { $aTransition = $aTransitions[$sStimulus]; $sTargetState = $aTransition['target_state']; $aStates = MetaModel::EnumStates($sClass); $aTargetStateDef = $aStates[$sTargetState]; $aExpectedAttributes = $aTargetStateDef['attribute_list']; $aMissingMandatory = array(); foreach ($aExpectedAttributes as $sAttCode => $iExpectCode) { if ($iExpectCode & OPT_ATT_MANDATORY && $oObject->Get($sAttCode) == '') { $aMissingMandatory[] = $sAttCode; } } if (count($aMissingMandatory) == 0) { // If all the mandatory fields are already present, just apply the transition silently... if ($oObject->ApplyStimulus($sStimulus)) { $oObject->DBUpdate(); $oResult->AddObject(0, 'updated', $oObject, $aShowFields, $bExtendedOutput); } } else { // Missing mandatory attributes for the transition $oResult->code = RestResult::INTERNAL_ERROR; $oResult->message = 'Missing mandatory attribute(s) for applying the stimulus: ' . implode(', ', $aMissingMandatory) . '.'; } } break; case 'core/get': $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields'); $bExtendedOutput = RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+'; $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); while ($oObject = $oObjectSet->Fetch()) { $oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput); } $oResult->message = "Found: " . $oObjectSet->Count(); break; case 'core/delete': $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $bSimulate = RestUtils::GetOptionalParam($aParams, 'simulate', false); $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); $aObjects = $oObjectSet->ToArray(); $this->DeleteObjects($oResult, $aObjects, $bSimulate); break; case 'core/get_related': $oResult = new RestResultWithRelations(); $sClass = RestUtils::GetClass($aParams, 'class'); $key = RestUtils::GetMandatoryParam($aParams, 'key'); $sRelation = RestUtils::GetMandatoryParam($aParams, 'relation'); $iMaxRecursionDepth = RestUtils::GetOptionalParam($aParams, 'depth', 20); $oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key); $aIndexByClass = array(); while ($oObject = $oObjectSet->Fetch()) { $aRelated = array(); $aGraph = array(); $aIndexByClass[get_class($oObject)][$oObject->GetKey()] = null; $oResult->AddObject(0, '', $oObject); $this->GetRelatedObjects($oObject, $sRelation, $iMaxRecursionDepth, $aRelated, $aGraph); foreach ($aRelated as $sClass => $aObjects) { foreach ($aObjects as $oRelatedObj) { $aIndexByClass[get_class($oRelatedObj)][$oRelatedObj->GetKey()] = null; $oResult->AddObject(0, '', $oRelatedObj); } } foreach ($aGraph as $sSrcKey => $aDestinations) { foreach ($aDestinations as $sDestKey) { $oResult->AddRelation($sSrcKey, $sDestKey); } } } if (count($aIndexByClass) > 0) { $aStats = array(); foreach ($aIndexByClass as $sClass => $aIds) { $aStats[] = $sClass . '= ' . count($aIds); } $oResult->message = "Scope: " . $oObjectSet->Count() . "; Related objects: " . implode(', ', $aStats); } else { $oResult->message = "Nothing found"; } break; case 'core/check_credentials': $oResult = new RestResult(); $sUser = RestUtils::GetMandatoryParam($aParams, 'user'); $sPassword = RestUtils::GetMandatoryParam($aParams, 'password'); if (UserRights::CheckCredentials($sUser, $sPassword) !== true) { $oResult->authorized = false; } else { $oResult->authorized = true; } break; default: // unknown operation: handled at a higher level } return $oResult; }