public function __construct($sClass, $sAttCode, $iInputId, $sNameSuffix = '', $bDuplicatesAllowed = false)
 {
     $this->m_sClass = $sClass;
     $this->m_sAttCode = $sAttCode;
     $this->m_sNameSuffix = $sNameSuffix;
     $this->m_iInputId = $iInputId;
     $this->m_bDuplicatesAllowed = $bDuplicatesAllowed;
     $this->m_aEditableFields = array();
     $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
     $this->m_sLinkedClass = $oAttDef->GetLinkedClass();
     $this->m_sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
     $this->m_sExtKeyToMe = $oAttDef->GetExtKeyToMe();
     $oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
     $this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
     $sExtKeyToMe = $oAttDef->GetExtKeyToMe();
     $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
     $sDefaultState = MetaModel::GetDefaultState($this->m_sClass);
     $this->m_aEditableFields = array();
     $this->m_aTableConfig = array();
     $this->m_aTableConfig['form::checkbox'] = array('label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget" . $this->m_iInputId . ".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
     foreach (MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode) {
         $oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
         if ($sStateAttCode == $sAttCode) {
             // State attribute is always hidden from the UI
         } else {
             if ($oAttDef->IsWritable() && $sAttCode != $sExtKeyToMe && $sAttCode != $this->m_sExtKeyToRemote && $sAttCode != 'finalclass') {
                 $iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
                 if (!($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY)) {
                     $this->m_aEditableFields[] = $sAttCode;
                     $this->m_aTableConfig[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
                 }
             }
         }
     }
     $this->m_aTableConfig['static::key'] = array('label' => MetaModel::GetName($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass));
     foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode) {
         // TO DO: check the state of the attribute: hidden or visible ?
         if ($sFieldCode != 'finalclass') {
             $oAttDef = MetaModel::GetAttributeDef($this->m_sRemoteClass, $sFieldCode);
             $this->m_aTableConfig['static::' . $sFieldCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
         }
     }
 }
예제 #2
0
/**
 * Helper to generate a Graphviz code for displaying the life cycle of a class
 * @param string $sClass The class to display
 * @return string The Graph description in Graphviz/Dot syntax   
 */
function GraphvizLifecycle($sClass)
{
    $sDotFileContent = "";
    $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
    if (empty($sStateAttCode)) {
        //$oPage->p("no lifecycle for this class");
    } else {
        $aStates = MetaModel::EnumStates($sClass);
        $aStimuli = MetaModel::EnumStimuli($sClass);
        $sDotFileContent .= "digraph finite_state_machine {\r\n\tgraph [bgcolor = \"transparent\"];\r\n\trankdir=LR;\r\n\tsize=\"12,12\"\r\n\tnode [ fontname=Verdana style=filled fillcolor=\"#ffffff\" ];\r\n\tedge [ fontname=Verdana ];\r\n";
        $aStatesLinks = array();
        foreach ($aStates as $sStateCode => $aStateDef) {
            $aStatesLinks[$sStateCode] = array('in' => 0, 'out' => 0);
        }
        foreach ($aStates as $sStateCode => $aStateDef) {
            $sStateLabel = MetaModel::GetStateLabel($sClass, $sStateCode);
            $sStateDescription = MetaModel::GetStateDescription($sClass, $sStateCode);
            foreach (MetaModel::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) {
                $aStatesLinks[$sStateCode]['out']++;
                $aStatesLinks[$aTransitionDef['target_state']]['in']++;
                $sStimulusLabel = $aStimuli[$sStimulusCode]->GetLabel();
                $sTargetStateLabel = MetaModel::GetStateLabel($sClass, $aTransitionDef['target_state']);
                $sDotFileContent .= "\t{$sStateCode} -> {$aTransitionDef['target_state']} [ label=\"" . GraphvizEscape($sStimulusLabel) . "\"];\n";
            }
        }
        foreach ($aStates as $sStateCode => $aStateDef) {
            if ($aStatesLinks[$sStateCode]['out'] > 0 || $aStatesLinks[$sStateCode]['in'] > 0) {
                // Show only reachable states
                $sStateLabel = str_replace(' ', '\\n', MetaModel::GetStateLabel($sClass, $sStateCode));
                if ($aStatesLinks[$sStateCode]['in'] == 0 || $aStatesLinks[$sStateCode]['out'] == 0) {
                    // End or Start state, make it look different
                    $sDotFileContent .= "\t{$sStateCode} [ shape=doublecircle,label=\"" . GraphvizEscape($sStateLabel) . "\"];\n";
                } else {
                    $sDotFileContent .= "\t{$sStateCode} [ shape=circle,label=\"" . GraphvizEscape($sStateLabel) . "\"];\n";
                }
            }
        }
        $sDotFileContent .= "}\n";
    }
    return $sDotFileContent;
}
예제 #3
0
 /**
  * Constructs the PHP target object from the parameters sent to the web page by the wizard
  * @param boolean $bReadUploadedFiles True to also ready any uploaded file (for blob/document fields)
  * @return object
  */
 public function GetTargetObject($bReadUploadedFiles = false)
 {
     if (isset($this->m_aData['m_oCurrentValues']['id'])) {
         $oObj = MetaModel::GetObject($this->m_aData['m_sClass'], $this->m_aData['m_oCurrentValues']['id']);
     } else {
         $oObj = MetaModel::NewObject($this->m_aData['m_sClass']);
     }
     foreach ($this->m_aData['m_oCurrentValues'] as $sAttCode => $value) {
         // Because this is stored in a Javascript array, unused indexes
         // are filled with null values and unused keys (stored as strings) contain $$NULL$$
         if ($sAttCode != 'id' && $sAttCode !== false && $value !== null && $value !== '$$NULL$$') {
             $oAttDef = MetaModel::GetAttributeDef($this->m_aData['m_sClass'], $sAttCode);
             if ($oAttDef->IsLinkSet() && $value != '') {
                 // special handling for lists
                 // assumes this is handled as an array of objects
                 // thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
                 $aData = json_decode($value, true);
                 // true means decode as a hash array (not an object)
                 // Check what are the meaningful attributes
                 $aFields = $this->GetLinkedWizardStructure($oAttDef);
                 $sLinkedClass = $oAttDef->GetLinkedClass();
                 $aLinkedObjectsArray = array();
                 if (!is_array($aData)) {
                     echo "aData: '{$aData}' (value: '{$value}')\n";
                 }
                 foreach ($aData as $aLinkedObject) {
                     $oLinkedObj = MetaModel::NewObject($sLinkedClass);
                     foreach ($aFields as $sLinkedAttCode) {
                         if (isset($aLinkedObject[$sLinkedAttCode]) && $aLinkedObject[$sLinkedAttCode] !== null) {
                             $sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
                             if ($sLinkedAttDef->IsExternalKey() && $aLinkedObject[$sLinkedAttCode] != '' && $aLinkedObject[$sLinkedAttCode] > 0) {
                                 // For external keys: load the target object so that external fields
                                 // get filled too
                                 $oTargetObj = MetaModel::GetObject($sLinkedAttDef->GetTargetClass(), $aLinkedObject[$sLinkedAttCode]);
                                 $oLinkedObj->Set($sLinkedAttCode, $oTargetObj);
                             } else {
                                 $oLinkedObj->Set($sLinkedAttCode, $aLinkedObject[$sLinkedAttCode]);
                             }
                         }
                     }
                     $aLinkedObjectsArray[] = $oLinkedObj;
                 }
                 $oSet = DBObjectSet::FromArray($sLinkedClass, $aLinkedObjectsArray);
                 $oObj->Set($sAttCode, $oSet);
             } else {
                 if ($oAttDef->GetEditClass() == 'Document') {
                     if ($bReadUploadedFiles) {
                         $oDocument = utils::ReadPostedDocument('attr_' . $sAttCode, 'fcontents');
                         $oObj->Set($sAttCode, $oDocument);
                     } else {
                         // Create a new empty document, just for displaying the file name
                         $oDocument = new ormDocument(null, '', $value);
                         $oObj->Set($sAttCode, $oDocument);
                     }
                 } else {
                     if ($oAttDef->IsExternalKey() && !empty($value) && $value > 0) {
                         // For external keys: load the target object so that external fields
                         // get filled too
                         $oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $value);
                         $oObj->Set($sAttCode, $oTargetObj);
                     } else {
                         $oObj->Set($sAttCode, $value);
                     }
                 }
             }
         }
     }
     if (isset($this->m_aData['m_sState']) && !empty($this->m_aData['m_sState'])) {
         $oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
     }
     $oObj->DoComputeValues();
     return $oObj;
 }
    /**
     * Display a form for modifying several objects at once
     * The form will be submitted to the current page, with the specified additional values	 
     */
    public static function DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, $sCustomOperation, $sCancelUrl, $aExcludeAttributes = array(), $aContextData = array())
    {
        if (count($aSelectedObj) > 0) {
            $iAllowedCount = count($aSelectedObj);
            $sSelectedObj = implode(',', $aSelectedObj);
            $sOQL = "SELECT {$sClass} WHERE id IN (" . $sSelectedObj . ")";
            $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL));
            // Compute the distribution of the values for each field to determine which of the "scalar" fields are homogenous
            $aList = MetaModel::ListAttributeDefs($sClass);
            $aValues = array();
            foreach ($aList as $sAttCode => $oAttDef) {
                if ($oAttDef->IsScalar()) {
                    $aValues[$sAttCode] = array();
                }
            }
            while ($oObj = $oSet->Fetch()) {
                foreach ($aList as $sAttCode => $oAttDef) {
                    if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) {
                        $currValue = $oObj->Get($sAttCode);
                        if ($oAttDef instanceof AttributeCaseLog) {
                            $currValue = ' ';
                            // Don't put an empty string, in case the field would be considered as mandatory...
                        }
                        if (is_object($currValue)) {
                            continue;
                        }
                        // Skip non scalar values...
                        if (!array_key_exists($currValue, $aValues[$sAttCode])) {
                            $aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode));
                        } else {
                            $aValues[$sAttCode][$currValue]['count']++;
                        }
                    }
                }
            }
            // Now create an object that has values for the homogenous values only
            $oDummyObj = new $sClass();
            // @@ What if the class is abstract ?
            $aComments = array();
            function MyComparison($a, $b)
            {
                if ($a['count'] == $b['count']) {
                    return 0;
                }
                return $a['count'] > $b['count'] ? -1 : 1;
            }
            $iFormId = cmdbAbstractObject::GetNextFormId();
            // Identifier that prefixes all the form fields
            $sReadyScript = '';
            $aDependsOn = array();
            $sFormPrefix = '2_';
            foreach ($aList as $sAttCode => $oAttDef) {
                $aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
                // List of attributes that are needed for the current one
                if (count($aPrerequisites) > 0) {
                    // When 'enabling' a field, all its prerequisites must be enabled too
                    $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aPrerequisites) . "']";
                    $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, true); } );\n");
                }
                $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode);
                // List of attributes that are needed for the current one
                if (count($aDependents) > 0) {
                    // When 'disabling' a field, all its dependent fields must be disabled too
                    $sFieldList = "['{$sFormPrefix}" . implode("','{$sFormPrefix}", $aDependents) . "']";
                    $oP->add_ready_script("\$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, false); } );\n");
                }
                if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) {
                    if ($oAttDef->GetEditClass() == 'One Way Password') {
                        $sTip = "Unknown values";
                        $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );";
                        $oDummyObj->Set($sAttCode, null);
                        $aComments[$sAttCode] = '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                        $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '"> ? </div>';
                        $sReadyScript .= 'ToogleField(false, \'' . $iFormId . '_' . $sAttCode . '\');' . "\n";
                    } else {
                        $iCount = count($aValues[$sAttCode]);
                        if ($iCount == 1) {
                            // Homogenous value
                            reset($aValues[$sAttCode]);
                            $aKeys = array_keys($aValues[$sAttCode]);
                            $currValue = $aKeys[0];
                            // The only value is the first key
                            //echo "<p>current value for $sAttCode : $currValue</p>";
                            $oDummyObj->Set($sAttCode, $currValue);
                            $aComments[$sAttCode] = '';
                            if ($sAttCode != MetaModel::GetStateAttributeCode($sClass)) {
                                $aComments[$sAttCode] .= '<input type="checkbox" checked id="enable_' . $iFormId . '_' . $sAttCode . '"  onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                            }
                            $aComments[$sAttCode] .= '<div class="mono_value">1</div>';
                        } else {
                            // Non-homogenous value
                            $aMultiValues = $aValues[$sAttCode];
                            uasort($aMultiValues, 'MyComparison');
                            $iMaxCount = 5;
                            $sTip = "<p><b>" . Dict::Format('UI:BulkModify_Count_DistinctValues', $iCount) . "</b><ul>";
                            $index = 0;
                            foreach ($aMultiValues as $sCurrValue => $aVal) {
                                $sDisplayValue = empty($aVal['display']) ? '<i>' . Dict::S('Enum:Undefined') . '</i>' : str_replace(array("\n", "\r"), " ", $aVal['display']);
                                $sTip .= "<li>" . Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count']) . "</li>";
                                $index++;
                                if ($iMaxCount == $index) {
                                    $sTip .= "<li>" . Dict::Format('UI:BulkModify:N_MoreValues', count($aMultiValues) - $iMaxCount) . "</li>";
                                    break;
                                }
                            }
                            $sTip .= "</ul></p>";
                            $sTip = addslashes($sTip);
                            $sReadyScript .= "\$('#multi_values_{$sAttCode}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );";
                            $oDummyObj->Set($sAttCode, null);
                            $aComments[$sAttCode] = '';
                            if ($sAttCode != MetaModel::GetStateAttributeCode($sClass)) {
                                $aComments[$sAttCode] .= '<input type="checkbox" id="enable_' . $iFormId . '_' . $sAttCode . '" onClick="ToogleField(this.checked, \'' . $iFormId . '_' . $sAttCode . '\')"/>';
                            }
                            $aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_' . $sAttCode . '">' . $iCount . '</div>';
                        }
                        $sReadyScript .= 'ToogleField(' . ($iCount == 1 ? 'true' : 'false') . ', \'' . $iFormId . '_' . $sAttCode . '\');' . "\n";
                    }
                }
            }
            $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
            if ($sStateAttCode != '' && $oDummyObj->GetState() == '') {
                // Hmmm, it's not gonna work like this ! Set a default value for the "state"
                // Maybe we should use the "state" that is the most common among the objects...
                $aMultiValues = $aValues[$sStateAttCode];
                uasort($aMultiValues, 'MyComparison');
                foreach ($aMultiValues as $sCurrValue => $aVal) {
                    $oDummyObj->Set($sStateAttCode, $sCurrValue);
                    break;
                }
                //$oStateAtt = MetaModel::GetAttributeDef($sClass, $sStateAttCode);
                //$oDummyObj->Set($sStateAttCode, $oStateAtt->GetDefaultValue());
            }
            $oP->add("<div class=\"page_header\">\n");
            $oP->add("<h1>" . $oDummyObj->GetIcon() . "&nbsp;" . Dict::Format('UI:Modify_M_ObjectsOf_Class_OutOf_N', $iAllowedCount, $sClass, $iAllowedCount) . "</h1>\n");
            $oP->add("</div>\n");
            $oP->add("<div class=\"wizContainer\">\n");
            $sDisableFields = json_encode($aExcludeAttributes);
            $aParams = array('fieldsComments' => $aComments, 'noRelations' => true, 'custom_operation' => $sCustomOperation, 'custom_button' => Dict::S('UI:Button:PreviewModifications'), 'selectObj' => $sSelectedObj, 'preview_mode' => true, 'disabled_fields' => $sDisableFields, 'disable_plugins' => true);
            $aParams = $aParams + $aContextData;
            // merge keeping associations
            $oDummyObj->DisplayModifyForm($oP, $aParams);
            $oP->add("</div>\n");
            $oP->add_ready_script($sReadyScript);
            $oP->add_ready_script(<<<EOF
\$('.wizContainer button.cancel').unbind('click');
\$('.wizContainer button.cancel').click( function() { window.location.href = '{$sCancelUrl}'; } );
EOF
);
        } else {
            $oP->p("No object selected !, nothing to do");
        }
    }
