Преглед изворни кода

N°653 Lifecycle flags can be defined on both states and transitions (Note: This is a beta version and need to be tested!)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@4688 a333f486-631f-4898-b8df-5754b55c2be0
glajarige пре 8 година
родитељ
комит
da0260c569

+ 7 - 10
application/cmdbabstract.class.inc.php

@@ -2464,16 +2464,13 @@ EOF
 		}
 		$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");
+        $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");
+        $oPage->add("<h1>$sActionDetails</h1>\n");
+        $sTargetState = $aTransitions[$sStimulus]['target_state'];
+        $aExpectedAttributes = $this->GetTransitionAttributes($sStimulus /*, current state*/);
 		$sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position');
 		if ($sButtonsPosition == 'bottom')
 		{

+ 62 - 1
core/dbobject.class.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2016 Combodo SARL
+// Copyright (C) 2010-2017 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -1060,6 +1060,67 @@ abstract class DBObject implements iDisplay
 		return $iFlags | $iSynchroFlags; // Combine both sets of flags
 	}
 
+    /**
+     * Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
+     * for the given attribute in a transition
+     * @param $sAttCode string $sAttCode The code of the attribute
+     * @param $sStimulus string The stimulus code to apply
+     * @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
+     * @param $sOriginState string The state from which to apply $sStimulus, if empty current state will be used
+     * @return integer Flags: the binary combination of the flags applicable to this attribute
+     */
+    public function GetTransitionFlags($sAttCode, $sStimulus, &$aReasons = array(), $sOriginState = '')
+    {
+        $iFlags = 0; // By default (if no lifecycle) no flag at all
+
+        $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
+        // If no state attribute, there is no lifecycle
+        if (empty($sStateAttCode))
+        {
+            return $iFlags;
+        }
+
+        // Retrieving current state if necessary
+        if ($sOriginState === '')
+        {
+            $sOriginState = $this->Get($sStateAttCode);
+        }
+
+        // Retrieving attribute flags
+        $iAttributeFlags = $this->GetAttributeFlags($sAttCode, $aReasons, $sOriginState);
+
+        // Retrieving transition flags
+        $iTransitionFlags = MetaModel::GetTransitionFlags(get_class($this), $sOriginState, $sStimulus, $sAttCode);
+
+        // Merging transition flags with attribute flags
+        $iFlags = $iTransitionFlags | $iAttributeFlags;
+
+        return $iFlags;
+    }
+
+    /**
+     * Returns an array of attribute codes (with their flags) when $sStimulus is applied on the object in the $sOriginState state.
+     * Note: Attributes (and flags) from the target state and the transition are combined.
+     *
+     * @param $sStimulus string
+     * @param $sOriginState string Default is current state
+     * @return array
+     */
+    public function GetTransitionAttributes($sStimulus, $sOriginState = null)
+    {
+        $sObjClass = get_class($this);
+
+        // Defining current state as origin state if not specified
+        if($sOriginState === null)
+        {
+            $sOriginState = $this->GetState();
+        }
+
+        $aAttributes = MetaModel::GetTransitionAttributes($sObjClass, $sStimulus, $sOriginState);
+
+        return $aAttributes;
+    }
+
 	/**
 	 * Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
 	 * for the given attribute for the current state of the object considered as an INITIAL state

+ 78 - 2
core/metamodel.class.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2016 Combodo SARL
+// Copyright (C) 2010-2017 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -27,7 +27,7 @@ require_once(APPROOT.'core/apc-compat.php');
 /**
  * Metamodel
  *
- * @copyright   Copyright (C) 2010-2016 Combodo SARL
+ * @copyright   Copyright (C) 2010-2017 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
@@ -1503,6 +1503,82 @@ abstract class MetaModel
 		}
 		return $iFlags;
 	}
+
+    /**
+     * Returns the $sAttCode flags when $sStimulus is applied on an object of $sClass in the $sState state.
+     * Note: This does NOT combine flags from the target state.
+     *
+     * @param $sClass string
+     * @param $sState string
+     * @param $sStimulus string
+     * @param $sAttCode string
+     * @return int
+     * @throws CoreException
+     */
+	public static function GetTransitionFlags($sClass, $sState, $sStimulus, $sAttCode)
+    {
+        $iFlags = 0; // By default (if no lifecycle) no flag at all
+        $sStateAttCode = self::GetStateAttributeCode($sClass);
+        if (!empty($sStateAttCode))
+        {
+            $aTransitions = MetaModel::EnumTransitions($sClass, $sState);
+            if(!array_key_exists($sStimulus, $aTransitions))
+            {
+                throw new CoreException("Invalid transition '$sStimulus' for class '$sClass', expecting a value in {".implode(', ', array_keys($aTransitions))."}");
+            }
+
+            $aCurrentTransition = $aTransitions[$sStimulus];
+            if( (array_key_exists('attribute_list', $aCurrentTransition)) && (array_key_exists($sAttCode, $aCurrentTransition['attribute_list'])) )
+            {
+                $iFlags = $aCurrentTransition['attribute_list'][$sAttCode];
+            }
+        }
+
+        return $iFlags;
+    }
+
+    /**
+     * Returns an array of attribute codes (with their flags) when $sStimulus is applied on an object of $sClass in the $sOriginState state.
+     * Note: Attributes (and flags) from the target state and the transition are combined.
+     *
+     * @param $sClass string Object class
+     * @param $sStimulus string Stimulus code applied
+     * @param $sOriginState string State the stimulus comes from
+     * @return array
+     */
+    public static function GetTransitionAttributes($sClass, $sStimulus, $sOriginState)
+    {
+        $aAttributes = array();
+
+        // Retrieving target state
+        $aTransitions = MetaModel::EnumTransitions($sClass, $sOriginState);
+        $aTransition = $aTransitions[$sStimulus];
+        $sTargetState = $aTransition['target_state'];
+
+        // Retrieving attributes from state
+        $aStates = MetaModel::EnumStates($sClass);
+        $aTargetState = $aStates[$sTargetState];
+        $aTargetStateAttributes = $aTargetState['attribute_list'];
+        // - Merging with results
+        $aAttributes = $aTargetStateAttributes;
+
+        // Retrieving attributes from transition
+        $aTransitionAttributes = $aTransition['attribute_list'];
+        // - Merging with results
+        foreach($aTransitionAttributes as $sAttCode => $iAttributeFlags)
+        {
+            if(array_key_exists($sAttCode, $aAttributes))
+            {
+                $aAttributes[$sAttCode] = $aAttributes[$sAttCode] | $iAttributeFlags;
+            }
+            else
+            {
+                $aAttributes[$sAttCode] = $iAttributeFlags;
+            }
+        }
+
+        return $aAttributes;
+    }
 	
 	/**
 	 * Combines the flags from the all states that compose the initial_state_path

+ 9 - 16
pages/UI.php

@@ -1120,17 +1120,16 @@ EOF
 			
 			$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
 			$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
-			$aTransition = $aTransitions[$sStimulus];
-			$sTargetState = $aTransition['target_state'];
+			$sTargetState = $aTransitions[$sStimulus]['target_state'];
 			$aStates = MetaModel::EnumStates($sClass);
 			$aTargetStateDef = $aStates[$sTargetState];
-			
+
 			$oP->set_title(Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass));
 			$oP->add('<div class="page_header">');
 			$oP->add('<h1>'.MetaModel::GetClassIcon($sClass).'&nbsp;'.Dict::Format('UI:StimulusModify_N_ObjectsOf_Class', $sActionLabel, count($aSelectObject), $sClass).'</h1>');
 			$oP->add('</div>');
 
-			$aExpectedAttributes = $aTargetStateDef['attribute_list'];
+			$aExpectedAttributes = MetaModel::GetTransitionAttributes($sClass, $sStimulus, $sState);
 			$aDetails = array();
 			$iFieldIndex = 0;
 			$aFieldsMap = array();
@@ -1326,16 +1325,13 @@ EOF
 					{
 						$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
 						$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
-						$aTransition = $aTransitions[$sStimulus];
-						$sTargetState = $aTransition['target_state'];
-						$aTargetStates = MetaModel::EnumStates($sClass);
-						$aTargetState = $aTargetStates[$sTargetState];
-						$aExpectedAttributes = $aTargetState['attribute_list'];
+						$sTargetState = $aTransitions[$sStimulus]['target_state'];
+						$aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /* cureent state */);
 						$aDetails = array();
 						$aErrors = array();
 						foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
 						{
-							$iFlags = $oObj->GetAttributeFlags($sAttCode);
+							$iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
 							if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') ) 
 							{
 								$paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');
@@ -1450,16 +1446,13 @@ EOF
 			{
 				$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
 				$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
-				$aTransition = $aTransitions[$sStimulus];
-				$sTargetState = $aTransition['target_state'];
-				$aTargetStates = MetaModel::EnumStates($sClass);
-				$aTargetState = $aTargetStates[$sTargetState];
-				$aExpectedAttributes = $aTargetState['attribute_list'];
+				$sTargetState = $aTransitions[$sStimulus]['target_state'];
+				$aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /*, current state*/);
 				$aDetails = array();
 				$aErrors = array();
 				foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
 				{
-					$iFlags = $oObj->GetAttributeFlags($sAttCode);
+					$iFlags = $oObj->GetTransitionFlags($sAttCode, $sStimulus);
 					if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') ) 
 					{
 						$paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data');

+ 23 - 1
setup/compiler.class.inc.php

@@ -1536,7 +1536,29 @@ EOF
 						$aVerbs[] = "array('verb' => '$sVerb', 'params' => $sActionParams)";
 					}
 					$sActions = implode(', ', $aVerbs);
-					$sLifecycle .= "		MetaModel::Init_DefineTransition(\"$sState\", \"$sStimulus\", array(\"target_state\"=>\"$sTargetState\", \"actions\"=>array($sActions), \"user_restriction\"=>null));\n";
+
+                    $sLifecycle .= "		MetaModel::Init_DefineTransition(\"$sState\", \"$sStimulus\", array(\n";
+                    $sLifecycle .= "            \"target_state\"=>\"$sTargetState\",\n";
+                    $sLifecycle .= "            \"actions\"=>array($sActions),\n";
+                    $sLifecycle .= "            \"user_restriction\"=>null,\n";
+                    $sLifecycle .= "            \"attribute_list\"=>array(\n";
+
+					$oFlags = $oTransition->GetOptionalElement('flags');
+					if($oFlags !== null)
+                    {
+                        foreach ($oFlags->getElementsByTagName('attribute') as $oAttributeNode)
+                        {
+                            $sFlags = $this->FlagsToPHP($oAttributeNode);
+                            if (strlen($sFlags) > 0)
+                            {
+                                $sAttCode = $oAttributeNode->GetAttribute('id');
+                                $sLifecycle .= "                '$sAttCode' => $sFlags,\n";
+                            }
+                        }
+                    }
+
+                    $sLifecycle .= "            )\n";
+                    $sLifecycle .= "        ));\n";
 				}
 			}
 		}

+ 11 - 1
setup/itopdesignformat.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2014-2016 Combodo SARL
+// Copyright (C) 2014-2017 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -574,6 +574,16 @@ class iTopDesignFormat
 		{
 			$this->LogWarning('The attribute _delta="force" is not supported, converted to _delta="define" ('.$iCount.' instances processed).');
 		}
+
+        // Remove attribute flags on transitions
+        //
+        $oNodeList = $oXPath->query("/itop_design/classes//class/lifecycle/states/state/transitions/transition/flags");
+        $this->LogWarning('Before removing flags nodes');
+        foreach ($oNodeList as $oNode)
+        {
+            $this->LogWarning('Attribute flags '.self::GetItopNodePath($oNode).' is irrelevant on transition and must be removed.');
+            $this->DeleteNode($oNode);
+        }
 	}