Parcourir la source

N°744 Portal: Prevented LinkedSet corruption through simultaneous updates. In the portal are now update incremantally like in the console. This needs to be tested with both 1:n and n:n LinkedSet

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@4857 a333f486-631f-4898-b8df-5754b55c2be0
glajarige il y a 7 ans
Parent
commit
7349d504c3

+ 44 - 52
datamodels/2.x/itop-portal-base/portal/src/forms/objectformmanager.class.inc.php

@@ -1014,6 +1014,7 @@ class ObjectFormManager extends FormManager
 				{
 					if (MetaModel::IsValidAttCode($sObjectClass, $sAttCode))
 					{
+					    /** @var \AttributeDefinition $oAttDef */
 						$oAttDef = MetaModel::GetAttributeDef($sObjectClass, $sAttCode);
 						if ($oAttDef->IsLinkSet())
 						{
@@ -1023,59 +1024,50 @@ class ObjectFormManager extends FormManager
 							// Which was an issue when deleting all objects from linkedset
 							$value = json_decode($value, true);
 
-							// Creating set from objects of the form
-							$sTargetClass = $oAttDef->GetLinkedClass();
-							$oValueSet = DBObjectSet::FromScratch($sTargetClass);
-							foreach ($value as $aValue)
-							{
-								$iTargetId = (int) $aValue['id'];
-								// LinkedSet
-								if (!$oAttDef->IsIndirect())
-								{
-									// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
-									$oLinkedObject = MetaModel::GetObject($sTargetClass, abs($iTargetId), true, true);
-									$oValueSet->AddObject($oLinkedObject);
-								}
-								// LinkedSetIndirect
-								else
-								{
-									// New relation
-									if ($iTargetId < 0)
-									{
-										$oLink = MetaModel::NewObject($sTargetClass);
-										$oLink->Set($oAttDef->GetExtKeyToRemote(), -1 * $iTargetId);
-										$oLink->Set($oAttDef->GetExtKeyToMe(), $this->oObject->GetKey());
-									}
-									// Existing relation
-									else
-									{
-										// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
-										$oLink = MetaModel::GetObject($sTargetClass, $iTargetId, true, true);
-									}
-									$oValueSet->AddObject($oLink);
-								}
-							}
-							// Comparing set from db to set from form if linkedset is DIRECT in order to identify removed objects
-							if (!$oAttDef->IsIndirect())
-							{
-								// Retrieving remote object's extkey definition in order to nullify it or completely remove the object regarding its mandatory status
-								$oExtKeyToMeAttDef = MetaModel::GetAttributeDef($sTargetClass, $oAttDef->GetExtKeyToMe());
-								if ($oExtKeyToMeAttDef->IsNullAllowed())
-								{
-									// Comparing sets
-									$oDBSet = $this->oObject->Get($sAttCode);
-									$oDBSetComparator = new DBObjectSetComparator($oDBSet, $oValueSet);
-									$aDBSetDifferences = $oDBSetComparator->GetDifferences();
-									// Nullifying remote object's ext key
-									foreach ($aDBSetDifferences['removed'] as $oRemovedLinkedObject)
-									{
-										$oRemovedLinkedObject->Set($oExtKeyToMeAttDef->GetCode(), $oExtKeyToMeAttDef->GetNullValue());
-										$oValueSet->AddObject($oRemovedLinkedObject);
-									}
-								}
-							}
+							/** @var \ormLinkSet $oLinkSet */
+                            $oLinkSet = $this->oObject->Get($sAttCode);
+                            $sLinkedClass = $oAttDef->GetLinkedClass();
+
+                            // Checking links to remove
+                            if(isset($value['remove']))
+                            {
+                                foreach($value['remove'] as $iObjKey => $aObjData)
+                                {
+                                    $oLinkSet->RemoveItem($iObjKey);
+                                }
+                            }
+
+							// Checking links to add
+                            if(isset($value['add']))
+                            {
+                                foreach($value['add'] as $iObjKey => $aObjdata)
+                                {
+                                    // Creating link when linkset is indirect...
+                                    if($oAttDef->IsIndirect())
+                                    {
+                                        $oLink = MetaModel::NewObject($sLinkedClass);
+                                        $oLink->Set($oAttDef->GetExtKeyToRemote(), $iObjKey);
+                                        $oLink->Set($oAttDef->GetExtKeyToMe(), $this->oObject->GetKey());
+                                    }
+                                    // ... or adding remote object when linkset id direct
+                                    else
+                                    {
+                                        // Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
+                                        $oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false, true);
+                                    }
+
+                                    if($oLink !== null)
+                                    {
+                                        $oLinkSet->AddItem($oLink);
+                                    }
+                                }
+                            }
+
+                            // Checking links to modify
+                            // TODO: Not implemented yet as we can't change lnk properties in the portal
+
 							// Setting value in the object
-							$this->oObject->Set($sAttCode, $oValueSet);
+							$this->oObject->Set($sAttCode, $oLinkSet);
 						}
 					    else if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime
 					    {

+ 45 - 25
sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php

@@ -57,9 +57,9 @@ class BsLinkedSetFieldRenderer extends FieldRenderer
 		$aItemIds = array();
 		$this->PrepareItems($aItems, $aItemIds);
 		$sItemsAsJson = json_encode($aItems);
-		$sItemIdsAsJson = htmlentities(json_encode($aItemIds), ENT_QUOTES, 'UTF-8');
-		
-		if (!$this->oField->GetHidden())
+        $sItemIdsAsJson = htmlentities(json_encode(array('current' => $aItemIds)), ENT_QUOTES, 'UTF-8');
+
+        if (!$this->oField->GetHidden())
 		{
 			// Rendering field
 			$sIsEditable = ($this->oField->GetReadOnly()) ? 'false' : 'true';
@@ -331,10 +331,11 @@ EOF
 									// Updating datatables
 									if(oData.items !== undefined)
 									{
-										for(var i in oData.items)
+									    for(var i in oData.items)
 										{
 											// Adding target item id information
 											oData.items[i].target_id = oData.items[i].id;
+											
 											// Adding item to table only if it's not already there
 											if($('#{$sTableId} tr[role="row"] > td input[data-target-object-id="' + oData.items[i].target_id + '"], #{$sTableId} tr[role="row"] > td input[data-target-object-id="' + (oData.items[i].target_id*-1) + '"]').length === 0)
 											{
@@ -342,22 +343,17 @@ EOF
 												oData.items[i].id = -1 * parseInt(oData.items[i].id);
 												oTable_{$this->oField->GetGlobalId()}.row.add(oData.items[i]);
 											}
+											
+											
 										}
 										oTable_{$this->oField->GetGlobalId()}.draw();
+										
+										// Updating input
+						                updateInputValue_{$this->oField->GetGlobalId()}();
 									}
 								}
 							)
 							.done(function(oData){
-								// Updating hidden field
-								var aData = oTable_{$this->oField->GetGlobalId()}.rows().data().toArray();
-								var aObjectIds = [];
-
-								for(var i in aData)
-								{
-									aObjectIds.push({id: aData[i].id});
-								}
-
-								$('#{$this->oField->GetGlobalId()}').val(JSON.stringify(aObjectIds));
 								// Updating items count
 								updateItemCount_{$this->oField->GetGlobalId()}();
 								// Updating global checkbox
@@ -371,16 +367,8 @@ EOF
 						// We come from a button
 						else
 						{
-							// Updating hidden field
-							var aData = oTable_{$this->oField->GetGlobalId()}.rows().data().toArray();
-							var aObjectIds = [];
-
-							for(var i in aData)
-							{
-								aObjectIds.push({id: aData[i].id});
-							}
-
-							$('#{$this->oField->GetGlobalId()}').val(JSON.stringify(aObjectIds));
+						    // Updating input
+						    updateInputValue_{$this->oField->GetGlobalId()}();
 							// Updating items count
 							updateItemCount_{$this->oField->GetGlobalId()}();
 							// Updating global checkbox
@@ -429,6 +417,38 @@ EOF
 					{
 						$('#{$sCollapseTogglerId} > .text').text( oTable_{$this->oField->GetGlobalId()}.rows().count() );
 					};
+					// - Field input handler
+					var updateInputValue_{$this->oField->GetGlobalId()} = function()
+					{
+					    // Retrieving table rows
+					    var aData = oTable_{$this->oField->GetGlobalId()}.rows().data().toArray();
+					    
+					    // Retrieving input values
+                        var oValues = JSON.parse($('#{$this->oField->GetGlobalId()}').val());
+                        oValues.add = {};
+                        oValues.remove = {};
+                        
+					    // Checking removed objects
+					    for(var i in oValues.current)
+					    {
+					        if($('#{$sTableId} tr[role="row"] input[data-object-id="'+i+'"]').length === 0)
+                            {
+                                oValues.remove[i] = {};
+                            }
+					    }
+					    
+					    // Checking added objects
+					    for(var i in aData)
+					    {
+					        if(oValues.current[aData[i].id] === undefined)
+					        {
+					            oValues.add[aData[i].target_id] = {};
+                            }
+					    }
+					    
+                        // Setting input values
+                        $('#{$this->oField->GetGlobalId()}').val(JSON.stringify(oValues));
+					};
 
 					// Handles items remove/add
 					$('#{$sButtonRemoveId}').off('click').on('click', function(){
@@ -555,7 +575,7 @@ EOF
 			}
 			
 			$aItems[] = $aItemProperties;
-			$aItemIds[] = array('id' => $aItemProperties['id']);
+			$aItemIds[$aItemProperties['id']] = array();
 		}
 	}