예제 #5
0
 public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
 {
     $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this->m_oObj));
     $aTemplateFields = array();
     preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
     foreach ($aMatches[1] as $sAttCode) {
         if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) {
             $aTemplateFields[] = $sAttCode;
         } else {
             $aParams['this->' . $sAttCode] = "<!--Unknown attribute: {$sAttCode}-->";
         }
     }
     preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
     foreach ($aMatches[1] as $sAttCode) {
         if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode)) {
             $aTemplateFields[] = $sAttCode;
         } else {
             $aParams['this->field(' . $sAttCode . ')'] = "<!--Unknown attribute: {$sAttCode}-->";
         }
     }
     $aFieldsComments = isset($aParams['fieldsComments']) ? $aParams['fieldsComments'] : array();
     $aFieldsMap = array();
     $sClass = get_class($this->m_oObj);
     // Renders the fields used in the template
     foreach (MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef) {
         $aParams['this->label(' . $sAttCode . ')'] = $oAttDef->GetLabel();
         $aParams['this->comments(' . $sAttCode . ')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
         $iInputId = '2_' . $sAttCode;
         // TODO: generate a real/unique prefix...
         if (in_array($sAttCode, $aTemplateFields)) {
             if ($this->m_oObj->IsNew()) {
                 $iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
             } else {
                 $iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
             }
             if ($iFlags & OPT_ATT_MANDATORY && $this->m_oObj->IsNew()) {
                 $iFlags = $iFlags & ~OPT_ATT_READONLY;
                 // Mandatory fields cannot be read-only when creating an object
             }
             if (!$oAttDef->IsWritable() || $sStateAttCode == $sAttCode) {
                 $iFlags = $iFlags | OPT_ATT_READONLY;
             }
             if ($iFlags & OPT_ATT_HIDDEN) {
                 $aParams['this->label(' . $sAttCode . ')'] = '';
                 $aParams['this->field(' . $sAttCode . ')'] = '';
                 $aParams['this->comments(' . $sAttCode . ')'] = '';
                 $aParams['this->' . $sAttCode] = '';
             } else {
                 if ($bEditMode && $iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) {
                     // Check if the attribute is not read-only because of a synchro...
                     $aReasons = array();
                     $sSynchroIcon = '';
                     if ($iFlags & OPT_ATT_SLAVE) {
                         $iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
                         $sSynchroIcon = "&nbsp;<img id=\"synchro_{$sInputId}\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
                         $sTip = '';
                         foreach ($aReasons as $aRow) {
                             $sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
                         }
                         $oPage->add_ready_script("\$('#synchro_{$iInputId}').qtip( { content: '{$sTip}', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
                     }
                     // Attribute is read-only
                     $sHTMLValue = "<span id=\"field_{$iInputId}\">" . $this->m_oObj->GetAsHTML($sAttCode);
                     $sHTMLValue .= '<input type="hidden" id="' . $iInputId . '" name="attr_' . $sAttCode . '" value="' . htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8') . '"/></span>';
                     $aFieldsMap[$sAttCode] = $iInputId;
                     $aParams['this->comments(' . $sAttCode . ')'] = $sSynchroIcon;
                 }
                 if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) {
                     $aParams['this->field(' . $sAttCode . ')'] = "<span id=\"field_{$iInputId}\">" . $this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $this->m_oObj->Get($sAttCode), $this->m_oObj->GetEditValue($sAttCode), $iInputId, '', $iFlags, array('this' => $this->m_oObj)) . '</span>';
                     $aFieldsMap[$sAttCode] = $iInputId;
                 } else {
                     $aParams['this->field(' . $sAttCode . ')'] = $this->m_oObj->GetAsHTML($sAttCode);
                 }
                 $aParams['this->' . $sAttCode] = "<table class=\"field\"><tr><td class=\"label\">" . $aParams['this->label(' . $sAttCode . ')'] . ":</td><td>" . $aParams['this->field(' . $sAttCode . ')'] . "</td><td>" . $aParams['this->comments(' . $sAttCode . ')'] . "</td></tr></table>";
             }
         }
     }
     // Renders the PlugIns used in the template
     preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
     $aPlugInProperties = $aMatches[1];
     foreach ($aPlugInProperties as $sPlugInClass) {
         $oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
         if ($oInstance != null) {
             $offset = $oPage->start_capture();
             $oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
             $sContent = $oPage->end_capture($offset);
             $aParams["PlugIn:{$sPlugInClass}->properties()"] = $sContent;
         } else {
             $aParams["PlugIn:{$sPlugInClass}->properties()"] = "Missing PlugIn: {$sPlugInClass}";
         }
     }
     $offset = $oPage->start_capture();
     parent::Render($oPage, $aParams);
     $sContent = $oPage->end_capture($offset);
     // Remove empty table rows in case some attributes are hidden...
     $sContent = preg_replace('/<tr[^>]*>\\s*(<td[^>]*>\\s*<\\/td>)+\\s*<\\/tr>/im', '', $sContent);
     $oPage->add($sContent);
     return $aFieldsMap;
 }
