Browse Source

#935 Better support of CheckToWrite() in object's transitions

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3180 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 11 years ago
parent
commit
85163679bd
2 changed files with 163 additions and 134 deletions
  1. 133 1
      application/cmdbabstract.class.inc.php
  2. 30 133
      pages/UI.php

+ 133 - 1
application/cmdbabstract.class.inc.php

@@ -2123,6 +2123,138 @@ EOF
 		}
 		return $oObj->DisplayModifyForm( $oPage, $aExtraParams);
 	}
+	
+	public function DisplayStimulusForm(WebPage $oPage, $sStimulus)
+	{
+		$sClass = get_class($this);
+		$aTransitions = $this->EnumTransitions();
+		$aStimuli = MetaModel::EnumStimuli($sClass);
+		if (!isset($aTransitions[$sStimulus]))
+		{
+			// Invalid stimulus
+			throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $this->GetName(), $this->GetStateLabel()));
+		}
+		$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
+		$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
+		$aTransition = $aTransitions[$sStimulus];
+		$sTargetState = $aTransition['target_state'];
+		$aTargetStates = MetaModel::EnumStates($sClass);
+		$oPage->add("<div class=\"page_header\">\n");
+		$oPage->add("<h1>$sActionLabel - <span class=\"hilite\">{$this->GetName()}</span></h1>\n");
+		$oPage->set_title($sActionLabel);
+		$oPage->add("</div>\n");
+		$aTargetState = $aTargetStates[$sTargetState];
+		$aExpectedAttributes = $aTargetState['attribute_list'];
+		$oPage->add("<h1>$sActionDetails</h1>\n");
+		$sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position');
+		if ($sButtonsPosition == 'bottom')
+		{
+			// bottom: Displays the ticket details BEFORE the actions
+			$oPage->add('<div class="ui-widget-content">');
+			$this->DisplayBareProperties($oPage);
+			$oPage->add('</div>');
+		}
+		$oPage->add("<div class=\"wizContainer\">\n");
+		$oPage->add("<form id=\"apply_stimulus\" method=\"post\" onSubmit=\"return OnSubmit('apply_stimulus');\">\n");
+		$aDetails = array();
+		$iFieldIndex = 0;
+		$aFieldsMap = array();
+
+		$aDetailsList =$this->FlattenZList(MetaModel::GetZListItems($sClass, 'details'));
+		// Order the fields based on their dependencies, set the fields for which there is only one possible value
+		// and perform this in the order of dependencies to avoid dead-ends
+		$aDeps = array();
+		foreach($aDetailsList as $sAttCode)
+		{
+			$aDeps[$sAttCode] = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
+		}
+		$aList =$this->OrderDependentFields($aDeps);
+
+		foreach($aList as $sAttCode)
+		{
+			// Consider only the "expected" fields for the target state
+			if (array_key_exists($sAttCode, $aExpectedAttributes))
+			{
+				$iExpectCode = $aExpectedAttributes[$sAttCode];
+				// Prompt for an attribute if
+				// - the attribute must be changed or must be displayed to the user for confirmation
+				// - or the field is mandatory and currently empty
+				if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
+					 (($iExpectCode & OPT_ATT_MANDATORY) && ($this->Get($sAttCode) == '')) ) 
+				{
+					$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+					$aArgs = array('this' => $this);
+					// If the field is mandatory, set it to the only possible value
+					if ((!$oAttDef->IsNullAllowed()) || ($iExpectCode & OPT_ATT_MANDATORY))
+					{
+						if ($oAttDef->IsExternalKey())
+						{
+							$oAllowedValues = MetaModel::GetAllowedValuesAsObjectSet($sClass, $sAttCode, $aArgs);
+							if ($oAllowedValues->Count() == 1)
+							{
+								$oRemoteObj = $oAllowedValues->Fetch();
+								$this->Set($sAttCode, $oRemoteObj->GetKey());
+							}
+						}
+						else
+						{
+							$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
+							if (count($aAllowedValues) == 1)
+							{
+								$aValues = array_keys($aAllowedValues);
+								$this->Set($sAttCode, $aValues[0]);
+							}
+						}
+					}
+					$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,$this->Get($sAttCode),$this->GetEditValue($sAttCode), 'att_'.$iFieldIndex, '', $iExpectCode, $aArgs);
+					$aDetails[] = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => "<span id=\"field_att_$iFieldIndex\">$sHTMLValue</span>");
+					$aFieldsMap[$sAttCode] = 'att_'.$iFieldIndex;
+					$iFieldIndex++;
+				}
+			}
+		}
+
+		$oPage->add('<table><tr><td>');
+		$oPage->details($aDetails);
+		$oPage->add('</td></tr></table>');
+		$oPage->add("<input type=\"hidden\" name=\"id\" value=\"".$this->GetKey()."\" id=\"id\">\n");
+		$aFieldsMap['id'] = 'id';
+		$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n");
+		$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"apply_stimulus\">\n");
+		$oPage->add("<input type=\"hidden\" name=\"stimulus\" value=\"$sStimulus\">\n");
+		$oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">\n");
+		$oAppContext = new ApplicationContext();
+		$oPage->add($oAppContext->GetForForm());
+		$oPage->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', ".$this->GetKey().")\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
+		$oPage->add("<button type=\"submit\" class=\"action\"><span>$sActionLabel</span></button>\n");
+		$oPage->add("</form>\n");
+		$oPage->add("</div>\n");
+		if ($sButtonsPosition != 'top')
+		{
+			// bottom or both: Displays the ticket details AFTER the actions
+			$oPage->add('<div class="ui-widget-content">');
+			$this->DisplayBareProperties($oPage);
+			$oPage->add('</div>');
+		}
+
+		$iFieldsCount = count($aFieldsMap);
+		$sJsonFieldsMap = json_encode($aFieldsMap);
+
+		$oPage->add_script(
+<<<EOF
+		// Initializes the object once at the beginning of the page...
+		var oWizardHelper = new WizardHelper('$sClass', '', '$sTargetState');
+		oWizardHelper.SetFieldsMap($sJsonFieldsMap);
+		oWizardHelper.SetFieldsCount($iFieldsCount);
+EOF
+		);
+		$oPage->add_ready_script(
+<<<EOF
+		// Starts the validation when the page is ready
+		CheckFields('apply_stimulus', false);
+EOF
+		);		
+	}
 
 	public static function ProcessZlist($aList, $aDetails, $sCurrentTab, $sCurrentCol, $sCurrentSet)
 	{
@@ -2967,7 +3099,7 @@ EOF
 		if (!isset($aTransitions[$sStimulus]))
 		{
 			// Invalid stimulus
-			throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
+			throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus,$this->GetName(),$this->GetStateLabel()));
 		}
 		$aTransition = $aTransitions[$sStimulus];
 		$sTargetState = $aTransition['target_state'];

