diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index e8a2acacc..a8eab12ae 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1426,7 +1426,7 @@ EOF } $sHeader = '
 '.Dict::S('UI:CaseLogTypeYourTextHere').'
'; $sEditValue = $oAttDef->GetEditValue($value); - $sPreviousLog = $value->GetAsHTML(); + $sPreviousLog = is_object($value) ? $value->GetAsHTML() : ''; $sHTMLValue = "
$sHeader$sPreviousLog{$sValidationField}
"; break; @@ -1453,9 +1453,9 @@ EOF } $iMaxFileSize = utils::ConvertToBytes(ini_get('upload_max_filesize')); $sHTMLValue = "\n"; - $sHTMLValue .= "\n"; + $sHTMLValue .= "\n"; $sHTMLValue .= "$sFileName
\n"; - $sHTMLValue .= " {$sValidationField}\n"; + $sHTMLValue .= " {$sValidationField}\n"; break; case 'List': @@ -1806,6 +1806,7 @@ EOF ); $oPage->add_ready_script( <<m_iFormId}', false); @@ -2152,11 +2153,12 @@ EOF } /** - * Updates the object from the POSTed parameters + * Updates the object from a flat array of values + * @param array $aAttList array of attcode + * @return array of attcodes that can be used for writing on the current object */ - public function UpdateObject($sFormPrefix = '', $aAttList = null) + public function GetWriteableAttList($aAttList, &$aErrors) { - $aErrors = array(); if (!is_array($aAttList)) { $aAttList = $this->FlattenZList(MetaModel::GetZListItems(get_class($this), 'details')); @@ -2175,6 +2177,8 @@ EOF } } } + + $aWriteableAttList = array(); foreach($aAttList as $sAttCode) { $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); @@ -2188,105 +2192,142 @@ EOF } elseif($iFlags & OPT_ATT_SLAVE) { - $value = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); - if (!is_null($value) && ($value != $this->Get($sAttCode))) - { - $aErrors[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel()); - } - } - elseif ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) - { - $aLinks = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); - $sLinkedClass = $oAttDef->GetLinkedClass(); - $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); - $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); - $oLinkedSet = DBObjectSet::FromScratch($sLinkedClass); - if (is_array($aLinks)) - { - foreach($aLinks as $id => $aData) - { - if (is_numeric($id)) - { - if ($id < 0) - { - // New link to be created, the opposite of the id (-$id) is the ID of the remote object - $oLink = MetaModel::NewObject($sLinkedClass); - $oLink->Set($sExtKeyToRemote, -$id); - $oLink->Set($sExtKeyToMe, $this->GetKey()); - } - else - { - // Existing link, potentially to be updated... - $oLink = MetaModel::GetObject($sLinkedClass, $id); - } - // Now populate the attributes - foreach($aData as $sName => $value) - { - if (MetaModel::IsValidAttCode($sLinkedClass, $sName)) - { - $oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName); - if ($oLinkAttDef->IsWritable()) - { - $oLink->Set($sName, $value); - } - } - } - $oLinkedSet->AddObject($oLink); - } - } - } - $this->Set($sAttCode, $oLinkedSet); - } - elseif ($oAttDef->GetEditClass() == 'Document') - { - // There should be an uploaded file with the named attr_ - $oDocument = utils::ReadPostedDocument("file_{$sFormPrefix}{$sAttCode}"); - if (!$oDocument->IsEmpty()) - { - // A new file has been uploaded - $this->Set($sAttCode, $oDocument); - } - } - elseif ($oAttDef->GetEditClass() == 'One Way Password') - { - // Check if the password was typed/changed - $bChanged = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_changed", false); - if ($bChanged) - { - // The password has been changed or set - $rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); - $this->Set($sAttCode, $rawValue); - } - } - elseif ($oAttDef->GetEditClass() == 'Duration') - { - $rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); - if (!is_array($rawValue)) continue; - - $iValue = (((24*$rawValue['d'])+$rawValue['h'])*60 +$rawValue['m'])*60 + $rawValue['s']; - $this->Set($sAttCode, $iValue); - $previousValue = $this->Get($sAttCode); - if ($previousValue !== $iValue) - { - $this->Set($sAttCode, $iValue); - } + $aErrors[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel()); } else { - $rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); - if (!is_null($rawValue)) + $aWriteableAttList[$sAttCode] = $oAttDef; + } + } + } + return $aWriteableAttList; + } + + /** + * Updates the object from a flat array of values + * @param string $aValues array of attcode => scalar or array (N-N links) + * @return void + */ + public function UpdateObjectFromArray($aValues) + { + foreach($aValues as $sAttCode => $value) + { + $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect()) + { + $aLinks = $value; + $sLinkedClass = $oAttDef->GetLinkedClass(); + $sExtKeyToRemote = $oAttDef->GetExtKeyToRemote(); + $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); + $oLinkedSet = DBObjectSet::FromScratch($sLinkedClass); + if (is_array($aLinks)) + { + foreach($aLinks as $id => $aData) { - $aAttributes[$sAttCode] = trim($rawValue); - $previousValue = $this->Get($sAttCode); - if ($previousValue !== $aAttributes[$sAttCode]) + if (is_numeric($id)) { - $this->Set($sAttCode, $aAttributes[$sAttCode]); + if ($id < 0) + { + // New link to be created, the opposite of the id (-$id) is the ID of the remote object + $oLink = MetaModel::NewObject($sLinkedClass); + $oLink->Set($sExtKeyToRemote, -$id); + $oLink->Set($sExtKeyToMe, $this->GetKey()); + } + else + { + // Existing link, potentially to be updated... + $oLink = MetaModel::GetObject($sLinkedClass, $id); + } + // Now populate the attributes + foreach($aData as $sName => $value) + { + if (MetaModel::IsValidAttCode($sLinkedClass, $sName)) + { + $oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName); + if ($oLinkAttDef->IsWritable()) + { + $oLink->Set($sName, $value); + } + } + } + $oLinkedSet->AddObject($oLink); } } } + $this->Set($sAttCode, $oLinkedSet); + } + elseif ($oAttDef->GetEditClass() == 'Document') + { + // There should be an uploaded file with the named attr_ + $oDocument = $value['fcontents']; + if (!$oDocument->IsEmpty()) + { + // A new file has been uploaded + $this->Set($sAttCode, $oDocument); + } + } + elseif ($oAttDef->GetEditClass() == 'One Way Password') + { + // Check if the password was typed/changed + $aPwdData = $value; + if (!is_null($aPwdData) && $aPwdData['changed']) + { + // The password has been changed or set + $this->Set($sAttCode, $aPwdData['value']); + } + } + elseif ($oAttDef->GetEditClass() == 'Duration') + { + $aDurationData = $value; + if (!is_array($aDurationData)) continue; + + $iValue = (((24*$aDurationData['d'])+$aDurationData['h'])*60 +$aDurationData['m'])*60 + $aDurationData['s']; + $this->Set($sAttCode, $iValue); + $previousValue = $this->Get($sAttCode); + if ($previousValue !== $iValue) + { + $this->Set($sAttCode, $iValue); + } + } + else + { + if (!is_null($value)) + { + $aAttributes[$sAttCode] = trim($value); + $previousValue = $this->Get($sAttCode); + if ($previousValue !== $aAttributes[$sAttCode]) + { + $this->Set($sAttCode, $aAttributes[$sAttCode]); + } + } } } - + } + + /** + * Updates the object from the POSTed parameters (form) + */ + public function UpdateObject($sFormPrefix = '', $aAttList = null) + { + $aErrors = array(); + $aValues = array(); + foreach($this->GetWriteableAttList($aAttList, $aErrors) as $sAttCode => $oAttDef) + { + if ($oAttDef->GetEditClass() == 'Document') + { + $value = array('fcontents' => utils::ReadPostedDocument("attr_{$sFormPrefix}{$sAttCode}", 'fcontents')); + } + else + { + $value = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null); + } + if (!is_null($value)) + { + $aValues[$sAttCode] = $value; + } + } + $this->UpdateObjectFromArray($aValues); + // Invoke extensions after the update of the object from the form foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) { @@ -2296,6 +2337,27 @@ EOF return $aErrors; } + /** + * Updates the object from a given page argument + */ + public function UpdateObjectFromArg($sArgName, $aAttList = null) + { + $aErrors = array(); + + $aRawValues = utils::ReadParam($sArgName, array()); + + $aValues = array(); + foreach($this->GetWriteableAttList($aAttList, $aErrors) as $sAttCode => $oAttDef) + { + if (isset($aRawValues[$sAttCode])) + { + $aValues[$sAttCode] = $aRawValues[$sAttCode]; + } + } + $this->UpdateObjectFromArray($aValues); + return $aErrors; + } + protected function DBInsertTracked_Internal($bDoNotReload = false) { $res = parent::DBInsertTracked_Internal($bDoNotReload); diff --git a/application/portalwebpage.class.inc.php b/application/portalwebpage.class.inc.php index 1b19d6bdb..cf8867307 100644 --- a/application/portalwebpage.class.inc.php +++ b/application/portalwebpage.class.inc.php @@ -167,6 +167,12 @@ EOF window.location.href = '?operation='; return false; } + + function SetWizardNextStep(sStep) + { + var next_step = $('input[id=next_step]'); + next_step.val(sStep); + } EOF ); @@ -668,17 +674,17 @@ EOF } $sStepHistory = implode(',', $aPreviousSteps); - $this->add(""); + $this->add(""); if (!is_null($sNextStep)) { - $this->add(""); + $this->add(""); } - $this->add(""); + $this->add(""); $sTransactionId = utils::GetNewTransactionId(); $this->SetTransactionId($sTransactionId); - $this->add("\n"); + $this->add("\n"); $oPage->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n"); } diff --git a/application/ui.extkeywidget.class.inc.php b/application/ui.extkeywidget.class.inc.php index b05dded8b..3a80bb36f 100644 --- a/application/ui.extkeywidget.class.inc.php +++ b/application/ui.extkeywidget.class.inc.php @@ -187,7 +187,7 @@ EOF <<iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper); oACWidget_{$this->iId}.emptyHtml = "

$sMessage

"; - $('#label_$this->iId').autocomplete('../pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter', json: $sWizHelperJSON }}); + $('#label_$this->iId').autocomplete('../pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter', json: function() { return $sWizHelperJSON; } }}); $('#label_$this->iId').blur(function() { $(this).search(); } ); $('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly ! $('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } ); diff --git a/application/ui.linkswidget.class.inc.php b/application/ui.linkswidget.class.inc.php index 1e6ffc54d..82ac06fa9 100644 --- a/application/ui.linkswidget.class.inc.php +++ b/application/ui.linkswidget.class.inc.php @@ -219,10 +219,18 @@ class UILinksWidget while($oCurrentLink = $oValue->Fetch()) { $aRow = array(); - $key = $oCurrentLink->GetKey(); $oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote)); + if ($oCurrentLink->IsNew()) + { + $key = -$oLinkedObj->GetKey(); + $aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs); + } + else + { + $key = $oCurrentLink->GetKey(); + $aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs); + } - $aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs); } $sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm); $sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false'; diff --git a/application/ui.passwordwidget.class.inc.php b/application/ui.passwordwidget.class.inc.php index fc33208cf..40296f584 100644 --- a/application/ui.passwordwidget.class.inc.php +++ b/application/ui.passwordwidget.class.inc.php @@ -52,13 +52,13 @@ class UIPasswordWidget { $sCode = $this->sAttCode.$this->sNameSuffix; $iWidgetIndex = self::$iWidgetIndex; - $sPasswordValue = utils::ReadPostedParam("attr_$sCode", '*****'); - $sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}_confirmed", '*****'); + $sPasswordValue = utils::ReadPostedParam("attr_{$sCode}[value]", '*****'); + $sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}[confirm]", '*****'); $sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0; $sHtmlValue = ''; - $sHtmlValue = ' 
'; - $sHtmlValue .= ' '.Dict::S('UI:PasswordConfirm').' '; - $sHtmlValue .= ''; + $sHtmlValue = ' 
'; + $sHtmlValue .= ' '.Dict::S('UI:PasswordConfirm').' '; + $sHtmlValue .= ''; $oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate $oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate diff --git a/application/utils.inc.php b/application/utils.inc.php index cc71efc66..caca89342 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -151,18 +151,25 @@ class utils /** * Reads an uploaded file and turns it into an ormDocument object - Triggers an exception in case of error * @param string $sName Name of the input used from uploading the file + * @param string $sIndex If Name is an array of posted files, then the index must be used to point out the file * @return ormDocument The uploaded file (can be 'empty' if nothing was uploaded) */ - public static function ReadPostedDocument($sName) + public static function ReadPostedDocument($sName, $sIndex = null) { $oDocument = new ormDocument(); // an empty document if(isset($_FILES[$sName])) { - switch($_FILES[$sName]['error']) + $aFileInfo = $_FILES[$sName]; + + $sError = is_null($sIndex) ? $aFileInfo['error'] : $aFileInfo['error'][$sIndex]; + switch($sError) { case UPLOAD_ERR_OK: - $doc_content = file_get_contents($_FILES[$sName]['tmp_name']); - $sMimeType = $_FILES[$sName]['type']; + $sTmpName = is_null($sIndex) ? $aFileInfo['tmp_name'] : $aFileInfo['tmp_name'][$sIndex]; + $sMimeType = is_null($sIndex) ? $aFileInfo['type'] : $aFileInfo['type'][$sIndex]; + $sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex]; + + $doc_content = file_get_contents($sTmpName); if (function_exists('finfo_file')) { // as of PHP 5.3 the fileinfo extension is bundled within PHP @@ -180,7 +187,7 @@ class utils } @finfo_close($rInfo); } - $oDocument = new ormDocument($doc_content, $sMimeType, $_FILES[$sName]['name']); + $oDocument = new ormDocument($doc_content, $sMimeType, $sName); break; case UPLOAD_ERR_NO_FILE: @@ -205,11 +212,12 @@ class utils break; case UPLOAD_ERR_EXTENSION: - throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $_FILES[$sName]['name'])); + $sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex]; + throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName)); break; default: - throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $_FILES[$sName]['error'])); + throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError)); break; } diff --git a/application/wizardhelper.class.inc.php b/application/wizardhelper.class.inc.php index 08f9e8f99..ef121b698 100644 --- a/application/wizardhelper.class.inc.php +++ b/application/wizardhelper.class.inc.php @@ -98,7 +98,7 @@ class WizardHelper { if ($bReadUploadedFiles) { - $oDocument = utils::ReadPostedDocument('file_'.$sAttCode); + $oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents'); $oObj->Set($sAttCode, $oDocument); } else diff --git a/js/forms-json-utils.js b/js/forms-json-utils.js index 07330229f..fdd28f940 100644 --- a/js/forms-json-utils.js +++ b/js/forms-json-utils.js @@ -153,7 +153,7 @@ function CheckFields(sFormId, bDisplayAlert) // The two 'fields' below will be updated when the 'validate' event is processed oFormErrors['err_'+sFormId] = 0; // Number of errors encountered when validating the form oFormErrors['input_'+sFormId] = null; // First 'input' with an error, to set the focus to it - $('#'+sFormId+' :input[type!=hidden]').each( function() + $('#'+sFormId+' :input').each( function() { validateEventResult = $(this).trigger('validate', sFormId); } diff --git a/pages/UI.php b/pages/UI.php index 30fd3f4d4..274bc7dca 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -1013,7 +1013,6 @@ EOF { $aArgs[$key] = $oAppContext->GetCurrentValue($key); } - // If the specified class has subclasses, ask the user an instance of which class to create $aSubClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself $aPossibleClasses = array(); @@ -1047,26 +1046,32 @@ EOF $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel)); $oP->add("