예제 #6
0
                 }
                 $oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
             }
         }
     }
     $oPage->add_script("oWizardHelper{$sFormPrefix}.m_oData=" . $oWizardHelper->ToJSON() . ";\noWizardHelper{$sFormPrefix}.UpdateFields();\n");
     break;
 case 'obj_creation_form':
     $oPage->SetContentType('text/html');
     $sJson = utils::ReadParam('json_obj', '', false, 'raw_data');
     $oWizardHelper = WizardHelper::FromJSON($sJson);
     $oObj = $oWizardHelper->GetTargetObject();
     $sClass = $oWizardHelper->GetTargetClass();
     $sTargetState = utils::ReadParam('target_state', '');
     $iTransactionId = utils::ReadParam('transaction_id', '');
     $oObj->Set(MetaModel::GetStateAttributeCode($sClass), $sTargetState);
     cmdbAbstractObject::DisplayCreationForm($oPage, $sClass, $oObj, array(), array('action' => utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php', 'transaction_id' => $iTransactionId));
     break;
     // DisplayBlock
 // DisplayBlock
 case 'ajax':
     $oPage->SetContentType('text/html');
     if ($sFilter != "") {
         $sExtraParams = stripslashes(utils::ReadParam('extra_params', '', false, 'raw_data'));
         $aExtraParams = array();
         if (!empty($sExtraParams)) {
             $aExtraParams = json_decode(str_replace("'", '"', $sExtraParams), true);
         }
         // Restore the app context from the ExtraParams
         $oAppContext = new ApplicationContext(false);
         // false => don't read the context yet !
예제 #7
0
 /**
  * Renders the "Actions" popup menu for the given set of objects
  * 
  * Note that the menu links containing (or ending) with a hash (#) will have their fragment
  * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is
  * displayed, to correspond to the current hash/fragment in the page. This allows modifying
  * an object in with the same tab active by default as the tab that was active when selecting
  * the "Modify..." action.
  */
 public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
 {
     if ($this->m_sStyle == 'popup') {
         $this->m_sStyle = 'list';
     }
     $sHtml = '';
     $oAppContext = new ApplicationContext();
     $sContext = $oAppContext->GetForLink();
     if (!empty($sContext)) {
         $sContext = '&' . $sContext;
     }
     $sClass = $this->m_oFilter->GetClass();
     $oReflectionClass = new ReflectionClass($sClass);
     $oSet = new CMDBObjectSet($this->m_oFilter);
     $sFilter = $this->m_oFilter->serialize();
     $sFilterDesc = $this->m_oFilter->ToOql(true);
     $aActions = array();
     $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
     $sRootUrl = utils::GetAbsoluteUrlAppRoot();
     // 1:n links, populate the target object as a default value when creating a new linked object
     if (isset($aExtraParams['target_attr'])) {
         $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id'];
     }
     $sDefault = '';
     if (!empty($aExtraParams['default'])) {
         foreach ($aExtraParams['default'] as $sKey => $sValue) {
             $sDefault .= "&default[{$sKey}]={$sValue}";
         }
     }
     $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
     switch ($oSet->Count()) {
         case 0:
             // No object in the set, the only possible action is "new"
             if ($bIsCreationAllowed) {
                 $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
             }
             break;
         case 1:
             $oObj = $oSet->Fetch();
             $id = $oObj->GetKey();
             $bLocked = false;
             if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) {
                 $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id);
                 if ($aLockInfo['locked']) {
                     $bLocked = true;
                     //$this->AddMenuSeparator($aActions);
                     //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}");
                 }
             }
             $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed;
             $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
             // Just one object in the set, possible actions are "new / clone / modify and delete"
             if (!isset($aExtraParams['link_attr'])) {
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#");
                 }
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsDeleteAllowed) {
                     $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}");
                 }
                 // Transitions / Stimuli
                 if (!$bLocked) {
                     $aTransitions = $oObj->EnumTransitions();
                     if (count($aTransitions)) {
                         $this->AddMenuSeparator($aActions);
                         $aStimuli = Metamodel::EnumStimuli(get_class($oObj));
                         foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                             $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
                             switch ($iActionAllowed) {
                                 case UR_ALLOWED_YES:
                                     $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}");
                                     break;
                                 default:
                                     // Do nothing
                             }
                         }
                     }
                 }
                 // Relations...
                 $aRelations = MetaModel::EnumRelationsEx($sClass);
                 if (count($aRelations)) {
                     $this->AddMenuSeparator($aActions);
                     foreach ($aRelations as $sRelationCode => $aRelationInfo) {
                         if (array_key_exists('down', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}");
                         }
                         if (array_key_exists('up', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}");
                         }
                     }
                 }
                 if ($bLocked && $bRawModifiedAllowed) {
                     // Add a special menu to kill the lock, but only to allowed users who can also modify this object
                     $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
                     $bCanKill = false;
                     $oUser = UserRights::GetUserObject();
                     $aUserProfiles = array();
                     if (!is_null($oUser)) {
                         $oProfileSet = $oUser->Get('profile_list');
                         while ($oProfile = $oProfileSet->Fetch()) {
                             $aUserProfiles[$oProfile->Get('profile')] = true;
                         }
                     }
                     foreach ($aAllowedProfiles as $sProfile) {
                         if (array_key_exists($sProfile, $aUserProfiles)) {
                             $bCanKill = true;
                             break;
                         }
                     }
                     if ($bCanKill) {
                         $this->AddMenuSeparator($aActions);
                         $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}");
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 // Static menus: Email this page & CSV Export
                 $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object 
                 if ($this->m_sStyle == 'list')
                 {
                 	// Actions specific to the list
                 	$sOQL = addslashes($sFilterDesc);
                 	$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 }
                 */
             }
             $this->AddMenuSeparator($aActions);
             foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
                 $oSet->Rewind();
                 foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) {
                     $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl);
                 }
             }
             break;
         default:
             // Check rights
             // New / Modify
             $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet);
             if (isset($aExtraParams['link_attr'])) {
                 $id = $aExtraParams['object_id'];
                 $sTargetAttr = $aExtraParams['target_attr'];
                 $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
                 $sTargetClass = $oAttDef->GetTargetClass();
                 $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}");
                 }
                 //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
             } else {
                 // many objects in the set, possible actions are: new / modify all / delete all
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 if ($bIsBulkDeleteAllowed) {
                     $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 // Stimuli
                 $aStates = MetaModel::EnumStates($sClass);
                 // Do not perform time consuming computations if there are too may objects in the list
                 $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
                 if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) {
                     // Life cycle actions may be available... if all objects are in the same state
                     //
                     // Group by <state>
                     $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
                     $aGroupBy = array('__state__' => $oGroupByExp);
                     $aQueryParams = array();
                     if (isset($aExtraParams['query_params'])) {
                         $aQueryParams = $aExtraParams['query_params'];
                     }
                     $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy);
                     $aRes = CMDBSource::QueryToArray($sSql);
                     if (count($aRes) == 1) {
                         // All objects are in the same state...
                         $sState = $aRes[0]['__state__'];
                         $aTransitions = Metamodel::EnumTransitions($sClass, $sState);
                         if (count($aTransitions)) {
                             $this->AddMenuSeparator($aActions);
                             $aStimuli = Metamodel::EnumStimuli($sClass);
                             foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                                 $oSet->Rewind();
                                 // As soon as the user rights implementation will browse the object set,
                                 // then we might consider using OptimizeColumnLoad() here
                                 $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet);
                                 $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO;
                                 switch ($iActionAllowed) {
                                     case UR_ALLOWED_YES:
                                     case UR_ALLOWED_DEPENDS:
                                         $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                                         break;
                                     default:
                                         // Do nothing
                                 }
                             }
                         }
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 $sUrl = utils::GetAbsoluteUrlAppRoot();
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 $sOQL = addslashes($sFilterDesc);
                 $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 */
             }
     }
     $this->AddMenuSeparator($aActions);
     foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
         $oSet->Rewind();
         foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) {
             if (is_array($data)) {
                 // New plugins can provide javascript handlers via the 'onclick' property
                 //TODO: enable extension of different menus by checking the 'target' property ??
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
             } else {
                 // Backward compatibility with old plugins
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data);
             }
         }
     }
     // New extensions based on iPopupMenuItem interface
     switch ($this->m_sStyle) {
         case 'list':
             $oSet->Rewind();
             $param = $oSet;
             $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
             break;
         case 'details':
             $oSet->Rewind();
             $param = $oSet->Fetch();
             $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
             break;
     }
     utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
     $aFavoriteActions = array();
     $aCallSpec = array($sClass, 'GetShortcutActions');
     if (is_callable($aCallSpec)) {
         $aShortcutActions = call_user_func($aCallSpec, $sClass);
         foreach ($aActions as $key => $aAction) {
             if (in_array($key, $aShortcutActions)) {
                 $aFavoriteActions[] = $aAction;
                 unset($aActions[$key]);
             }
         }
     } else {
         $aShortcutActions = array();
     }
     if (count($aFavoriteActions) > 0) {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n";
     } else {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n";
     }
     $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
     static $bPopupScript = false;
     if (!$bPopupScript) {
         // Output this once per page...
         $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n");
         $bPopupScript = true;
     }
     return $sHtml;
 }