+ 30 - 133
pages/UI.php

@@ -398,6 +398,7 @@ try
 		case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
 		case 'bulk_stimulus': // For to apply a stimulus to multiple objects
 		case 'stimulus': // Form displayed when applying a stimulus (state change)
+		case 'apply_stimulus': // Form displayed when applying a stimulus (state change)
 		$oP->add_linked_script("../js/json.js");
 		$oP->add_linked_script("../js/forms-json-utils.js");
 		$oP->add_linked_script("../js/wizardhelper.js");
@@ -1381,132 +1382,7 @@ EOF
 		$oObj = MetaModel::GetObject($sClass, $id, false);
 		if ($oObj != null)
 		{
-			$aTransitions = $oObj->EnumTransitions();
-			$aStimuli = MetaModel::EnumStimuli($sClass);
-			if (!isset($aTransitions[$sStimulus]))
-			{
-				// Invalid stimulus
-				throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
-			}
-			$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
-			$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
-			$aTransition = $aTransitions[$sStimulus];
-			$sTargetState = $aTransition['target_state'];
-			$aTargetStates = MetaModel::EnumStates($sClass);
-			$oP->add("<div class=\"page_header\">\n");
-			$oP->add("<h1>$sActionLabel - <span class=\"hilite\">{$oObj->GetName()}</span></h1>\n");
-			$oP->set_title($sActionLabel);
-			$oP->add("</div>\n");
-			$aTargetState = $aTargetStates[$sTargetState];
-			$aExpectedAttributes = $aTargetState['attribute_list'];
-			$oP->add("<h1>$sActionDetails</h1>\n");
-			$sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position');
-			if ($sButtonsPosition == 'bottom')
-			{
-				// bottom: Displays the ticket details BEFORE the actions
-				$oP->add('<div class="ui-widget-content">');
-				$oObj->DisplayBareProperties($oP);
-				$oP->add('</div>');
-			}
-			$oP->add("<div class=\"wizContainer\">\n");
-			$oP->add("<form id=\"apply_stimulus\" method=\"post\" onSubmit=\"return OnSubmit('apply_stimulus');\">\n");
-			$aDetails = array();
-			$iFieldIndex = 0;
-			$aFieldsMap = array();
-
-			$aDetailsList = $oObj->FlattenZList(MetaModel::GetZListItems($sClass, 'details'));
-			// Order the fields based on their dependencies, set the fields for which there is only one possible value
-			// and perform this in the order of dependencies to avoid dead-ends
-			$aDeps = array();
-			foreach($aDetailsList as $sAttCode)
-			{
-				$aDeps[$sAttCode] = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
-			}
-			$aList = $oObj->OrderDependentFields($aDeps);
-
-			foreach($aList as $sAttCode)
-			{
-				// Consider only the "expected" fields for the target state
-				if (array_key_exists($sAttCode, $aExpectedAttributes))
-				{
-					$iExpectCode = $aExpectedAttributes[$sAttCode];
-					// Prompt for an attribute if
-					// - the attribute must be changed or must be displayed to the user for confirmation
-					// - or the field is mandatory and currently empty
-					if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
-						 (($iExpectCode & OPT_ATT_MANDATORY) && ($oObj->Get($sAttCode) == '')) ) 
-					{
-						$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
-						$aArgs = array('this' => $oObj);
-						// If the field is mandatory, set it to the only possible value
-						if ((!$oAttDef->IsNullAllowed()) || ($iExpectCode & OPT_ATT_MANDATORY))
-						{
-							if ($oAttDef->IsExternalKey())
-							{
-								$oAllowedValues = MetaModel::GetAllowedValuesAsObjectSet($sClass, $sAttCode, $aArgs);
-								if ($oAllowedValues->Count() == 1)
-								{
-									$oRemoteObj = $oAllowedValues->Fetch();
-									$oObj->Set($sAttCode, $oRemoteObj->GetKey());
-								}
-							}
-							else
-							{
-								$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
-								if (count($aAllowedValues) == 1)
-								{
-									$aValues = array_keys($aAllowedValues);
-									$oObj->Set($sAttCode, $aValues[0]);
-								}
-							}
-						}
-						$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetEditValue($sAttCode), 'att_'.$iFieldIndex, '', $iExpectCode, $aArgs);
-						$aDetails[] = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => "<span id=\"field_att_$iFieldIndex\">$sHTMLValue</span>");
-						$aFieldsMap[$sAttCode] = 'att_'.$iFieldIndex;
-						$iFieldIndex++;
-					}
-				}
-			}
-
-			$oP->add('<table><tr><td>');
-			$oP->details($aDetails);
-			$oP->add('</td></tr></table>');
-			$oP->add("<input type=\"hidden\" name=\"id\" value=\"$id\" id=\"id\">\n");
-			$aFieldsMap['id'] = 'id';
-			$oP->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n");
-			$oP->add("<input type=\"hidden\" name=\"operation\" value=\"apply_stimulus\">\n");
-			$oP->add("<input type=\"hidden\" name=\"stimulus\" value=\"$sStimulus\">\n");
-			$oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">\n");
-			$oP->add($oAppContext->GetForForm());
-			$oP->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', $id)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
-			$oP->add("<button type=\"submit\" class=\"action\"><span>$sActionLabel</span></button>\n");
-			$oP->add("</form>\n");
-			$oP->add("</div>\n");
-			if ($sButtonsPosition != 'top')
-			{
-				// bottom or both: Displays the ticket details AFTER the actions
-				$oP->add('<div class="ui-widget-content">');
-				$oObj->DisplayBareProperties($oP);
-				$oP->add('</div>');
-			}
-
-			$iFieldsCount = count($aFieldsMap);
-			$sJsonFieldsMap = json_encode($aFieldsMap);
-	
-			$oP->add_script(
-<<<EOF
-			// Initializes the object once at the beginning of the page...
-			var oWizardHelper = new WizardHelper('$sClass', '', '$sTargetState');
-			oWizardHelper.SetFieldsMap($sJsonFieldsMap);
-			oWizardHelper.SetFieldsCount($iFieldsCount);
-EOF
-);
-			$oP->add_ready_script(
-<<<EOF
-			// Starts the validation when the page is ready
-			CheckFields('apply_stimulus', false);
-EOF
-);
+			$oObj->DisplayStimulusForm($oP, $sStimulus);
 		}
 		else
 		{
@@ -1533,6 +1409,7 @@ EOF
 			$aStimuli = MetaModel::EnumStimuli($sClass);
 			$sMessage = '';
 			$sSeverity = 'ok';
+			$bDisplayDetails = true;
 			if (!isset($aTransitions[$sStimulus]))
 			{
 				throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
@@ -1572,16 +1449,33 @@ EOF
 				
 				if (count($aErrors) == 0)
 				{
-					if ($oObj->ApplyStimulus($sStimulus))
+					$sIssues = '';
+					try
 					{
-						$oObj->DBUpdate();
-						$sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
-						$sSeverity = 'ok';
+						$sPreviousState = $oObj->GetState();
+						$bApplyStimulus = $oObj->ApplyStimulus($sStimulus); // will write the object in the DB
+					}
+					catch(CoreException $e)
+					{
+						// Rollback to the previous state...
+						$oObj->Set(MetaModel::GetStateAttributeCode(get_class($oObj)), $sPreviousState);
+						$aData = $e->getContextData();
+						$sIssues = (array_key_exists('issues', $aData)) ? $aData['issues'] : 'Unknown error...';
+					}
+					if ($sIssues != '')
+					{
+						$bDisplayDetails = false;
+						// Found issues, explain and give the user a second chance
+						//
+						$oObj->DisplayStimulusForm($oP, $sStimulus);
+						$sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten',$sIssues);
+						$oP->add_ready_script("alert('".addslashes($sIssueDesc)."');");
 					}
 					else
 					{
-						$sMessage = Dict::S('UI:FailedToApplyStimuli');
-						$sSeverity = 'error';
+						$sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+						$sSeverity = 'ok';
+						utils::RemoveTransaction($sTransactionId);
 					}
 				}
 				else
@@ -1590,7 +1484,10 @@ EOF
 					$sSeverity = 'error';
 				}
 			}
-			ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
+			if ($bDisplayDetails)
+			{
+				ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity);
+			}
 		}
 		else
 		{