From 5a77159ece0037afb3271d7720a044fa9157b21a Mon Sep 17 00:00:00 2001 From: acognet Date: Fri, 8 Jul 2022 12:15:46 +0200 Subject: [PATCH 1/2] =?UTF-8?q?N=C2=B04157=20-=20Relations,=20modify=20one?= =?UTF-8?q?=20and=20add=20it=20again=20fails,=20the=20adding=20is=20ignore?= =?UTF-8?q?d=20-=20check=20uniqueness=20rule=20before=20saving=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/dbobject.class.php | 64 +++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 48b27e305e..e51e0a73e8 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -2062,15 +2062,13 @@ protected function DoCheckUniqueness() if ($bHasDuplicates) { $bIsBlockingRule = $aUniquenessRuleProperties['is_blocking']; - if (is_null($bIsBlockingRule)) - { + if (is_null($bIsBlockingRule)) { $bIsBlockingRule = true; } - $sErrorMessage = $this->GetUniquenessRuleMessage($sUniquenessRuleId); + $sErrorMessage = $this->GetUniquenessRuleMessage($sUniquenessRuleId, $this); - if ($bIsBlockingRule) - { + if ($bIsBlockingRule) { $this->m_aCheckIssues[] = $sErrorMessage; continue; } @@ -2081,32 +2079,32 @@ protected function DoCheckUniqueness() } /** - * - * @internal - * + * + * @internal + * * @param string $sUniquenessRuleId + * @param DBObject $oObj * * @return string dict key : Class:$sClassName/UniquenessRule:$sUniquenessRuleId if none then will use Core:UniquenessDefaultError * Dictionary keys can contain "$this" placeholders * * @since 2.6.0 N°659 uniqueness constraint */ - protected function GetUniquenessRuleMessage($sUniquenessRuleId) + protected function GetUniquenessRuleMessage($sUniquenessRuleId, $oObj) { - $sCurrentClass = get_class($this); + $sCurrentClass = get_class($oObj); $sClass = MetaModel::GetRootClassForUniquenessRule($sUniquenessRuleId, $sCurrentClass); $sMessageKey = "Class:$sClass/UniquenessRule:$sUniquenessRuleId"; $sTemplate = Dict::S($sMessageKey, ''); - if (empty($sTemplate)) - { + if (empty($sTemplate)) { // we could add also a specific message if user is admin ("dict key is missing") return Dict::Format('Core:UniquenessDefaultError', $sUniquenessRuleId); } $oString = new TemplateString($sTemplate); - return $oString->Render(array('this' => $this)); + return $oString->Render(array('this' => $oObj)); } /** @@ -2205,20 +2203,41 @@ protected function DoCheckLinkedSetDuplicates($sAttCode, $value) $aCurrentRemoteIds = []; $aDuplicatesFields = []; $value->rewind(); + $oOneLnkFaill = null; while ($oCurrentLnk = $value->current()) { $iExtKeyToRemote = $oCurrentLnk->Get($sExtKeyToRemote); if (isset($aCurrentRemoteIds[$iExtKeyToRemote])) { $aDuplicatesFields[] = $oCurrentLnk->Get($sExtKeyToRemote.'_friendlyname'); } else { $aCurrentRemoteIds[$iExtKeyToRemote] = true; + $oOneLnkFaill = $oCurrentLnk; } $value->next(); } if (!empty($aDuplicatesFields)) { - $this->m_aCheckWarnings[] = Dict::Format('Core:AttributeLinkedSetDuplicatesFound', - $oAttDef->GetLabel(), - implode(', ', $aDuplicatesFields)); + //check uniqueness rule in order to stop saving object if necessary + $sCurrentClass = $value->GetClass(); + $aUniquenessRules = MetaModel::GetUniquenessRules($sCurrentClass); + + foreach ($aUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties) { + $bIsBlockingRule = $aUniquenessRuleProperties['is_blocking']; + if (is_null($bIsBlockingRule)) { + $bIsBlockingRule = true; + } + + if ($bIsBlockingRule || $aUniquenessRuleProperties['disabled'] === true) { + $sErrorMessage = $this->GetUniquenessRuleMessage($sUniquenessRuleId, $oOneLnkFaill); + $this->m_aCheckIssues[] = $sErrorMessage; + $this->m_aCheckIssues[] = Dict::Format('Core:AttributeLinkedSetDuplicatesFound', + $oAttDef->GetLabel(), + implode(', ', $aDuplicatesFields)); + } else { + $this->m_aCheckWarnings[] = Dict::Format('Core:AttributeLinkedSetDuplicatesFound', + $oAttDef->GetLabel(), + implode(', ', $aDuplicatesFields)); + } + } } } @@ -3174,8 +3193,7 @@ public function DBUpdate() $this->OnUpdate(); $aChanges = $this->ListChanges(); - if (count($aChanges) == 0) - { + if (count($aChanges) == 0) { // Attempting to update an unchanged object unset($aUpdateReentrance[$sKey]); @@ -3184,12 +3202,11 @@ public function DBUpdate() // Ultimate check - ensure DB integrity list($bRes, $aIssues) = $this->CheckToWrite(); - if (!$bRes) - { + if (!$bRes) { throw new CoreCannotSaveObjectException(array( 'issues' => $aIssues, - 'class' => get_class($this), - 'id' => $this->GetKey() + 'class' => get_class($this), + 'id' => $this->GetKey(), )); } @@ -3283,8 +3300,7 @@ public function DBUpdate() } // Update scalar attributes - if (count($aDBChanges) != 0) - { + if (count($aDBChanges) != 0) { $oFilter = new DBObjectSearch(get_class($this)); $oFilter->AddCondition('id', $this->m_iKey, '='); $oFilter->AllowAllData(); From c7eea3f51f98d52f1a34db63b8b74890c0201bdf Mon Sep 17 00:00:00 2001 From: acognet Date: Fri, 8 Jul 2022 12:24:53 +0200 Subject: [PATCH 2/2] =?UTF-8?q?N=C2=B04157=20-=20Relations,=20modify=20one?= =?UTF-8?q?=20and=20add=20it=20again=20fails,=20the=20adding=20is=20ignore?= =?UTF-8?q?d=20-=20Dont-work.=20It's=20a=20idee=20to=20solve=20the=20probl?= =?UTF-8?q?em=20of=20display=20modified=20link,=20but=20actually=20there?= =?UTF-8?q?=20is=20a=20js=20bug.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/cmdbabstract.class.inc.php | 103 ++++++++--------------- application/ui.linkswidget.class.inc.php | 71 ++++++++-------- core/ormlinkset.class.inc.php | 26 ++++-- js/linkswidget.js | 25 ++++-- 4 files changed, 104 insertions(+), 121 deletions(-) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index efc31737b9..0b85eabee7 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -676,33 +676,26 @@ public function DisplayBareRelations(WebPage $oPage, $bEditMode = false) $sTargetClass = $oLinkingAttDef->GetTargetClass(); // n:n links => must be allowed to modify the linking class AND read the target class in order to edit the linkedset if (!UserRights::IsActionAllowed($sLinkedClass, - UR_ACTION_MODIFY) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) - { + UR_ACTION_MODIFY) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) { $iFlags |= OPT_ATT_READONLY; } // n:n links => must be allowed to read the linking class AND the target class in order to display the linkedset if (!UserRights::IsActionAllowed($sLinkedClass, - UR_ACTION_READ) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) - { + UR_ACTION_READ) || !UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ)) { $iFlags |= OPT_ATT_HIDDEN; } - } - else - { + } else { // 1:n links => must be allowed to modify the linked class in order to edit the linkedset - if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_MODIFY)) - { + if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_MODIFY)) { $iFlags |= OPT_ATT_READONLY; } // 1:n links => must be allowed to read the linked class in order to display the linkedset - if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_READ)) - { + if (!UserRights::IsActionAllowed($sLinkedClass, UR_ACTION_READ)) { $iFlags |= OPT_ATT_HIDDEN; } } // Non-readable/hidden linkedset... don't display anything - if ($iFlags & OPT_ATT_HIDDEN) - { + if ($iFlags & OPT_ATT_HIDDEN) { continue; } @@ -711,27 +704,23 @@ public function DisplayBareRelations(WebPage $oPage, $bEditMode = false) $aArgs = array('this' => $this); $bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)); - if ($bEditMode && (!$bReadOnly)) - { + if ($bEditMode && (!$bReadOnly)) { $sInputId = $this->m_iFormId.'_'.$sAttCode; - if ($oAttDef->IsIndirect()) - { + if ($oAttDef->IsIndirect()) { $oLinkingAttDef = MetaModel::GetAttributeDef($sLinkedClass, $oAttDef->GetExtKeyToRemote()); $sTargetClass = $oLinkingAttDef->GetTargetClass(); - } - else - { + } else { $sTargetClass = $sLinkedClass; } $oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($sTargetClass, false)); $oClassIcon->SetDescription($oAttDef->GetDescription())->AddCSSClass('ibo-block-list--medallion'); $oPage->AddUiBlock($oClassIcon); - + $sDisplayValue = ''; // not used $sHTMLValue = "".self::GetFormElementForField($oPage, $sClass, $sAttCode, - $oAttDef, $oLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).''; + $oAttDef, $oOrmLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).''; $this->AddToFieldsMap($sAttCode, $sInputId); $oPage->add($sHTMLValue); } @@ -2382,8 +2371,7 @@ public static function GetFormElementForField($oPage, $sClass, $sAttCode, $oAttD case 'LinkedSet': $sInputType = self::ENUM_INPUT_TYPE_LINKEDSET; if ($oAttDef->IsIndirect()) { - $oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix, - $oAttDef->DuplicatesAllowed()); + $oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix, $oAttDef->DuplicatesAllowed()); } else { $oWidget = new UILinksWidgetDirect($sClass, $sAttCode, $iId, $sNameSuffix); } @@ -4031,18 +4019,14 @@ public function UpdateObjectFromArray($aValues) $this->Set($sAttCode, $value); break; case 'LinkedSet': - if ($this->IsValueModified($value)) - { + if ($this->IsValueModified($value)) { $oLinkSet = $this->Get($sAttCode); $sLinkedClass = $oAttDef->GetLinkedClass(); - if (array_key_exists('to_be_created', $value) && (count($value['to_be_created']) > 0)) - { + if (array_key_exists('to_be_created', $value) && (count($value['to_be_created']) > 0)) { // Now handle the links to be created - foreach ($value['to_be_created'] as $aData) - { + foreach ($value['to_be_created'] as $aData) { $sSubClass = $aData['class']; - if (($sLinkedClass == $sSubClass) || (is_subclass_of($sSubClass, $sLinkedClass))) - { + if (($sLinkedClass == $sSubClass) || (is_subclass_of($sSubClass, $sLinkedClass))) { $aObjData = $aData['data']; $oLink = MetaModel::NewObject($sSubClass); $oLink->UpdateObjectFromArray($aObjData); @@ -4254,28 +4238,20 @@ protected function PrepareValueFromPostedForm($sFormPrefix, $sAttCode, $sClass = case 'LinkedSet': /** @var AttributeLinkedSet $oAttDef */ - $aRawToBeCreated = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbc", '{}', - 'raw_data'), true); + $aRawToBeCreated = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbc", '{}', 'raw_data'), true); $aToBeCreated = array(); - foreach($aRawToBeCreated as $aData) - { + foreach ($aRawToBeCreated as $aData) { $sSubFormPrefix = $aData['formPrefix']; $sObjClass = isset($aData['class']) ? $aData['class'] : $oAttDef->GetLinkedClass(); $aObjData = array(); - foreach($aData as $sKey => $value) - { - if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) - { + foreach ($aData as $sKey => $value) { + if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) { $oLinkAttDef = MetaModel::GetAttributeDef($sObjClass, $aMatches[1]); // Recursing over n:n link datetime attributes // Note: We might need to do it with other attribute types, like Document or redundancy setting. - if ($oLinkAttDef instanceof AttributeDateTime) - { - $aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, - $aMatches[1], $sObjClass, $aData); - } - else - { + if ($oLinkAttDef instanceof AttributeDateTime) { + $aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, $aMatches[1], $sObjClass, $aData); + } else { $aObjData[$aMatches[1]] = $value; } } @@ -4283,28 +4259,20 @@ protected function PrepareValueFromPostedForm($sFormPrefix, $sAttCode, $sClass = $aToBeCreated[] = array('class' => $sObjClass, 'data' => $aObjData); } - $aRawToBeModified = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbm", '{}', - 'raw_data'), true); + $aRawToBeModified = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbm", '{}', 'raw_data'), true); $aToBeModified = array(); - foreach($aRawToBeModified as $iObjKey => $aData) - { + foreach ($aRawToBeModified as $iObjKey => $aData) { $sSubFormPrefix = $aData['formPrefix']; $sObjClass = isset($aData['class']) ? $aData['class'] : $oAttDef->GetLinkedClass(); $aObjData = array(); - foreach($aData as $sKey => $value) - { - if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) - { + foreach ($aData as $sKey => $value) { + if (preg_match("/^attr_$sSubFormPrefix(.*)$/", $sKey, $aMatches)) { $oLinkAttDef = MetaModel::GetAttributeDef($sObjClass, $aMatches[1]); // Recursing over n:n link datetime attributes // Note: We might need to do it with other attribute types, like Document or redundancy setting. - if ($oLinkAttDef instanceof AttributeDateTime) - { - $aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, - $aMatches[1], $sObjClass, $aData); - } - else - { + if ($oLinkAttDef instanceof AttributeDateTime) { + $aObjData[$aMatches[1]] = $this->PrepareValueFromPostedForm($sSubFormPrefix, $aMatches[1], $sObjClass, $aData); + } else { $aObjData[$aMatches[1]] = $value; } } @@ -4313,14 +4281,11 @@ protected function PrepareValueFromPostedForm($sFormPrefix, $sAttCode, $sClass = } $value = array( - 'to_be_created' => $aToBeCreated, + 'to_be_created' => $aToBeCreated, 'to_be_modified' => $aToBeModified, - 'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]', - 'raw_data'), true), - 'to_be_added' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tba", '[]', - 'raw_data'), true), - 'to_be_removed' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbr", '[]', - 'raw_data'), true), + 'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]', 'raw_data'), true), + 'to_be_added' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tba", '[]', 'raw_data'), true), + 'to_be_removed' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbr", '[]', 'raw_data'), true), ); break; diff --git a/application/ui.linkswidget.class.inc.php b/application/ui.linkswidget.class.inc.php index 1f4e63da53..84adede5b2 100644 --- a/application/ui.linkswidget.class.inc.php +++ b/application/ui.linkswidget.class.inc.php @@ -108,15 +108,14 @@ public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '', $b * @throws \CoreUnexpectedValue * @throws \Exception */ - protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false) + protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $aArgs, $oCurrentObj, $iUniqueId, $bReadOnly = false, $bModified = false) { $sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}"; $aRow = array(); $aFieldsMap = array(); $iKey = 0; - if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew())) - { + if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew())) { $iKey = $linkObjOrId->GetKey(); $iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote); $sPrefix .= "[$iKey]["; @@ -125,49 +124,44 @@ protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $ $aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}"; $aArgs['this'] = $linkObjOrId; - if ($bReadOnly) - { + if ($bReadOnly) { $aRow['form::checkbox'] = ""; - foreach ($this->m_aEditableFields as $sFieldCode) - { + foreach ($this->m_aEditableFields as $sFieldCode) { $sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode); $aRow[$sFieldCode] = $sDisplayValue; } - } - else - { + } else { $aRow['form::checkbox'] = "m_iInputId.".OnSelectChange();\" value=\"$iKey\">"; - foreach ($this->m_aEditableFields as $sFieldCode) - { + foreach ($this->m_aEditableFields as $sFieldCode) { $sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode); $this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId); $aFieldsMap[$sFieldCode] = $sSafeFieldId; + + if ($bModified) { + $oP->add_ready_script( + <<m_iInputId}.AddModified($iUniqueId, {$this->m_iInputId}, $sFieldCode, {$linkObjOrId->Get($sFieldCode)}); +EOF + ); + } } } $sState = $linkObjOrId->GetState(); $sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);; - } - else - { + } else { // form for creating a new record - if (is_object($linkObjOrId)) - { + if (is_object($linkObjOrId)) { // New link existing only in memory $oNewLinkObj = $linkObjOrId; $iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote); - $oNewLinkObj->Set($this->m_sExtKeyToMe, - $oCurrentObj); // Setting the extkey with the object also fills the related external fields - } - else - { + $oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields + } else { $iRemoteObjKey = $linkObjOrId; $oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass); $oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey); - $oNewLinkObj->Set($this->m_sExtKeyToRemote, - $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields - $oNewLinkObj->Set($this->m_sExtKeyToMe, - $oCurrentObj); // Setting the extkey with the object also fills the related external fields + $oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields + $oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields } $sPrefix .= "[-$iUniqueId]["; $sNameSuffix = "]"; // To make a tabular form @@ -177,8 +171,7 @@ protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $ $sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId"; $aRow['form::checkbox'] = "m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">"; - if ($iUniqueId > 0) - { + if ($iUniqueId > 0) { // Rows created with ajax call need OnLinkAdded call. // $oP->add_ready_script( @@ -187,9 +180,7 @@ protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId, $ oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey); EOF ); - } - else - { + } else { // Rows added before loading the form don't have to call OnLinkAdded. // Listeners are already present and DOM is not recreated $iPositiveUniqueId = -$iUniqueId; @@ -377,11 +368,16 @@ public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrent $aForm = array(); $iMaxAddedId = 0; $iAddedId = -1; // Unique id for new links - while ($oCurrentLink = $oValue->Fetch()) - { + $oModified = $oValue->GetModified($this->m_sExtKeyToRemote); + while ($oCurrentLink = $oValue->Fetch()) { // We try to retrieve the remote object as usual - $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), - false /* Must not be found */); + $bModified = false; + if (array_key_exists($oCurrentLink->GetKey(), $oModified)) { + $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oModified[$oCurrentLink->GetKey()], false /* Must not be found */); + $bModified = true; + } else { + $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */); + } // If successful, it means that we can edit its link if ($oLinkedObj !== null) { $bReadOnly = false; @@ -398,9 +394,10 @@ public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrent } $iMaxAddedId = max($iMaxAddedId, $key); - $aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly); + $aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly, $bModified); } - $oBlock->iMaxAddedId = (int) $iMaxAddedId; + $oBlock->iMaxAddedId = (int)$iMaxAddedId; + $oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm); $oDataTable->SetOptions(['select_mode' => 'custom']); diff --git a/core/ormlinkset.class.inc.php b/core/ormlinkset.class.inc.php index caa5be16c6..24f1af7fdb 100644 --- a/core/ormlinkset.class.inc.php +++ b/core/ormlinkset.class.inc.php @@ -605,16 +605,32 @@ public function ListModifiedLinks() $aAdded = $this->aAdded; $aModified = $this->aModified; $aRemoved = array(); - if (count($this->aRemoved) > 0) - { + if (count($this->aRemoved) > 0) { $oSearch = new DBObjectSearch($this->sClass); $oSearch->AddCondition('id', $this->aRemoved, 'IN'); $oSet = new DBObjectSet($oSearch); $aRemoved = $oSet->ToArray(); } + return array_merge($aAdded, $aModified, $aRemoved); } + /** + * Get the list of all modified (added, modified and removed) links + * + * @return array of link objects + * @throws \Exception + */ + public function GetModified($sExtKeyToMe) + { + $aModified = []; + foreach ($this->aModified as $oObj) { + $aModified[$oObj->GetKey()] = $oObj->Get($sExtKeyToMe); + } + + return $aModified; + } + /** * @param DBObject $oHostObject * @@ -658,8 +674,7 @@ public function DBWrite(DBObject $oHostObject) { $aCheckLinks[] = $iLinkId; } - foreach ($this->aModified as $iLinkId => $oLink) - { + foreach ($this->aModified as $iLinkId => $oLink) { $aCheckLinks[] = $oLink->GetKey(); } @@ -695,8 +710,7 @@ public function DBWrite(DBObject $oHostObject) // Write the links according to the existing links // - foreach ($this->aAdded as $oLink) - { + foreach ($this->aAdded as $oLink) { // Make sure that the objects in the set point to "this" $oLink->Set($sExtKeyToMe, $oHostObject->GetKey()); diff --git a/js/linkswidget.js b/js/linkswidget.js index d7a51736c7..20758c1bad 100644 --- a/js/linkswidget.js +++ b/js/linkswidget.js @@ -385,12 +385,10 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH */ this.OnValueChange = function (iLink, iUniqueId, sAttCode, value, $oSourceObject) { let sFormPrefix = me.iInputId; - if (iLink > 0) - { + if (iLink > 0) { // Modifying an existing link let oModified = me.aModified[iLink]; - if (oModified == undefined) - { + if (oModified == undefined) { // Still not marked as modified oModified = {}; oModified['formPrefix'] = sFormPrefix; @@ -398,17 +396,26 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizH // Weird formatting, aligned with the output of the direct links widget (new links to be created) oModified['attr_'+sFormPrefix+sAttCode] = value; me.aModified[iLink] = oModified; - } - else - { + } else { // Modifying a newly added link - the structure should already be up to date - if (iUniqueId < 0) - { + if (iUniqueId < 0) { iUniqueId = -iUniqueId; } me.aAdded[iUniqueId]['attr_'+sFormPrefix+sAttCode] = value; } }; + this.AddModified = function (iLink, sFormPrefix, sAttCode, value) { + // Modifying an existing link + let oModified = me.aModified[iLink]; + if (oModified == undefined) { + // Still not marked as modified + oModified = {}; + oModified['formPrefix'] = sFormPrefix; + } + // Weird formatting, aligned with the output of the direct links widget (new links to be created) + oModified['attr_'+sFormPrefix+sAttCode] = value; + me.aModified[iLink] = oModified; + }; this.OnFormSubmit = function () { let oDiv = $('#linkedset_'+me.id);