예제 #8
0
 /**
  * Compute the order of the fields & pages in the wizard
  * @param $oPage iTopWebPage The current page (used to display error messages) 
  * @param $sClass string Name of the class
  * @param $sStateCode string Code of the target state of the object
  * @return hash Two dimensional array: each element represents the list of fields for a given page   
  */
 protected function ComputeWizardStructure()
 {
     $aWizardSteps = array('mandatory' => array(), 'optional' => array());
     $aFieldsDone = array();
     // Store all the fields that are already covered by a previous step of the wizard
     $aStates = MetaModel::EnumStates($this->m_sClass);
     $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
     $aMandatoryAttributes = array();
     // Some attributes are always mandatory independently of the state machine (if any)
     foreach (MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) {
         $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
         if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() && $oAttDef->IsWritable() && $sAttCode != $sStateAttCode) {
             $aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
         }
     }
     // Now check the attributes that are mandatory in the specified state
     if (!empty($this->m_sTargetState) && count($aStates[$this->m_sTargetState]['attribute_list']) > 0) {
         // Check all the fields that *must* be included in the wizard for this
         // particular target state
         $aFields = array();
         foreach ($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) {
             if (isset($aMandatoryAttributes[$sAttCode]) && $aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) {
                 $aMandatoryAttributes[$sAttCode] |= $iOptions;
             } else {
                 $aMandatoryAttributes[$sAttCode] = $iOptions;
             }
         }
     }
     // Check all the fields that *must* be included in the wizard
     // i.e. all mandatory, must-change or must-prompt fields that are
     // not also read-only or hidden.
     // Some fields may be required (null not allowed) from the database
     // perspective, but hidden or read-only from the user interface perspective
     $aFields = array();
     foreach ($aMandatoryAttributes as $sAttCode => $iOptions) {
         if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT) && !($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN))) {
             $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
             $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
             $aFields[$sAttCode] = array();
             foreach ($aPrerequisites as $sCode) {
                 $aFields[$sAttCode][$sCode] = '';
             }
         }
     }
     // Now use the dependencies between the fields to order them
     // Start from the order of the 'details'
     $aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
     $index = 0;
     $aOrder = array();
     foreach ($aFields as $sAttCode => $void) {
         $aOrder[$sAttCode] = 999;
         // At the end of the list...
     }
     foreach ($aList as $sAttCode) {
         if (array_key_exists($sAttCode, $aFields)) {
             $aOrder[$sAttCode] = $index;
         }
         $index++;
     }
     foreach ($aFields as $sAttCode => $aDependencies) {
         // All fields with no remaining dependencies can be entered at this
         // step of the wizard
         if (count($aDependencies) > 0) {
             $iMaxPos = 0;
             // Remove this field from the dependencies of the other fields
             foreach ($aDependencies as $sDependentAttCode => $void) {
                 // position the current field after the ones it depends on
                 $iMaxPos = max($iMaxPos, 1 + $aOrder[$sDependentAttCode]);
             }
         }
     }
     asort($aOrder);
     $aCurrentStep = array();
     foreach ($aOrder as $sAttCode => $rank) {
         $aCurrentStep[] = $sAttCode;
         $aFieldsDone[$sAttCode] = '';
     }
     $aWizardSteps['mandatory'][] = $aCurrentStep;
     // Now computes the steps to fill the optional fields
     $aFields = array();
     // reset
     foreach (MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode => $oAttDef) {
         $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
         if ($sStateAttCode != $sAttCode && !$oAttDef->IsExternalField() && ($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0 && !isset($aFieldsDone[$sAttCode])) {
             // 'State', external fields, read-only and hidden fields
             // and fields that are already listed in the wizard
             // are removed from the 'optional' part of the wizard
             $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
             $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
             $aFields[$sAttCode] = array();
             foreach ($aPrerequisites as $sCode) {
                 if (!isset($aFieldsDone[$sCode])) {
                     // retain only the dependencies that were not covered
                     // in the 'mandatory' part of the wizard
                     $aFields[$sAttCode][$sCode] = '';
                 }
             }
         }
     }
     // Now use the dependencies between the fields to order them
     while (count($aFields) > 0) {
         $aCurrentStep = array();
         foreach ($aFields as $sAttCode => $aDependencies) {
             // All fields with no remaining dependencies can be entered at this
             // step of the wizard
             if (count($aDependencies) == 0) {
                 $aCurrentStep[] = $sAttCode;
                 $aFieldsDone[$sAttCode] = '';
                 unset($aFields[$sAttCode]);
                 // Remove this field from the dependencies of the other fields
                 foreach ($aFields as $sUpdatedCode => $aDummy) {
                     // remove the dependency
                     unset($aFields[$sUpdatedCode][$sAttCode]);
                 }
             }
         }
         if (count($aCurrentStep) == 0) {
             // This step of the wizard would contain NO field !
             $this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
             print_r($aFields);
             break;
         }
         $aWizardSteps['optional'][] = $aCurrentStep;
     }
     return $aWizardSteps;
 }
 function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
 {
     parent::DisplayBareRelations($oPage, $bEditMode);
     $sTicketListAttCode = 'tickets_list';
     if (MetaModel::IsValidAttCode(get_class($this), $sTicketListAttCode)) {
         // Display one list per leaf class (the only way to display the status as of now)
         $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sTicketListAttCode);
         $sLnkClass = $oAttDef->GetLinkedClass();
         $sExtKeyToMe = $oAttDef->GetExtKeyToMe();
         $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
         $iTotal = 0;
         $aSearches = array();
         foreach (MetaModel::EnumChildClasses('Ticket') as $sSubClass) {
             if (!MetaModel::HasChildrenClasses($sSubClass)) {
                 $sStateAttCode = MetaModel::GetStateAttributeCode($sSubClass);
                 if ($sStateAttCode != '') {
                     $oSearch = DBSearch::FromOQL("SELECT {$sSubClass} AS t JOIN {$sLnkClass} AS lnk ON lnk.{$sExtKeyToRemote} = t.id WHERE {$sExtKeyToMe} = :myself AND {$sStateAttCode} NOT IN ('rejected', 'resolved', 'closed')", array('myself' => $this->GetKey()));
                     $aSearches[$sSubClass] = $oSearch;
                     $oSet = new DBObjectSet($oSearch);
                     $iTotal += $oSet->Count();
                 }
             }
         }
         $sCount = $iTotal > 0 ? ' (' . $iTotal . ')' : '';
         $oPage->SetCurrentTab(Dict::S('Class:FunctionalCI/Tab:OpenedTickets') . $sCount);
         foreach ($aSearches as $sSubClass => $oSearch) {
             $sBlockId = __CLASS__ . '_opened_' . $sSubClass;
             $oPage->add('<fieldset>');
             $oPage->add('<legend>' . MetaModel::GetName($sSubClass) . '</legend>');
             $oBlock = new DisplayBlock($oSearch, 'list', false);
             $oBlock->Display($oPage, $sBlockId, array('menu' => false));
             $oPage->add('</fieldset>');
         }
     }
 }