".MetaModel::GetClassIcon($sRealClass)." ".Dict::Format('UI:CreationTitle_Class', $sClassLabel)."

\n"); $oP->add("
\n"); - $aDefaults = utils::ReadParam('default', array()); - $aContext = $oAppContext->GetAsHash(); - foreach( $oAppContext->GetNames() as $key) - { - $aDefaults[$key] = $oAppContext->GetCurrentValue($key); - } + // Set all the default values in an object and clone this "default" object $oObjToClone = MetaModel::NewObject($sRealClass); - foreach($aDefaults as $sName => $value) + + // 1st - set context values + $aContext = $oAppContext->GetAsHash(); + foreach($oAppContext->GetNames() as $key) { - if (MetaModel::IsValidAttCode($sRealClass, $sName)) + if (MetaModel::IsValidAttCode($sRealClass, $key)) { - $oAttDef = MetaModel::GetAttributeDef($sRealClass, $sName); + $oAttDef = MetaModel::GetAttributeDef($sRealClass, $key); if ($oAttDef->IsWritable()) { - $oObjToClone->Set($sName, $value); + $value = $oAppContext->GetCurrentValue($key, null); + if (!is_null($value)) + { + $oObjToClone->Set($key, $value); + } } } } - cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array('default' => $aDefaults)); + + // 2nd - set values from the page argument 'default' + $oObjToClone->UpdateObjectFromArg('default'); + + cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array('XXXXXXdefault' => $aDefaults=null)); $oP->add("
\n"); } else