Jelajahi Sumber

N°642 Portal: Flags on transition

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@4774 a333f486-631f-4898-b8df-5754b55c2be0
glajarige 8 tahun lalu
induk
melakukan
8652d4b993

+ 52 - 45
datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php

@@ -332,11 +332,10 @@ class ObjectController extends AbstractController
 		}
 
 		// Checking security layers
-		// TODO : This should call the stimulus check in the security helper
-//		if (!SecurityHelper::IsActionAllowed($oApp, UR_ACTION_MODIFY, $sObjectClass, $sObjectId))
-//		{
-//			$oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
-//		}
+        if(!SecurityHelper::IsStimulusAllowed($oApp, $sStimulusCode, $sObjectClass))
+		{
+			$oApp->abort(404, Dict::S('UI:ObjectDoesNotExist'));
+		}
 		
 		// Retrieving object
 		$oObject = MetaModel::GetObject($sObjectClass, $sObjectId, false /* MustBeFound */, $oApp['scope_validator']->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass));
@@ -349,34 +348,54 @@ class ObjectController extends AbstractController
 
 		// Retrieving request parameters
 		$sOperation = $oRequest->request->get('operation');
-		
-		// Preparing a dedicated form for the stimulus application
-		$aFormProperties = array(
-			'id' => 'apply-stimulus',
-			'type' => 'static',
-			'fields' => array(),
-			'layout' => null
-		);
-		// Checking which fields need to be prompt
-		$aTransitions = MetaModel::EnumTransitions($sObjectClass, $oObject->GetState());
-		$aTargetStates = MetaModel::EnumStates($sObjectClass);
-		$aTargetState = $aTargetStates[$aTransitions[$sStimulusCode]['target_state']];
-		$aExpectedAttributes = $aTargetState['attribute_list'];
-		foreach ($aExpectedAttributes as $sAttCode => $iFlags)
-		{
-			if (($iFlags & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
-				(($iFlags & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == '')))
-			{
-				$aFormProperties['fields'][$sAttCode] = array();
-				// Settings flags for the field
-				if ($iFlags & OPT_ATT_MUSTCHANGE)
-					$aFormProperties['fields'][$sAttCode]['must_change'] = true;
-				if ($iFlags & OPT_ATT_MUSTPROMPT)
-					$aFormProperties['fields'][$sAttCode]['must_prompt'] = true;
-				if (($iFlags & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == ''))
-					$aFormProperties['fields'][$sAttCode]['mandatory'] = true;
-			}
-		}
+
+		// Retrieving form properties
+        $aStimuliForms = ApplicationHelper::GetLoadedFormFromClass($oApp, $sObjectClass, 'apply_stimulus');
+        if(array_key_exists($sStimulusCode, $aStimuliForms))
+        {
+            $aFormProperties = $aStimuliForms[$sStimulusCode];
+        }
+        // Or preparing a default form for the stimulus application
+        else
+        {
+            $aFormProperties = array(
+                'id' => 'apply-stimulus',
+                'type' => 'static',
+                'fields' => array(),
+                'layout' => null
+            );
+        }
+
+        // Adding stimulus code to form
+        $aFormProperties['stimulus_code'] = $sStimulusCode;
+
+        // Checking which fields need to be prompt
+//		$aTransitions = MetaModel::EnumTransitions($sObjectClass, $oObject->GetState());
+//		$aTargetStates = MetaModel::EnumStates($sObjectClass);
+//		$aTargetState = $aTargetStates[$aTransitions[$sStimulusCode]['target_state']];
+//		$aExpectedAttributes = $oObject->GetTransitionAttributes($sStimulusCode /*, current state*/);
+//		IssueLog::Info($oObject->GetState());
+//		IssueLog::Info(print_r($aExpectedAttributes, true));
+//		foreach ($aExpectedAttributes as $sAttCode => $iFlags)
+//		{
+//			if (($iFlags & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
+//				(($iFlags & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == '')))
+//			{
+//			    if(!isset($aFormProperties['fields'][$sAttCode]))
+//                {
+//                    $aFormProperties['fields'][$sAttCode] = array();
+//                }
+//
+//				// Settings flags for the field
+//				if ($iFlags & OPT_ATT_MUSTCHANGE)
+//					$aFormProperties['fields'][$sAttCode]['must_change'] = true;
+//				if ($iFlags & OPT_ATT_MUSTPROMPT)
+//					$aFormProperties['fields'][$sAttCode]['must_prompt'] = true;
+//				if (($iFlags & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == ''))
+//					$aFormProperties['fields'][$sAttCode]['mandatory'] = true;
+//			}
+//		}
+//		IssueLog::Info(print_r($aFormProperties['fields'], true));
 		// Adding target_state to current_values
 		$oRequest->request->set('apply_stimulus', array('code' => $sStimulusCode));
 
@@ -487,12 +506,6 @@ class ObjectController extends AbstractController
 				$aStimuli = Metamodel::EnumStimuli($sObjectClass);
 				foreach ($oObject->EnumTransitions() as $sStimulusCode => $aTransitionDef)
 				{
-//					$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sObjectClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO;
-//					// Careful, $iAction is an integer whereas UR_ALLOWED_YES is a boolean, therefore we can't use a '===' operator.
-//					if ($iActionAllowed == UR_ALLOWED_YES)
-//					{
-//						$aFormData['buttons']['transitions'][$sStimulusCode] = $aStimuli[$sStimulusCode]->GetLabel();
-//					}
 					if(SecurityHelper::IsStimulusAllowed($oApp, $sStimulusCode, $sObjectClass, $oSetToCheckRights))
                     {
                         $aFormData['buttons']['transitions'][$sStimulusCode] = $aStimuli[$sStimulusCode]->GetLabel();
@@ -555,12 +568,6 @@ class ObjectController extends AbstractController
 				->SetRenderer($oFormRenderer)
 				->SetFormProperties($aFormProperties);
 
-			if ($sMode === 'apply_stimulus')
-			{
-				$aEditFormProperties = ApplicationHelper::GetLoadedFormFromClass($oApp, $sObjectClass, ObjectFormManager::ENUM_MODE_APPLY_STIMULUS);
-				$oFormManager->MergeFormProperties($aEditFormProperties);
-			}
-
 			$oFormManager->Build();
 
 			// Check the number of editable fields

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

@@ -260,6 +260,16 @@ class ObjectFormManager extends FormManager
 		return $this;
 	}
 
+    /**
+     * Returns if the form manager is handling a transition form instead of a state form.
+     *
+     * @return bool
+     */
+	public function IsTransitionForm()
+    {
+        return ($this->sMode === static::ENUM_MODE_APPLY_STIMULUS);
+    }
+
 	/**
 	 * Creates a JSON string from the current object including :
 	 * - formobject_class
@@ -314,16 +324,16 @@ class ObjectFormManager extends FormManager
 					{
 						$iFieldFlags = $iFieldFlags | OPT_ATT_SLAVE;
 					}
-					// Checking if field should be must prompt
+                    // Checking if field should be must_change
+                    if (isset($aOptions['must_change']) && ($aOptions['must_change'] === true))
+                    {
+                        $iFieldFlags = $iFieldFlags | OPT_ATT_MUSTCHANGE;
+                    }
+                    // Checking if field should be must prompt
 					if (isset($aOptions['must_prompt']) && ($aOptions['must_prompt'] === true))
 					{
 						$iFieldFlags = $iFieldFlags | OPT_ATT_MUSTPROMPT;
 					}
-					// Checking if field should be must_change
-					if (isset($aOptions['must_change']) && ($aOptions['must_change'] === true))
-					{
-						$iFieldFlags = $iFieldFlags | OPT_ATT_MUSTCHANGE;
-					}
 					// Checking if field should be hidden
 					if (isset($aOptions['hidden']) && ($aOptions['hidden'] === true))
 					{
@@ -438,10 +448,24 @@ class ObjectFormManager extends FormManager
 		// Also, retrieving mandatory attributes from metamodel to be able to complete the form with them if necessary
 		if ($this->aFormProperties['type'] !== 'static')
 		{
-			foreach (MetaModel::ListAttributeDefs($sObjectClass) as $sAttCode => $oAttDef)
+		    if($this->IsTransitionForm())
+            {
+                $aDatamodelAttCodes = $this->oObject->GetTransitionAttributes($this->aFormProperties['stimulus_code']);
+            }
+            else
+            {
+                $aDatamodelAttCodes = MetaModel::ListAttributeDefs($sObjectClass);
+            }
+
+			foreach ($aDatamodelAttCodes as $sAttCode => $value)
 			{
 				// Retrieving object flags
-				if ($this->oObject->IsNew())
+                if ($this->IsTransitionForm())
+                {
+                    // Retrieving only mandatory flag from DM when on a transition
+                    $iFieldFlags = $value & OPT_ATT_MANDATORY;
+                }
+				elseif ($this->oObject->IsNew())
 				{
 					$iFieldFlags = $this->oObject->GetInitialStateAttributeFlags($sAttCode);
 				}
@@ -454,7 +478,9 @@ class ObjectFormManager extends FormManager
 				// - only if the field if it's in fields list
 				if (array_key_exists($sAttCode, $aFieldsAtts))
 				{
-					$aFieldsAtts[$sAttCode] = $aFieldsAtts[$sAttCode] | $iFieldFlags;
+				    if($this->IsTransitionForm()) {
+                        $aFieldsAtts[$sAttCode] = $aFieldsAtts[$sAttCode] | $iFieldFlags;
+                    }
 				}
 				// - or it is mandatory and has no value
 				if ((($iFieldFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY) && ($this->oObject->Get($sAttCode) === ''))
@@ -493,12 +519,19 @@ class ObjectFormManager extends FormManager
 					{
 						$oField->SetReadOnly(true);
 					}
-					// - Else if it's mandatory and has no value, we force it as mandatory
-					elseif ((($iFieldFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY) && $oAttDef->IsNull($this->oObject->Get($sAttCode)))
-					{
-						$oField->SetMandatory(true);
-					}
-					// - Else if it wasn't mandatory or already had a value, and it's hidden, we force it as hidden
+                    // - Else if it's must change (transition), we force it as not readonly and not hidden
+                    elseif (($iFieldFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE && $this->IsTransitionForm())
+                    {
+                        $oField->SetReadOnly(false);
+                        $oField->SetHidden(false);
+                    }
+                    // - Else if it's must prompt (transition), we force it as not readonly and not hidden
+                    elseif (($iFieldFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT && $this->IsTransitionForm())
+                    {
+                        $oField->SetReadOnly(false);
+                        $oField->SetHidden(false);
+                    }
+                    // - Else if it wasn't mandatory or already had a value, and it's hidden, we force it as hidden
 					elseif (($iFieldFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN)
 					{
 						$oField->SetHidden(true);
@@ -507,23 +540,17 @@ class ObjectFormManager extends FormManager
 					{
 						$oField->SetReadOnly(true);
 					}
-					// - Else if it's must change, we force it as not readonly and not hidden
-					elseif (($iFieldFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE)
-					{
-						$oField->SetReadOnly(false);
-						$oField->SetHidden(false);
-					}
-					// - Else if it's must prompt, we force it as not readonly and not hidden
-					elseif (($iFieldFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT)
-					{
-						$oField->SetReadOnly(false);
-						$oField->SetHidden(false);
-					}
 					else
 					{
 						// Normal field
 					}
 
+                    // Finally, if it's mandatory and has no value, we force it as mandatory
+                    if ((($iFieldFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY) && $oAttDef->IsNull($this->oObject->Get($sAttCode)))
+                    {
+                        $oField->SetMandatory(true);
+                    }
+
 					// Specific operation on field
 					// - Field that require a transaction id
 					if (in_array(get_class($oField), array('Combodo\\iTop\\Form\\Field\\TextAreaField', 'Combodo\\iTop\\Form\\Field\\CaseLogField')))
@@ -719,7 +746,11 @@ class ObjectFormManager extends FormManager
 					$oField->SetReadOnly(true);
 				}
 
-				$oForm->AddField($oField);
+				// Adding attachements field in transition only if it is editable
+				if(!$this->IsTransitionForm() || ($this->IsTransitionForm() && !$oField->GetReadOnly()) )
+                {
+                    $oForm->AddField($oField);
+                }
 			}
 		}
 
@@ -729,87 +760,6 @@ class ObjectFormManager extends FormManager
 	}
 
 	/**
-	 * Merging $this->aFormProperties with $aFormPropertiesToMerge. Merge only layout for now
-	 *
-	 * @param array $aFormPropertiesToMerge
-	 * @throws Exception
-	 */
-	public function MergeFormProperties($aFormPropertiesToMerge)
-	{
-		if ($aFormPropertiesToMerge['layout'] !== null)
-		{
-			// Checking if we need to render the template from twig to html in order to parse the fields
-			if ($aFormPropertiesToMerge['layout']['type'] === 'twig')
-			{
-				// Creating sandbox twig env. to load and test the custom form template
-				$oTwig = new \Twig_Environment(new \Twig_Loader_String());
-				$sRendered = $oTwig->render($aFormPropertiesToMerge['layout']['content'], array('oRenderer' => $this->oRenderer, 'oObject' => $this->oObject));
-			}
-			else
-			{
-				$sRendered = $aFormPropertiesToMerge['layout']['content'];
-			}
-
-			// Parsing rendered template to find the fields
-			$oHtmlDocument = new \DOMDocument();
-			$oHtmlDocument->loadHTML('<root>' . $sRendered . '</root>');
-
-			// Adding fields to the list
-			$oXPath = new \DOMXPath($oHtmlDocument);
-			foreach ($oXPath->query('//div[@class="form_field"][@data-field-id]') as $oFieldNode)
-			{
-				$sFieldId = $oFieldNode->getAttribute('data-field-id');
-				$sFieldFlags = $oFieldNode->getAttribute('data-field-flags');
-//				$iFieldFlags = OPT_ATT_NORMAL;
-
-//				// Checking if field has form_path, if not, we add it
-//				if (!$oFieldNode->hasAttribute('data-form-path'))
-//				{
-//					$oFieldNode->setAttribute('data-form-path', $oForm->GetId());
-//				}
-				// Merging only fields that are already in the form
-				if (array_key_exists($sFieldId, $this->aFormProperties['fields']))
-				{
-					// Settings field flags from the data-field-flags attribute
-					foreach (explode(' ', $sFieldFlags) as $sFieldFlag)
-					{
-						if ($sFieldFlag !== '')
-						{
-							$sConst = 'OPT_ATT_' . strtoupper(str_replace('_', '', $sFieldFlag));
-							if (defined($sConst))
-							{
-								switch ($sConst)
-								{
-									case 'OPT_ATT_SLAVE':
-									case 'OPT_ATT_HIDDEN':
-										if (!array_key_exists($sFieldId, $this->aFormProperties['fields']))
-										{
-											$this->aFormProperties['fields'][$sFieldId] = array();
-										}
-										$this->aFormProperties['fields'][$sFieldId]['hidden'] = true;
-										break;
-									case 'OPT_ATT_READONLY':
-										if (!array_key_exists($sFieldId, $this->aFormProperties['fields']))
-										{
-											$this->aFormProperties['fields'][$sFieldId] = array();
-										}
-										$this->aFormProperties['fields'][$sFieldId]['read_only'] = true;
-										break;
-								}
-							}
-							else
-							{
-								IssueLog::Error(__METHOD__ . ' at line ' . __LINE__ . ' : Flag "' . $sFieldFlag . '" is not valid for field [@data-field-id="' . $sFieldId . '"] in form[@id="' . $aFormPropertiesToMerge['id'] . '"]');
-								throw new Exception('Flag "' . $sFieldFlag . '" is not valid for field [@data-field-id="' . $sFieldId . '"] in form[@id="' . $aFormPropertiesToMerge['id'] . '"]');
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
 	 * Calls all form fields OnCancel method in order to delegate them the cleanup;
 	 *
 	 * @param array $aArgs

+ 48 - 7
datamodels/2.x/itop-portal-base/portal/src/helpers/applicationhelper.class.inc.php

@@ -878,7 +878,8 @@ class ApplicationHelper
                         }
                     }
 
-					// Parsing availables modes for that form (view, edit, create)
+					// Parsing availables modes for that form (view, edit, create, apply_stimulus)
+                    $aFormStimuli = array();
 					if (($oFormNode->GetOptionalElement('modes') !== null) && ($oFormNode->GetOptionalElement('modes')->GetNodes('mode')->length > 0))
 					{
 						$aModes = array();
@@ -892,10 +893,25 @@ class ApplicationHelper
 							{
 								throw new DOMFormatException('Mode tag must have an id attribute', null, null, $oFormNode);
 							}
+
+							// If apply_stimulus mode, checking if stimuli are defined
+                            if ($oModeNode->getAttribute('id') === 'apply_stimulus')
+                            {
+                                $oStimuliNode = $oModeNode->GetOptionalElement('stimuli');
+                                if($oStimuliNode !== null)
+                                {
+                                    foreach ($oStimuliNode->GetNodes('stimulus') as $oStimulusNode)
+                                    {
+                                        $aFormStimuli[] = $oStimulusNode->getAttribute('id');
+                                    }
+                                }
+                            }
 						}
 					}
 					else
 					{
+					    // If no mode was specified, we set it all but stimuli as it would have no sense that every transition forms
+                        // have as many fields displayed as a regular edit form for example.
 						$aModes = array('view', 'edit', 'create');
 					}
 
@@ -941,11 +957,6 @@ class ApplicationHelper
 							}
 						}
 					}
-//					// ... or a specified zlist
-//					elseif ($oFormNode->GetOptionalElement('presentation') !== null)
-//					{
-//						// This is not implemented yet as it was rejected until futher notice.
-//					}
 					// ... or the default zlist
 					else
 					{
@@ -953,6 +964,25 @@ class ApplicationHelper
 						$aFields['fields'] = 'details';
 					}
 
+					// Adding stimuli if explicitly defined
+                    if(in_array('apply_stimulus', $aModes))
+                    {
+                        // If stimuli are implicitly defined (empty tag), we define all those that have not already been by other forms.
+                        if(empty($aFormStimuli))
+                        {
+                            // Stimuli already declared
+                            $aDeclaredStimuli = array();
+                            if(array_key_exists($sFormClass, $aForms) && array_key_exists('apply_stimulus', $aForms[$sFormClass]))
+                            {
+                                $aDeclaredStimuli = array_keys($aForms[$sFormClass]['apply_stimulus']);
+                            }
+                            // All stimuli
+                            $aDatamodelStimuli = array_keys(MetaModel::EnumStimuli($sFormClass));
+                            // Missing stimuli
+                            $aFormStimuli = array_diff($aDatamodelStimuli, $aDeclaredStimuli);
+                        }
+                    }
+
 					// Parsing presentation
 					if ($oFormNode->GetOptionalElement('twig') !== null)
 					{
@@ -975,7 +1005,18 @@ class ApplicationHelper
 							$aForms[$sFormClass] = array();
 						}
 
-						if (!isset($aForms[$sFormClass][$sMode]))
+						if ($sMode === 'apply_stimulus')
+                        {
+                            foreach($aFormStimuli as $sFormStimulus)
+                            {
+                                if(!isset($aForms[$sFormClass][$sMode][$sFormStimulus]))
+                                {
+                                    $aForms[$sFormClass][$sMode][$sFormStimulus] = $aFields;
+                                    $aForms[$sFormClass][$sMode][$sFormStimulus]['id'] = 'apply_stimulus-'.$sFormClass.'-'.$sFormStimulus;
+                                }
+                            }
+                        }
+						elseif (!isset($aForms[$sFormClass][$sMode]))
 						{
 							$aForms[$sFormClass][$sMode] = $aFields;
 						}