예제 #10
0
 /**
  * Designed as an action to be called when a stop watch threshold times out
  * or from within the framework	
  */
 public function ApplyStimulus($sStimulusCode, $bDoNotWrite = false)
 {
     $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
     if (empty($sStateAttCode)) {
         return false;
     }
     MyHelpers::CheckKeyInArray('object lifecycle stimulus', $sStimulusCode, MetaModel::EnumStimuli(get_class($this)));
     $aStateTransitions = $this->EnumTransitions();
     if (!array_key_exists($sStimulusCode, $aStateTransitions)) {
         // This simulus has no effect in the current state... do nothing
         return;
     }
     $aTransitionDef = $aStateTransitions[$sStimulusCode];
     // Change the state before proceeding to the actions, this is necessary because an action might
     // trigger another stimuli (alternative: push the stimuli into a queue)
     $sPreviousState = $this->Get($sStateAttCode);
     $sNewState = $aTransitionDef['target_state'];
     $this->Set($sStateAttCode, $sNewState);
     // $aTransitionDef is an
     //    array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD
     $bSuccess = true;
     foreach ($aTransitionDef['actions'] as $sActionHandler) {
         // std PHP spec
         $aActionCallSpec = array($this, $sActionHandler);
         if (!is_callable($aActionCallSpec)) {
             throw new CoreException("Unable to call action: " . get_class($this) . "::{$sActionHandler}");
             return;
         }
         $bRet = call_user_func($aActionCallSpec, $sStimulusCode);
         // if one call fails, the whole is considered as failed
         if (!$bRet) {
             $bSuccess = false;
         }
     }
     if ($bSuccess) {
         $sClass = get_class($this);
         // Stop watches
         foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
             if ($oAttDef instanceof AttributeStopWatch) {
                 $oSW = $this->Get($sAttCode);
                 if (in_array($sNewState, $oAttDef->GetStates())) {
                     $oSW->Start($this, $oAttDef);
                 } else {
                     $oSW->Stop($this, $oAttDef);
                 }
                 $this->Set($sAttCode, $oSW);
             }
         }
         if (!$bDoNotWrite) {
             $this->DBWrite();
         }
         // Change state triggers...
         $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
         $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('{$sClassList}') AND t.state='{$sPreviousState}'"));
         while ($oTrigger = $oSet->Fetch()) {
             $oTrigger->DoActivate($this->ToArgs('this'));
         }
         $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN ('{$sClassList}') AND t.state='{$sNewState}'"));
         while ($oTrigger = $oSet->Fetch()) {
             $oTrigger->DoActivate($this->ToArgs('this'));
         }
     }
     return $bSuccess;
 }
