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

SVN:trunk[4688]
This commit is contained in:
Guillaume Lajarige
2017-04-21 14:59:04 +00:00
parent 2e8c629195
commit 2fcf50bb88
6 changed files with 190 additions and 31 deletions

View File

@@ -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')
{

View File

@@ -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

View File

@@ -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

View File

@@ -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');

View File

@@ -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";
}
}
}

View File

@@ -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);
}
}