예제 #11
0
 $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'];
 $aDetails = array();
 $iFieldIndex = 0;
 $aFieldsMap = array();
 $aValues = array();
 $aObjects = array();
 foreach ($aSelectObject as $iId) {
     $aObjects[] = MetaModel::GetObject($sClass, $iId);
 }
 $oSet = DBObjectSet::FromArray($sClass, $aObjects);
 $oObj = $oSet->ComputeCommonObject($aValues);
 $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
 $oObj->Set($sStateAttCode, $sTargetState);
 $sReadyScript = '';
 foreach ($aExpectedAttributes as $sAttCode => $iExpectCode) {
     // 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) == '') {
         $aAttributesDef = MetaModel::ListAttributeDefs($sClass);
         $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
         $aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
         // List of attributes that are needed for the current one
         if (count($aPrerequisites) > 0) {
             // When 'enabling' a field, all its prerequisites must be enabled too
             $sFieldList = "['" . implode("','", $aPrerequisites) . "']";
             $oP->add_ready_script("\$('#enable_{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, {$sFieldList}, true); } );\n");
예제 #12
0
/**
 * Helper for the lifecycle details of a given class
 */
function DisplayLifecycle($oPage, $sClass)
{
    $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
    if (empty($sStateAttCode)) {
        $oPage->p(Dict::S('UI:Schema:NoLifeCyle'));
    } else {
        $aStates = MetaModel::EnumStates($sClass);
        $aStimuli = MetaModel::EnumStimuli($sClass);
        $oPage->add("<img src=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/graphviz.php?class={$sClass}\">\n");
        $oPage->add("<h3>" . Dict::S('UI:Schema:LifeCycleTransitions') . "</h3>\n");
        $oPage->add("<ul>\n");
        foreach ($aStates as $sStateCode => $aStateDef) {
            $sStateLabel = MetaModel::GetStateLabel($sClass, $sStateCode);
            $sStateDescription = MetaModel::GetStateDescription($sClass, $sStateCode);
            $oPage->add("<li title=\"code: {$sStateCode}\">{$sStateLabel} <span style=\"color:grey;\">({$sStateCode}) {$sStateDescription}</span></li>\n");
            $oPage->add("<ul>\n");
            foreach (MetaModel::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) {
                $sStimulusLabel = $aStimuli[$sStimulusCode]->GetLabel();
                $sTargetStateLabel = MetaModel::GetStateLabel($sClass, $aTransitionDef['target_state']);
                if (count($aTransitionDef['actions']) > 0) {
                    $sActions = " <em>(" . implode(', ', $aTransitionDef['actions']) . ")</em>";
                } else {
                    $sActions = "";
                }
                $oPage->add("<li><span style=\"color:red;font-weight=bold;\">{$sStimulusLabel}</span> =&gt; {$sTargetStateLabel} {$sActions}</li>\n");
            }
            $oPage->add("</ul>\n");
        }
        $oPage->add("</ul>\n");
        $oPage->add("<h3>" . Dict::S('UI:Schema:LifeCyleAttributeOptions') . "</h3>\n");
        $oPage->add("<ul>\n");
        foreach ($aStates as $sStateCode => $aStateDef) {
            $sStateLabel = MetaModel::GetStateLabel($sClass, $sStateCode);
            $sStateDescription = MetaModel::GetStateDescription($sClass, $sStateCode);
            $oPage->add("<li title=\"code: {$sStateCode}\">{$sStateLabel} <span style=\"color:grey;\">({$sStateCode}) {$sStateDescription}</span></li>\n");
            if (count($aStates[$sStateCode]['attribute_list']) > 0) {
                $oPage->add("<ul>\n");
                foreach ($aStates[$sStateCode]['attribute_list'] as $sAttCode => $iOptions) {
                    $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
                    $sAttLabel = $oAttDef->GetLabel();
                    $aOptions = array();
                    if ($iOptions & OPT_ATT_HIDDEN) {
                        $aOptions[] = Dict::S('UI:Schema:LifeCycleHiddenAttribute');
                    }
                    if ($iOptions & OPT_ATT_READONLY) {
                        $aOptions[] = Dict::S('UI:Schema:LifeCycleReadOnlyAttribute');
                    }
                    if ($iOptions & OPT_ATT_MANDATORY) {
                        $aOptions[] = Dict::S('UI:Schema:LifeCycleMandatoryAttribute');
                    }
                    if ($iOptions & OPT_ATT_MUSTCHANGE) {
                        $aOptions[] = Dict::S('UI:Schema:LifeCycleAttributeMustChange');
                    }
                    if ($iOptions & OPT_ATT_MUSTPROMPT) {
                        $aOptions[] = Dict::S('UI:Schema:LifeCycleAttributeMustPrompt');
                    }
                    if (count($aOptions)) {
                        $sOptions = implode(', ', $aOptions);
                    } else {
                        $sOptions = "";
                    }
                    $oPage->add("<li><span style=\"color:purple;font-weight=bold;\">{$sAttLabel}</span> {$sOptions}</li>\n");
                }
                $oPage->add("</ul>\n");
            } else {
                $oPage->p("<em>" . Dict::S('UI:Schema:LifeCycleEmptyList') . "</em>");
            }
        }
        $oPage->add("</ul>\n");
    }
}
예제 #13
0
function MakeDictionaryTemplate($sModules = '', $sLanguage = 'EN US')
{
    $sRes = '';
    Dict::SetDefaultLanguage($sLanguage);
    $aAvailableLanguages = Dict::GetLanguages();
    $sDesc = $aAvailableLanguages[$sLanguage]['description'];
    $sLocalizedDesc = $aAvailableLanguages[$sLanguage]['localized_description'];
    $sRes .= "// Dictionary conventions\n";
    $sRes .= htmlentities("// Class:<class_name>\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>+\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>+\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>\n", ENT_QUOTES, 'UTF-8');
    $sRes .= htmlentities("// Class:<class_name>/Stimulus:<stimulus_code>+\n", ENT_QUOTES, 'UTF-8');
    $sRes .= "\n";
    // Note: I did not use EnumCategories(), because a given class maybe found in several categories
    // Need to invent the "module", to characterize the origins of a class
    if (strlen($sModules) == 0) {
        $aModules = array('bizmodel', 'core/cmdb', 'gui', 'application', 'addon/userrights', 'monitoring');
    } else {
        $aModules = explode(', ', $sModules);
    }
    $sRes .= "//////////////////////////////////////////////////////////////////////\n";
    $sRes .= "// Note: The classes have been grouped by categories: " . implode(', ', $aModules) . "\n";
    $sRes .= "//////////////////////////////////////////////////////////////////////\n";
    foreach ($aModules as $sCategory) {
        $sRes .= "//////////////////////////////////////////////////////////////////////\n";
        $sRes .= "// Classes in '{$sCategory}'\n";
        $sRes .= "//////////////////////////////////////////////////////////////////////\n";
        $sRes .= "//\n";
        $sRes .= "\n";
        foreach (MetaModel::GetClasses($sCategory) as $sClass) {
            if (!MetaModel::HasTable($sClass)) {
                continue;
            }
            $bNotInDico = false;
            $bNotImportant = true;
            $sClassRes = "//\n";
            $sClassRes .= "// Class: {$sClass}\n";
            $sClassRes .= "//\n";
            $sClassRes .= "\n";
            $sClassRes .= "Dict::Add('{$sLanguage}', '{$sDesc}', '{$sLocalizedDesc}', array(\n";
            $sClassRes .= MakeDictEntry("Class:{$sClass}", MetaModel::GetName_Obsolete($sClass), $sClass, $bNotInDico);
            $sClassRes .= MakeDictEntry("Class:{$sClass}+", MetaModel::GetClassDescription_Obsolete($sClass), '', $bNotImportant);
            foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
                if ($sAttCode == 'friendlyname') {
                    continue;
                }
                // Skip this attribute if not originaly defined in this class
                if (MetaModel::GetAttributeOrigin($sClass, $sAttCode) != $sClass) {
                    continue;
                }
                $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}", $oAttDef->GetLabel_Obsolete(), $sAttCode, $bNotInDico);
                $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}+", $oAttDef->GetDescription_Obsolete(), '', $bNotImportant);
                if ($oAttDef instanceof AttributeEnum) {
                    if (MetaModel::GetStateAttributeCode($sClass) == $sAttCode) {
                        foreach (MetaModel::EnumStates($sClass) as $sStateCode => $aStateData) {
                            if (array_key_exists('label', $aStateData)) {
                                $sValue = $aStateData['label'];
                            } else {
                                $sValue = MetaModel::GetStateLabel($sClass, $sStateCode);
                            }
                            if (array_key_exists('description', $aStateData)) {
                                $sValuePlus = $aStateData['description'];
                            } else {
                                $sValuePlus = MetaModel::GetStateDescription($sClass, $sStateCode);
                            }
                            $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sStateCode}", $sValue, '', $bNotInDico);
                            $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sStateCode}+", $sValuePlus, '', $bNotImportant);
                        }
                    } else {
                        foreach ($oAttDef->GetAllowedValues() as $sKey => $value) {
                            $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sKey}", $value, '', $bNotInDico);
                            $sClassRes .= MakeDictEntry("Class:{$sClass}/Attribute:{$sAttCode}/Value:{$sKey}+", $value, '', $bNotImportant);
                        }
                    }
                }
            }
            foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) {
                $sClassRes .= MakeDictEntry("Class:{$sClass}/Stimulus:{$sStimulusCode}", $oStimulus->GetLabel_Obsolete(), '', $bNotInDico);
                $sClassRes .= MakeDictEntry("Class:{$sClass}/Stimulus:{$sStimulusCode}+", $oStimulus->GetDescription_Obsolete(), '', $bNotImportant);
            }
            $sClassRes .= "));\n";
            $sClassRes .= "\n";
            $sRes .= $sClassRes;
        }
    }
    return $sRes;
}
예제 #14
0
 function test_object_lifecycle()
 {
     echo "<h4>Test object lifecycle</h4>";
     self::DumpVariable(MetaModel::GetStateAttributeCode("cmdbContact"));
     self::DumpVariable(MetaModel::EnumStates("cmdbContact"));
     self::DumpVariable(MetaModel::EnumStimuli("cmdbContact"));
     foreach (MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef) {
         echo "<p>Transition from <strong>{$sStateCode}</strong></p>\n";
         self::DumpVariable(MetaModel::EnumTransitions("cmdbContact", $sStateCode));
     }
     $oObj = MetaModel::GetObject("cmdbContact", 18);
     echo "Current state: " . $oObj->GetState() . "... let's go to school...";
     self::DumpVariable($oObj->EnumTransitions());
     $oObj->ApplyStimulus("toschool");
     echo "New state: " . $oObj->GetState() . "... let's get older...";
     self::DumpVariable($oObj->EnumTransitions());
     $oObj->ApplyStimulus("raise");
     echo "New state: " . $oObj->GetState() . "... let's try to go further... (should give an error)";
     self::DumpVariable($oObj->EnumTransitions());
     $oObj->ApplyStimulus("raise");
     // should give an error
 }