From 5386662146bb2ca0cfd5550ce16a561d7bde8b7a Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Tue, 3 May 2016 09:56:02 +0000 Subject: [PATCH] Support of date and time custom formats... continuing towards the beta ! SVN:trunk[4019] --- application/cmdbabstract.class.inc.php | 16 +- application/displayblock.class.inc.php | 19 +- application/itopwebpage.class.inc.php | 15 +- core/attributedef.class.inc.php | 391 +++++------------- core/bulkchange.class.inc.php | 44 +- core/csvbulkexport.class.inc.php | 51 ++- core/datetimeformat.class.inc.php | 51 ++- core/dbobjectsearch.class.php | 10 +- core/excelbulkexport.class.inc.php | 37 +- core/ormcaselog.class.inc.php | 12 +- core/pdfbulkexport.class.inc.php | 40 +- core/spreadsheetbulkexport.class.inc.php | 73 +++- dictionaries/cs.dictionary.itop.core.php | 8 +- dictionaries/da.dictionary.itop.core.php | 8 +- dictionaries/de.dictionary.itop.core.php | 8 +- dictionaries/dictionary.itop.core.php | 8 +- dictionaries/es_cr.dictionary.itop.core.php | 8 +- dictionaries/fr.dictionary.itop.core.php | 8 +- dictionaries/hu.dictionary.itop.core.php | 8 +- dictionaries/it.dictionary.itop.core.php | 8 +- dictionaries/ja.dictionary.itop.core.php | 8 +- dictionaries/nl.dictionary.itop.core.php | 8 +- dictionaries/pt_br.dictionary.itop.core.php | 8 +- dictionaries/ru.dictionary.itop.core.php | 8 +- dictionaries/tr.dictionary.itop.core.php | 8 +- dictionaries/zh.dictionary.itop.core.php | 8 +- pages/csvimport.php | 15 +- sources/autoload.php | 1 - .../form/field/datetimefield.class.inc.php | 48 ++- .../bootstrap/bsformrenderer.class.inc.php | 1 + .../bssimplefieldrenderer.class.inc.php | 35 ++ webservices/import.php | 7 +- 32 files changed, 518 insertions(+), 460 deletions(-) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 2572b9a2b..c3e10902c 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -1710,8 +1710,9 @@ EOF $aEventsList[] ='validate'; $aEventsList[] ='keyup'; $aEventsList[] ='change'; + $sPlaceholderValue = 'placeholder="'.htmlentities(AttributeDate::GetFormat()->ToPlaceholder(), ENT_QUOTES, 'UTF-8').'"'; - $sHTMLValue = " {$sValidationSpan}{$sReloadSpan}"; + $sHTMLValue = " {$sValidationSpan}{$sReloadSpan}"; break; case 'DateTime': @@ -1719,7 +1720,8 @@ EOF $aEventsList[] ='keyup'; $aEventsList[] ='change'; - $sHTMLValue = " {$sValidationSpan}{$sReloadSpan}"; + $sPlaceholderValue = 'placeholder="'.htmlentities(AttributeDateTime::GetFormat()->ToPlaceholder(), ENT_QUOTES, 'UTF-8').'"'; + $sHTMLValue = " {$sValidationSpan}{$sReloadSpan}"; break; case 'Duration': @@ -3159,7 +3161,15 @@ EOF $value = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null, 'raw_data'); if ($value != null) { - $value = AttributeDateTime::Parse($value, $oAttDef->GetFormat()); + $oDate = $oAttDef->GetFormat()->Parse($value); + if ($oDate instanceof DateTime) + { + $value = $oDate->format($oAttDef->GetInternalFormat()); + } + else + { + $value = null; + } } } else diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index fd0792efe..6f2be9518 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -319,13 +319,16 @@ class DisplayBlock { $externalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data'); $condition = null; + $bParseSearchString = true; if (isset($aExtraParams[$sFilterCode])) { + $bParseSearchString = false; $condition = $aExtraParams[$sFilterCode]; } if ($bDoSearch && $externalFilterValue != "") { // Search takes precedence over context params... + $bParseSearchString = true; unset($aExtraParams[$sFilterCode]); if (!is_array($externalFilterValue)) { @@ -350,7 +353,7 @@ class DisplayBlock $sOpCode = 'IN'; } - $this->AddCondition($sFilterCode, $condition, $sOpCode); + $this->AddCondition($sFilterCode, $condition, $sOpCode, $bParseSearchString); } } if ($bDoSearch) @@ -882,14 +885,16 @@ EOF $sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : ''; $sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : ''; $sFilter = $this->m_oFilter->serialize(); + $oContext = new ApplicationContext(); + $sContextParam = $oContext->GetForLink(); if (isset($aExtraParams['group_by_label'])) { - $sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter)); + $sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam); } else { - $sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter)); + $sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[currentId]=$sId{$iChartCounter}&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam); } $sType = ($sChartType == 'pie') ? 'pie' : 'bar'; @@ -927,6 +932,8 @@ EOF $aGroupBy['grouped_by_1'] = $oGroupByExp; $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy, true); $aRes = CMDBSource::QueryToArray($sSql); + $oContext = new ApplicationContext(); + $sContextParam = $oContext->GetForLink(); $aGroupBy = array(); $aLabels = array(); @@ -946,7 +953,7 @@ EOF $oSubsetSearch = $this->m_oFilter->DeepClone(); $oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue)); $oSubsetSearch->AddConditionExpression($oCondition); - $aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".urlencode($oSubsetSearch->serialize()); + $aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".urlencode($oSubsetSearch->serialize()).'&'.$sContextParam; } $sJSURLs = json_encode($aURLs); } @@ -1059,7 +1066,7 @@ EOF * Add a condition (restriction) to the current DBSearch on which the display block is based * taking into account the hierarchical keys for which the condition is based on the 'below' operator */ - protected function AddCondition($sFilterCode, $condition, $sOpCode = null) + protected function AddCondition($sFilterCode, $condition, $sOpCode = null, $bParseSearchString = false) { // Workaround to an issue revealed whenever a condition on org_id is applied twice (with a hierarchy of organizations) // Moreover, it keeps the query as simple as possible @@ -1114,7 +1121,7 @@ EOF // In all other cases, just add the condition directly if (!$bConditionAdded) { - $this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator + $this->m_oFilter->AddCondition($sFilterCode, $condition, null, $bParseSearchString); // Use the default 'loose' operator } } diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index d045a620d..0144209b3 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -155,9 +155,10 @@ EOF; $sJSMonthsShort = json_encode(array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'), Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short'))); $iFirstDayOfWeek = (int) Dict::S('Calendar-FirstDayOfWeek'); - $sDateFormat = AttributeDate::GetDatePickerFormat(); - $sJSDateFormat = json_encode($sDateFormat); - $sJSTimeFormat = json_encode(trim(str_replace($sDateFormat, '', AttributeDateTime::GetDatePickerFormat()))); + $sJSDateFormat = json_encode(AttributeDate::GetFormat()->ToDatePicker()); + $sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat(); + $oTimeFormat = new DateTimeFormat($sTimeFormat); + $sJSTimeFormat = json_encode($oTimeFormat->ToDatePicker()); $sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2))); $sJSOk = json_encode(Dict::S('UI:Button:Ok')); @@ -423,14 +424,20 @@ EOF // time picker options timeFormat: $sJSTimeFormat, controlType: 'select', + closeText: $sJSOk + }); + + if ($sJSLangShort != 'en') + { + $(".datetime-pick").datetimepicker('option', { timeText: $.timepicker.regional[$sJSLangShort].timeText, hourText: $.timepicker.regional[$sJSLangShort].hourText, minuteText: $.timepicker.regional[$sJSLangShort].minuteText, secondText: $.timepicker.regional[$sJSLangShort].secondText, currentText: $.timepicker.regional[$sJSLangShort].currentText, - closeText: $sJSOk }); + } // Make sortable, everything that claims to be sortable $('.sortable').sortable( {axis: 'y', cursor: 'move', handle: '.drag_handle', stop: function() diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index cbe5e1b60..c6d6faa4f 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -34,6 +34,7 @@ require_once('htmlsanitizer.class.inc.php'); require_once(APPROOT.'sources/autoload.php'); require_once('customfieldshandler.class.inc.php'); require_once('ormcustomfieldsvalue.class.inc.php'); +require_once('datetimeformat.class.inc.php'); // This should be changed to a use when we go full-namespace require_once(APPROOT . 'sources/form/validator/validator.class.inc.php'); require_once(APPROOT . 'sources/form/validator/notemptyextkeyvalidator.class.inc.php'); @@ -298,6 +299,15 @@ abstract class AttributeDefinition return $this->MakeRealValue($sProposedValue, null); } + /** + * Parses a search string coming from user input + * @param string $sSearchString + * @return string + */ + public function ParseSearchString($sSearchString) + { + return $sSearchString; + } public function GetLabel_Obsolete() { // Written for compatibility with a data model written prior to version 0.9.1 @@ -3537,17 +3547,16 @@ class AttributeMetaEnum extends AttributeEnum */ class AttributeDateTime extends AttributeDBField { - static $sDateTimeFormat = null; - static $sTimeFormat = null; + static $oFormat = null; static public function GetFormat() { - if (self::$sDateTimeFormat == null) + if (self::$oFormat == null) { static::LoadFormatFromConfig(); } - return self::$sDateTimeFormat; - } + return self::$oFormat; + } /** * Load the 3 settings: date format, time format and data_time format from the configuration @@ -3560,11 +3569,10 @@ class AttributeDateTime extends AttributeDBField $sTimeFormat = isset($aFormats[$sLang]['time']) ? $aFormats[$sLang]['time'] : (isset($aFormats['default']['time']) ? $aFormats['default']['time'] : 'H:i:s'); $sDateAndTimeFormat = isset($aFormats[$sLang]['date_time']) ? $aFormats[$sLang]['date_time'] : (isset($aFormats['default']['date_time']) ? $aFormats['default']['date_time'] : '$date $time'); - $sFormat = str_replace(array('$date', '$time'), array($sDateFormat, $sTimeFormat), $sDateAndTimeFormat); + $sFullFormat = str_replace(array('$date', '$time'), array($sDateFormat, $sTimeFormat), $sDateAndTimeFormat); - self::SetFormat($sFormat); - self::SetTimeFormat($sTimeFormat); - AttributeDate::SetFormat($sDateFormat); + self::SetFormat(new DateTimeFormat($sFullFormat)); + AttributeDate::SetFormat(new DateTimeFormat($sDateFormat)); } /** @@ -3585,18 +3593,9 @@ class AttributeDateTime extends AttributeDBField return 'Y-m-d H:i:s'; } - static public function SetFormat($sDateTimeFormat) + static public function SetFormat(DateTimeFormat $oDateTimeFormat) { - self::$sDateTimeFormat = $sDateTimeFormat; - } - - static public function GetTimeFormat() - { - if (self::$sTimeFormat == null) - { - static::LoadFormatFromConfig(); - } - return self::$sTimeFormat; + self::$oFormat = $oDateTimeFormat; } static public function GetSQLTimeFormat() @@ -3604,286 +3603,47 @@ class AttributeDateTime extends AttributeDBField return 'H:i:s'; } - static public function SetTimeFormat($sTimeFormat) - { - self::$sTimeFormat = $sTimeFormat; - } - /** - * Return the mapping table for converting between various convention for data formats - */ - public static function GetFormatMapping() - { - return array( - // Days - 'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'dd', 'usage' => 'day', 'excel' => 'dd'), // Day of the month: 2 digits (with leading zero) - 'j' => array('regexpr' => '([1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'd', 'usage' => 'day', 'excel' => '%d'), // Day of the month: 1 or 2 digits (without leading zero) - // Months - 'm' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'mm', 'usage' => 'month', 'excel' => 'MM'), // Month on 2 digits i.e. 01-12 - 'n' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'm', 'usage' => 'month', 'excel' => '%M'), // Month on 1 or 2 digits 1-12 - // Years - 'Y' => array('regexpr' => '([0-9]{4})', 'datepicker' => 'yy', 'usage' => 'year', 'excel' => 'YYYY'), // Year on 4 digits - 'y' => array('regexpr' => '([0-9]{2})', 'datepicker' => 'y', 'usage' => 'year', 'excel' => 'YY'), // Year on 2 digits - // Hours - 'H' => array('regexpr' => '([0-1][0-9]|2[0-3])', 'datepicker' => 'HH', 'usage' => 'hour', 'excel' => 'HH'), // Hour 00..23 - 'h' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'hh', 'usage' => 'hour', 'excel' => 'hh'), // Hour 01..12 - 'G' => array('regexpr' => '([1-9]|[1[0-9]|2[0-3])', 'datepicker' => 'H', 'usage' => 'hour', 'excel' => '%H'), // Hour 0..23 - 'g' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'h', 'usage' => 'hour', 'excel' => '%h'), // Hour 1..12 - 'a' => array('regexpr' => '(am|pm)', 'datepicker' => 'tt', 'usage' => 'am/pm', 'excel' => 'am/pm'), - 'A' => array('regexpr' => '(AM|PM)', 'datepicker' => 'TT', 'usage' => 'am/pm', 'excel' => 'AM/PM'), - // Minutes - 'i' => array('regexpr' => '([0-5][0-9])', 'datepicker' => 'mm', 'usage' => 'minutes', 'excel' => 'mm'), - // Seconds - 's' => array('regexpr' => '([0-5][0-9])', 'datepicker' => 'ss', 'usage' => 'seconds', 'excel' => 'ss'), - ); - } - - /** - * Format a date into the supplied format string - * @param mixed $date An int, string, DateTime object or null !! - * @param string $sFormat The format using PHP createFromFormat convention - * @throws Exception - * @return string The formatted date - */ - public static function Format($date, $sFormat = null) - { - if ($sFormat === null) - { - $sFormat = static::GetFormat(); - } - if ($date == null) - { - $sDate = ''; - } - else if (($date === '0000-00-00') || ($date === '0000-00-00 00:00:00')) - { - $sDate = ''; - } - else if ($date instanceof DateTime) - { - // Parameter is a DateTime - $sDate = $date->format($sFormat); - } - else if (is_int($date)) - { - // Parameter is a Unix timestamp - $oDate = new DateTime(); - $oDate->setTimestamp($date); - $sDate = $oDate->format($sFormat); - } - else if (is_string($date)) - { - $oDate = new DateTime($date); - $sDate = $oDate->format($sFormat); - } - else - { - throw new Exception("AttributeDateTime::Format: Unexpected date value: ".print_r($date, true)); - } - return $sDate; - } - - /** - * Parse a date in the supplied format and return the date as a string in the internal format - * @param string $sDate The string to parse - * @param string $sFormat The format, in PHP createFromFormat convention - * @throws Exception + * Parses a search string coming from user input + * @param string $sSearchString * @return string */ - public static function Parse($sDate, $sFormat) + public function ParseSearchString($sSearchString) { - if (($sDate == null) || ($sDate == '0000-00-00 00:00:00') || ($sDate == '0000-00-00')) + try { - return null; + $oDateTime = $this->GetFormat()->Parse($sSearchString); + $sSearchString = $oDateTime->format($this->GetInternalFormat()); } - else + catch(Exception $e) { - $sFormat = preg_replace('/\\?/', '', $sFormat); // replace escaped characters by a wildcard for parsing - $oDate = DateTime::createFromFormat($sFormat, $sDate); - if ($oDate === false) + $sFormatString = '!'.(string)AttributeDate::GetFormat(); // BEWARE: ! is needed to set non-parsed fields to zero !!! + $oDateTime = DateTime::createFromFormat($sFormatString, $sSearchString); + if ($oDateTime !== false) { - throw new Exception("Unable to parse the date: '$sDate' using the format: '$sFormat'"); + $sSearchString = $oDateTime->format($this->GetInternalFormat()); } - return $oDate->format(static::GetInternalFormat()); } + return $sSearchString; + } + + static public function GetFormFieldClass() + { + return '\\Combodo\\iTop\\Form\\Field\\DateTimeField'; } /** - * Get a date or datetime format string in the jQuery UI date picker format - * @param string $sFormat - * @return string The format string using the date picker convention + * Override to specify Field class + * + * When called first, $oFormField is null and will be created (eg. Make). Then when the ::parent is called and the $oFormField is passed, MakeFormField behave more like a Prepare. */ - static public function GetDatePickerFormat() + public function MakeFormField(DBObject $oObject, $oFormField = null) { - $sFormat = static::GetFormat(); - $aMappings = static::GetFormatMapping(); - $sResult = ''; + $oFormField = parent::MakeFormField($oObject, $oFormField); + $oFormField->SetPHPDateTimeFormat($this->GetFormat()); + $oFormField->SetJSDateTimeFormat($this->GetMomentJSFormat()); - $bEscaping = false; - for($i=0; $i < strlen($sFormat); $i++) - { - if (($sFormat[$i] == '\\')) - { - $bEscaping = true; - continue; - } - - if ($bEscaping) - { - $sResult .= "'{$sFormat[$i]}'"; - $bEscaping = false; - } - else if(array_key_exists($sFormat[$i], $aMappings)) - { - // Not a litteral value, must be replaced by its regular expression pattern - $sResult .= $aMappings[$sFormat[$i]]['datepicker']; - } - else - { - - // Normal char with no special meaning - $sResult .= $sFormat[$i]; - } - } - - return $sResult; - } - - /** - * Get a date or datetime format string in the Excel format - * @param string $sFormat - * @return string The format string using the Excel convention - */ - static public function GetExcelFormat($sFormat = null) - { - $sFormat = ($sFormat == null) ? static::GetFormat() : $sFormat; - $aMappings = static::GetFormatMapping(); - $sResult = ''; - - $bEscaping = false; - for($i=0; $i < strlen($sFormat); $i++) - { - if (($sFormat[$i] == '\\')) - { - $bEscaping = true; - continue; - } - - if ($bEscaping) - { - $sResult .= $sFormat[$i]; // What's the way to escape characters in Excel format ?? - $bEscaping = false; - } - else if(array_key_exists($sFormat[$i], $aMappings)) - { - // Not a litteral value, must be replaced by its regular expression pattern - $sResult .= $aMappings[$sFormat[$i]]['excel']; - } - else - { - - // Normal char with no special meaning - $sResult .= $sFormat[$i]; - } - } - - return $sResult; - } -/* - * Unused since the sorting of the tables is always performed server-side - * - public static function GetTableSorterRule() - { - $aOrder = array(); - $aPos = array(); - $sRegExpr = static::GetRegExpr($aOrder); - foreach(array('year', 'month', 'day', 'hour', 'minutes', 'seconds') as $sUsage) - { - $pos = array_search($sUsage, $aOrder); - if ($pos !== false) - { - $aPos[$sUsage] = '$'.(1+$pos); - } - } - $sIsoDate = "{$aPos['year']}/{$aPos['month']}/{$aPos['day']}"; - if (array_key_exists('hour', $aPos)) - { - $sIsoDate .= " {$aPos['hour']}:{$aPos['minutes']}:{$aPos['seconds']}"; - } - return array('regexpr' => $sRegExpr, 'replacement' => $sIsoDate); - } - - public static function InitTableSorter($oPage, $sRuleName) - { - $aDef = static::GetTableSorterRule(); - - $oPage->add_ready_script( -<<format($sValue); + } + public function GetValueLabel($sValue, $oHostObj = null) + { + return (string)static::GetFormat()->format($sValue); } protected function GetSQLCol($bFullSpec = false) {return "DATETIME";} @@ -3916,7 +3680,7 @@ EOF public function GetValidationPattern() { - return static::GetRegExpr(); + return static::GetFormat()->ToRegExpr(); } public function GetBasicFilterOperators() @@ -3990,7 +3754,7 @@ EOF return $proposedValue; } - return date(self::GetInternalFormat(), $proposedValue); + return date(static::GetInternalFormat(), $proposedValue); } public function ScalarToSQL($value) @@ -4009,7 +3773,7 @@ EOF public function GetAsHTML($value, $oHostObject = null, $bLocalize = true) { - return Str::pure2html(static::Format($value, static::GetFormat())); + return Str::pure2html(static::GetFormat()->format($value)); } public function GetAsXML($value, $oHostObject = null, $bLocalize = true) @@ -4023,13 +3787,13 @@ EOF { return ''; } - else if (self::GetFormat() !== self::GetInternalFormat()) + else if ((string)static::GetFormat() !== static::GetInternalFormat()) { // Format conversion $oDate = new DateTime($sValue); if ($oDate !== false) { - $sValue = $oDate->format(self::GetFormat()); + $sValue = static::GetFormat()->format($oDate); } } $sFrom = array("\r\n", $sTextQualifier); @@ -4047,7 +3811,7 @@ EOF * @param Hash $aParams Values of the query parameters * @return Expression The search condition to be added (AND) to the current search */ - public function GetSmartConditionExpression($sSearchText, FieldExpression $oField, &$aParams) + public function GetSmartConditionExpression($sSearchText, FieldExpression $oField, &$aParams, $bParseSearchString = false) { // Possible smart patterns $aPatterns = array( @@ -4075,13 +3839,27 @@ EOF $sParamName1 = $oField->GetParent().'_'.$oField->GetName().'_1'; $oRightExpr = new VariableExpression($sParamName1); + if ($bParseSearchString) + { + $aParams[$sParamName1] = $this->ParseSearchString($aMatches[1]); + } + else + { $aParams[$sParamName1] = $aMatches[1]; + } $oCondition1 = new BinaryExpression($oField, '>=', $oRightExpr); $sParamName2 = $oField->GetParent().'_'.$oField->GetName().'_2'; $oRightExpr = new VariableExpression($sParamName2); $sOperator = $this->GetBasicFilterLooseOperator(); + if ($bParseSearchString) + { + $aParams[$sParamName2] = $this->ParseSearchString($aMatches[2]); + } + else + { $aParams[$sParamName2] = $aMatches[2]; + } $oCondition2 = new BinaryExpression($oField, '<=', $oRightExpr); $oNewCondition = new BinaryExpression($oCondition1, 'AND', $oCondition2); @@ -4094,18 +3872,35 @@ EOF $sSQLOperator = $aPatterns[$sPatternFound]['operator']; $sParamName = $oField->GetParent().'_'.$oField->GetName(); $oRightExpr = new VariableExpression($sParamName); + if ($bParseSearchString) + { + $aParams[$sParamName] = $this->ParseSearchString($aMatches[1]); + } + else + { $aParams[$sParamName] = $aMatches[1]; + } $oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr); break; default: - $oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams); + $oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, $aParams, $bParseSearchString); } return $oNewCondition; } + + + public function GetHelpOnSmartSearch() + { + $sDict = parent::GetHelpOnSmartSearch(); + + $oFormat = static::GetFormat(); + $sExample = $oFormat->Format(new DateTime('2015-07-19 18:40:00')); + return vsprintf($sDict, array($oFormat->ToPlaceholder(), $sExample)); + } } /** @@ -4188,20 +3983,20 @@ class AttributeDuration extends AttributeInteger */ class AttributeDate extends AttributeDateTime { - static $sDateFormat = null; + static $oDateFormat = null; static public function GetFormat() { - if (self::$sDateFormat == null) + if (self::$oDateFormat == null) { AttributeDateTime::LoadFormatFromConfig(); } - return self::$sDateFormat; + return self::$oDateFormat; } - static public function SetFormat($sDateFormat) + static public function SetFormat(DateTimeFormat $oDateFormat) { - self::$sDateFormat = $sDateFormat; + self::$oDateFormat = $oDateFormat; } /** @@ -4251,7 +4046,7 @@ class AttributeDeadline extends AttributeDateTime if ($value !== null) { $iValue = AttributeDateTime::GetAsUnixSeconds($value); - $sDate = $value; + $sDate = AttributeDateTime::Format($value); $difference = $iValue - time(); if ($difference >= 0) diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php index c920e17ef..98d47b9ba 100644 --- a/core/bulkchange.class.inc.php +++ b/core/bulkchange.class.inc.php @@ -554,7 +554,15 @@ class BulkChange else { // By default... nothing happens - $aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]); + $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); + if ($oAttDef instanceof AttributeDateTime) + { + $aResults[$iCol]= new CellStatus_Void($oAttDef->GetFormat()->Format($aRowData[$iCol])); + } + else + { + $aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]); + } } } } @@ -795,6 +803,11 @@ class BulkChange if (!is_null($this->m_sDateFormat) && (strlen($this->m_sDateFormat) > 0)) { + $sDateTimeFormat = $this->m_sDateFormat; // the specified format is actually the date AND time format + $oDateTimeFormat = new DateTimeFormat($sDateTimeFormat); + $sDateFormat = $oDateTimeFormat->ToDateFormat(); + AttributeDateTime::SetFormat($oDateTimeFormat); + AttributeDate::SetFormat(new DateTimeFormat($sDateFormat)); // Translate dates from the source data // foreach ($this->m_aAttList as $sAttCode => $iCol) @@ -802,21 +815,34 @@ class BulkChange if ($sAttCode == 'id') continue; $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); - if ($oAttDef instanceof AttributeDateTime) + if ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime { foreach($this->m_aData as $iRow => $aRowData) { - $oDate = DateTime::createFromFormat($this->m_sDateFormat, $this->m_aData[$iRow][$iCol]); - if ($oDate !== false) + $sFormat = $sDateTimeFormat; + $sValue = $this->m_aData[$iRow][$iCol]; + if (!empty($sValue)) { - $sNewDate = $oDate->format($oAttDef->GetInternalFormat()); - $this->m_aData[$iRow][$iCol] = $sNewDate; + if ($oAttDef instanceof AttributeDate) + { + $sFormat = $sDateFormat; + } + $oDate = DateTime::createFromFormat($sFormat, $this->m_aData[$iRow][$iCol]); + if ($oDate !== false) + { + $sNewDate = $oDate->format($oAttDef->GetInternalFormat()); + $this->m_aData[$iRow][$iCol] = $sNewDate; + } + else + { + // Leave the cell unchanged + $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat')); + $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat')); + } } else { - // Leave the cell unchanged - $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat')); - $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat')); + $this->m_aData[$iRow][$iCol] = ''; } } } diff --git a/core/csvbulkexport.class.inc.php b/core/csvbulkexport.class.inc.php index 333636121..c2ee9440e 100644 --- a/core/csvbulkexport.class.inc.php +++ b/core/csvbulkexport.class.inc.php @@ -34,7 +34,7 @@ class CSVBulkExport extends TabularBulkExport $oP->p(" *\ttext-qualifier: (optional) character to be used around text strings (default is '\"')."); $oP->p(" *\tno_localize: set to 1 to retrieve non-localized values (for instance for ENUM values). Default is 0 (= localized values)"); $oP->p(" *\tformatted_text: set to 1 to export case logs and formatted text fields with their HTML markup. Default is 0 (= plain text)"); - $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the format used in the user interface). Example: 'm/d/Y H:i:s'"); + $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the SQL format used in the user interface). e.g. 'Y-m-d H:i:s'"); } public function ReadParameters() @@ -59,14 +59,22 @@ class CSVBulkExport extends TabularBulkExport $this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data')); $this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true); - $sDateFormatRadio = utils::ReadParam('date_format_radio', 'custom'); - if ($sDateFormatRadio == 'default') + $sDateFormatRadio = utils::ReadParam('date_format_radio', ''); + switch($sDateFormatRadio) { - $this->aStatusInfo['date_format'] = AttributeDateTime::GetFormat(); - } - else - { - $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); + case 'default': + // Export from the UI => format = same as is the UI + $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); + break; + + case 'custom': + // Custom format specified from the UI + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + break; + + default: + // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); } } @@ -176,12 +184,12 @@ class CSVBulkExport extends TabularBulkExport $oP->add(''); $oP->add(''); - $sDateTimeFormat = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); - $sDefaultChecked = ($sDateTimeFormat == AttributeDateTime::GetFormat()) ? ' checked' : ''; - $sCustomChecked = ($sDateTimeFormat !== AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + $sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; $oP->add('

'.Dict::S('Core:BulkExport:DateTimeFormat').'

'); - $sDefaultFormat = htmlentities(AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); - $sExample = htmlentities(date(AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); + $sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); + $sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); $oP->add('
'); $sFormatInput = ''; $oP->add(''); @@ -267,6 +275,17 @@ EOF $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); + $sExportDateTimeFormat = $this->aStatusInfo['date_format']; + $oPrevDateTimeFormat = AttributeDateTime::GetFormat(); + $oPrevDateFormat = AttributeDate::GetFormat(); + if ($sExportDateTimeFormat !== (string)$oPrevDateTimeFormat) + { + // Change date & time formats + $oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat); + $oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat()); + AttributeDateTime::SetFormat($oDateTimeFormat); + AttributeDate::SetFormat($oDateFormat); + } while($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); @@ -287,10 +306,7 @@ EOF break; default: - $sPrevFormat = AttributeDateTime::GetFormat(); - AttributeDateTime::SetFormat($this->aStatusInfo['date_format']); $sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']); - AttributeDateTime::SetFormat($sPrevFormat); } } if ($this->aStatusInfo['charset'] != 'UTF-8') @@ -307,6 +323,9 @@ EOF $sData .= implode($this->aStatusInfo['separator'], $aData)."\n"; $iCount++; } + // Restore original date & time formats + AttributeDateTime::SetFormat($oPrevDateTimeFormat); + AttributeDate::SetFormat($oPrevDateFormat); set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) diff --git a/core/datetimeformat.class.inc.php b/core/datetimeformat.class.inc.php index 8c398e682..5dfa4d22f 100644 --- a/core/datetimeformat.class.inc.php +++ b/core/datetimeformat.class.inc.php @@ -40,7 +40,15 @@ class DateTimeFormat */ public function __construct($sPHPFormat) { - $this->sPHPFormat = $sPHPFormat; + $this->sPHPFormat = (string)$sPHPFormat; + } + + /** + * @return string + */ + public function __toString() + { + return $this->sPHPFormat; } /** @@ -231,14 +239,13 @@ class DateTimeFormat */ public function ToPlaceholder($sFormat = null) { - $sFormat = ($sFormat == null) ? static::GetFormat() : $sFormat; $aMappings = static::GetFormatMapping(); $sResult = ''; $bEscaping = false; - for($i=0; $i < strlen($sFormat); $i++) + for($i=0; $i < strlen($this->sPHPFormat); $i++) { - if (($sFormat[$i] == '\\')) + if (($this->sPHPFormat[$i] == '\\')) { $bEscaping = true; continue; @@ -246,41 +253,41 @@ class DateTimeFormat if ($bEscaping) { - $sResult .= $sFormat[$i]; // No need to escape characters in the placeholder + $sResult .= $this->sPHPFormat[$i]; // No need to escape characters in the placeholder $bEscaping = false; } - else if(array_key_exists($sFormat[$i], $aMappings)) + else if(array_key_exists($this->sPHPFormat[$i], $aMappings)) { // Not a litteral value, must be replaced by Dict equivalent - $sResult .= Dict::S('Core:DateTime:Placeholder_'.$sFormat[$i]); + $sResult .= Dict::S('Core:DateTime:Placeholder_'.$this->sPHPFormat[$i]); } else { // Normal char with no special meaning - $sResult .= $sFormat[$i]; + $sResult .= $this->sPHPFormat[$i]; } } return $sResult; } - + /** - * Produces the Date format string by extracting only the date part of the date and time format string + * Produces a subformat (Date or Time) by extracting the part of the whole DateTime format containing only the given placeholders * @return string */ - public function ToDateFormat() + protected function ToSubFormat($aPlaceholders) { $aDatePlaceholders = array('Y', 'y', 'd', 'j', 'm', 'n'); $iStart = 999; $iEnd = 0; - foreach($aDatePlaceholders as $sChar) + foreach($aPlaceholders as $sChar) { $iPos = strpos($this->sPHPFormat, $sChar); if ($iPos !== false) { - if (($iPos > 0) && ($aDatePlaceholders[$iPos-1] == '\\')) + if (($iPos > 0) && ($this->sPHPFormat[$iPos-1] == '\\')) { // The placeholder is actually escaped, it's a litteral character, ignore it continue; @@ -293,6 +300,24 @@ class DateTimeFormat return $sFormat; } + /** + * Produces the Date format string by extracting only the date part of the date and time format string + * @return string + */ + public function ToDateFormat() + { + return $this->ToSubFormat(array('Y', 'y', 'd', 'j', 'm', 'n')); + } + + /** + * Produces the Time format string by extracting only the time part of the date and time format string + * @return string + */ + public function ToTimeFormat() + { + return $this->ToSubFormat(array('H', 'h', 'G', 'g', 'i', 's')); + } + /** * Get the regular expression to (approximately) validate a date/time for the current format * The validation does not take into account the number of days in a month (i.e. June 31st will pass, as well as Feb 30th!) diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index c42203234..edce53061 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -268,7 +268,7 @@ class DBObjectSearch extends DBSearch $this->AddConditionExpression($oNewCondition); } - public function AddCondition($sFilterCode, $value, $sOpCode = null) + public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSeachString = false) { MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass())); $oFilterDef = MetaModel::GetClassFilterDef($this->GetClass(), $sFilterCode); @@ -283,12 +283,18 @@ class DBObjectSearch extends DBSearch else { $oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode); - $oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams); + $oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams, $bParseSeachString); $this->AddConditionExpression($oNewCondition); return; } } MyHelpers::CheckKeyInArray('operator', $sOpCode, $oFilterDef->GetOperators()); + // Parse search strings if needed and if the filter code corresponds to a valid attcode + if($bParseSeachString && MetaModel::IsValidAttCode($this->GetClass(), $sFilterCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode); + $value = $oAttDef->ParseSearchString($value); + } // Preserve backward compatibility - quick n'dirty way to change that API semantic // diff --git a/core/excelbulkexport.class.inc.php b/core/excelbulkexport.class.inc.php index 63c84f9b0..7640db699 100644 --- a/core/excelbulkexport.class.inc.php +++ b/core/excelbulkexport.class.inc.php @@ -47,7 +47,7 @@ class ExcelBulkExport extends TabularBulkExport $oP->p(" * xlsx format options:"); $oP->p(" *\tfields: the comma separated list of field codes to export (e.g: name,org_id,service_name...)."); $oP->p(" *\tformatted_text: set to 1 to export case logs and formatted text fields with their HTML markup. Default is 0 (= plain text)"); - $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the format used in the user interface). Example: 'm/d/Y H:i:s'"); + $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the SQL format). e.g. 'Y-m-d H:i:s'"); } public function ReadParameters() @@ -55,14 +55,22 @@ class ExcelBulkExport extends TabularBulkExport parent::ReadParameters(); $this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true); - $sDateFormatRadio = utils::ReadParam('date_format_radio', 'custom'); - if ($sDateFormatRadio == 'default') + $sDateFormatRadio = utils::ReadParam('date_format_radio', ''); + switch($sDateFormatRadio) { - $this->aStatusInfo['date_format'] = AttributeDateTime::GetFormat(); - } - else - { - $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); + case 'default': + // Export from the UI => format = same as is the UI + $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); + break; + + case 'custom': + // Custom format specified from the UI + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + break; + + default: + // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); } } @@ -89,12 +97,12 @@ class ExcelBulkExport extends TabularBulkExport $oP->add(''); - $sDateTimeFormat = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); - $sDefaultChecked = ($sDateTimeFormat == AttributeDateTime::GetFormat()) ? ' checked' : ''; - $sCustomChecked = ($sDateTimeFormat !== AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + $sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; $oP->add('

'.Dict::S('Core:BulkExport:DateTimeFormat').'

'); - $sDefaultFormat = htmlentities(AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); - $sExample = htmlentities(date(AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); + $sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); + $sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); $oP->add('
'); $sFormatInput = ''; $oP->add(''); @@ -304,7 +312,8 @@ EOF $fStartExcel = microtime(true); $writer = new XLSXWriter(); - $writer->setDateTimeFormat(AttributeDateTime::GetExcelFormat($this->aStatusInfo['date_format'])); + $oDateTimeFormat = new DateTimeFormat($this->aStatusInfo['date_format']); + $writer->setDateTimeFormat($oDateTimeFormat->ToExcel()); $writer->setAuthor(UserRights::GetUserFriendlyName()); $aHeaderTypes = array(); $aHeaderNames = array(); diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php index c0cea3eab..d1a910a85 100644 --- a/core/ormcaselog.class.inc.php +++ b/core/ormcaselog.class.inc.php @@ -234,14 +234,14 @@ class ormCaseLog { if (is_int($aIndex[$index]['date'])) { // Unix timestamp - $sDate = date(AttributeDateTime::GetFormat(), $aIndex[$index]['date']); + $sDate = date((string)AttributeDateTime::GetFormat(), $aIndex[$index]['date']); } elseif (is_object($aIndex[$index]['date'])) { if (version_compare(phpversion(), '5.3.0', '>=')) { // DateTime - $sDate = $aIndex[$index]['date']->format(AttributeDateTime::GetFormat()); + $sDate = $aIndex[$index]['date']->format((string)AttributeDateTime::GetFormat()); } else { @@ -322,14 +322,14 @@ class ormCaseLog { if (is_int($aIndex[$index]['date'])) { // Unix timestamp - $sDate = date(AttributeDateTime::GetFormat(),$aIndex[$index]['date']); + $sDate = date((string)AttributeDateTime::GetFormat(),$aIndex[$index]['date']); } elseif (is_object($aIndex[$index]['date'])) { if (version_compare(phpversion(), '5.3.0', '>=')) { // DateTime - $sDate = $aIndex[$index]['date']->format(AttributeDateTime::GetFormat()); + $sDate = $aIndex[$index]['date']->format((string)AttributeDateTime::GetFormat()); } else { @@ -425,14 +425,14 @@ class ormCaseLog { if (is_int($aIndex[$index]['date'])) { // Unix timestamp - $sDate = date(AttributeDateTime::GetFormat(),$aIndex[$index]['date']); + $sDate = date((string)AttributeDateTime::GetFormat(),$aIndex[$index]['date']); } elseif (is_object($aIndex[$index]['date'])) { if (version_compare(phpversion(), '5.3.0', '>=')) { // DateTime - $sDate = $aIndex[$index]['date']->format(AttributeDateTime::GetFormat()); + $sDate = $aIndex[$index]['date']->format((string)AttributeDateTime::GetFormat()); } else { diff --git a/core/pdfbulkexport.class.inc.php b/core/pdfbulkexport.class.inc.php index 851b59522..31a43a317 100644 --- a/core/pdfbulkexport.class.inc.php +++ b/core/pdfbulkexport.class.inc.php @@ -31,7 +31,7 @@ class PDFBulkExport extends HTMLBulkExport $oP->p(" *\tfields: (mandatory) the comma separated list of field codes to export (e.g: name,org_id,service_name...)."); $oP->p(" *\tpage_size: (optional) size of the page. One of A4, A3, Letter (default is 'A4')."); $oP->p(" *\tpage_orientation: (optional) the orientation of the page. Either Portrait or Landscape (default is 'Portrait')."); - $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the format used in the user interface). Example: 'm/d/Y H:i:s'"); + $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the SQL format). e.g. 'Y-m-d H:i:s'"); } public function EnumFormParts() @@ -59,12 +59,12 @@ class PDFBulkExport extends HTMLBulkExport $oP->add(''); - $sDateTimeFormat = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); - $sDefaultChecked = ($sDateTimeFormat == AttributeDateTime::GetFormat()) ? ' checked' : ''; - $sCustomChecked = ($sDateTimeFormat !== AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + $sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; $oP->add('

'.Dict::S('Core:BulkExport:DateTimeFormat').'

'); - $sDefaultFormat = htmlentities(AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); - $sExample = htmlentities(date(AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); + $sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); + $sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); $oP->add('
'); $sFormatInput = ''; $oP->add(''); @@ -114,14 +114,22 @@ EOF $this->aStatusInfo['page_size'] = utils::ReadParam('page_size', 'A4', true, 'raw_data'); $this->aStatusInfo['page_orientation'] = utils::ReadParam('page_orientation', 'L', true); - $sDateFormatRadio = utils::ReadParam('date_format_radio', 'custom'); - if ($sDateFormatRadio == 'default') + $sDateFormatRadio = utils::ReadParam('date_format_radio', ''); + switch($sDateFormatRadio) { - $this->aStatusInfo['date_format'] = AttributeDateTime::GetFormat(); - } - else - { - $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', AttributeDateTime::GetFormat(), true, 'raw_data'); + case 'default': + // Export from the UI => format = same as is the UI + $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); + break; + + case 'custom': + // Custom format specified from the UI + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + break; + + default: + // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); } } @@ -141,10 +149,10 @@ EOF public function GetNextChunk(&$aStatus) { - $sPrevFormat = AttributeDateTime::GetFormat(); - AttributeDateTime::SetFormat($this->aStatusInfo['date_format']); + $oPrevFormat = AttributeDateTime::GetFormat(); + AttributeDateTime::SetFormat(new DateTimeFormat($this->aStatusInfo['date_format'])); $sData = parent::GetNextChunk($aStatus); - AttributeDateTime::SetFormat($sPrevFormat); + AttributeDateTime::SetFormat($oPrevFormat); $hFile = @fopen($this->aStatusInfo['tmp_file'], 'ab'); if ($hFile === false) { diff --git a/core/spreadsheetbulkexport.class.inc.php b/core/spreadsheetbulkexport.class.inc.php index ddd0e1338..910ea4d48 100644 --- a/core/spreadsheetbulkexport.class.inc.php +++ b/core/spreadsheetbulkexport.class.inc.php @@ -30,6 +30,7 @@ class SpreadsheetBulkExport extends TabularBulkExport $oP->p(" * spreadsheet format options:"); $oP->p(" *\tfields: (mandatory) the comma separated list of field codes to export (e.g: name,org_id,service_name...)."); $oP->p(" *\tno_localize: (optional) pass 1 to retrieve the raw (untranslated) values for enumerated fields. Default: 0."); + $oP->p(" *\tdate_format: the format to use when exporting date and time fields (default = the SQL format). e.g. 'Y-m-d H:i:s'"); } public function EnumFormParts() @@ -51,15 +52,59 @@ class SpreadsheetBulkExport extends TabularBulkExport $oP->add(''); $oP->add(''); $oP->add(''); + + $sDateTimeFormat = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + $sDefaultChecked = ($sDateTimeFormat == (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; + $sCustomChecked = ($sDateTimeFormat !== (string)AttributeDateTime::GetFormat()) ? ' checked' : ''; + + $oP->add(''); + $oP->add(''); $oP->add('
'); + $oP->add('

'.Dict::S('Core:BulkExport:DateTimeFormat').'

'); + $sDefaultFormat = htmlentities((string)AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'); + $sExample = htmlentities(date((string)AttributeDateTime::GetFormat()), ENT_QUOTES, 'UTF-8'); + $oP->add('
'); + $sFormatInput = ''; + $oP->add(''); + $oP->add('
'); $oP->add(''); + $sJSTooltip = json_encode('
'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'
'); + $oP->add_ready_script( +<< format = same as is the UI + $this->aStatusInfo['date_format'] = (string)AttributeDateTime::GetFormat(); + break; + + case 'custom': + // Custom format specified from the UI + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetFormat(), true, 'raw_data'); + break; + + default: + // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise + $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); + } + } protected function GetSampleData($oObj, $sAttCode) { @@ -89,6 +134,10 @@ class SpreadsheetBulkExport extends TabularBulkExport { $sRet = $oObj->GetAsHTML($sAttCode); } + elseif ($oAttDef instanceof AttributeCustomFields) + { + $sRet = $oObj->GetAsHTML($sAttCode); + } else { if ($this->bLocalizeOutput) @@ -97,7 +146,7 @@ class SpreadsheetBulkExport extends TabularBulkExport } else { - $sRet = htmlentities($value, ENT_QUOTES, 'UTF-8'); + $sRet = htmlentities((string)$value, ENT_QUOTES, 'UTF-8'); } } } @@ -164,7 +213,13 @@ class SpreadsheetBulkExport extends TabularBulkExport $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); - + + $sExportDateTimeFormat = $this->aStatusInfo['date_format']; + // Date & time formats + $oDateTimeFormat = new DateTimeFormat($sExportDateTimeFormat); + $oDateFormat = new DateTimeFormat($oDateTimeFormat->ToDateFormat()); + $oTimeFormat = new DateTimeFormat($oDateTimeFormat->ToTimeFormat()); + $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); @@ -199,10 +254,16 @@ class SpreadsheetBulkExport extends TabularBulkExport $oFinalAttDef = $oAttDef->GetFinalAttDef(); if (get_class($oFinalAttDef) == 'AttributeDateTime') { - $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCode)); - $sData .= ''.date('Y-m-d', $iDate).''; // Add the first column directly - $sField = date('H:i:s', $iDate); // Will add the second column below - $sData .= "$sField"; + // Split the date and time in two columns + $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); + $sTime = $oTimeFormat->Format($oObj->Get($sAttCode)); + $sData .= "$sDate"; + $sData .= "$sTime"; + } + else if (get_class($oFinalAttDef) == 'AttributeDate') + { + $sDate = $oDateFormat->Format($oObj->Get($sAttCode)); + $sData .= "$sDate"; } else if($oAttDef instanceof AttributeCaseLog) { diff --git a/dictionaries/cs.dictionary.itop.core.php b/dictionaries/cs.dictionary.itop.core.php index 01ba79097..f02dafe73 100755 --- a/dictionaries/cs.dictionary.itop.core.php +++ b/dictionaries/cs.dictionary.itop.core.php @@ -98,8 +98,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array( 'Core:AttributeDateTime?SmartSearch' => '

Formát data:
- yyyy-mm-dd hh:mm:ss
- Například: 2011-07-19 18:40:00 + %1$s
+ Například: %2$s

Operátory:
@@ -116,8 +116,8 @@ Je-li čas vynechán, bude nastaveno 00:00:00 'Core:AttributeDate?SmartSearch' => '

Formát data:
- yyyy-mm-dd
- Například: 2011-07-19 + %1$s
+ Například: %2$s

Operátory:
diff --git a/dictionaries/da.dictionary.itop.core.php b/dictionaries/da.dictionary.itop.core.php index ce85d1608..64ea675ea 100644 --- a/dictionaries/da.dictionary.itop.core.php +++ b/dictionaries/da.dictionary.itop.core.php @@ -1432,8 +1432,8 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$s
+ Example: %2$s

Operators:
@@ -1449,8 +1449,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/de.dictionary.itop.core.php b/dictionaries/de.dictionary.itop.core.php index 129902655..8714519c8 100644 --- a/dictionaries/de.dictionary.itop.core.php +++ b/dictionaries/de.dictionary.itop.core.php @@ -358,8 +358,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array( 'Core:AttributeDateTime?SmartSearch' => '

Datumsformat:
- yyyy-mm-dd hh:mm:ss
- Beispiel: 2011-07-19 18:40:00 + %1$s
+ Beispiel: %2$s

Operatoren:
@@ -375,8 +375,8 @@ Falls der Zeit-Wert weggelassenw ird, ist der Default 00:00:00 'Core:AttributeDate?SmartSearch' => '

Datumsformat:
- yyyy-mm-dd
- Beispiel: 2011-07-19 + %1$s
+ Beispiel: %2$s

Operatoren:
diff --git a/dictionaries/dictionary.itop.core.php b/dictionaries/dictionary.itop.core.php index d242becce..e81fd65f0 100644 --- a/dictionaries/dictionary.itop.core.php +++ b/dictionaries/dictionary.itop.core.php @@ -96,8 +96,8 @@ Dict::Add('EN US', 'English', 'English', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$s
+ Example: %2$s

Operators:
@@ -114,8 +114,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/es_cr.dictionary.itop.core.php b/dictionaries/es_cr.dictionary.itop.core.php index f76477035..c8b5e2d1b 100644 --- a/dictionaries/es_cr.dictionary.itop.core.php +++ b/dictionaries/es_cr.dictionary.itop.core.php @@ -96,8 +96,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array( 'Core:AttributeDateTime?SmartSearch' => '

Formato de Fecha:
- yyyy-mm-dd hh:mm:ss
- Ejemplo: 2011-07-19 18:40:00 + %1$s
+ Ejemplo: %2$s

Operadores:
@@ -114,8 +114,8 @@ Si se omite el tiempo, por omisión es 00:00:00 'Core:AttributeDate?SmartSearch' => '

Formato de Fecha:
- yyyy-mm-dd
- Ejemplo: 2011-07-19 + %1$s
+ Ejemplo: %2$s

Operadores:
diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php index e4ffa60ab..e7b584a87 100644 --- a/dictionaries/fr.dictionary.itop.core.php +++ b/dictionaries/fr.dictionary.itop.core.php @@ -467,8 +467,8 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Core:AttributeDateTime?SmartSearch' => '

Format de date :
- aaaa-mm-jj hh:mm:ss
- Exemple : 2011-07-19 18:40:00 + %1$s
+ Exemple : %2$s

Opérateurs :
@@ -484,8 +484,8 @@ Si l\'heure n\'est pas spécifiée, cela revient à 00:00:00 (minuit) 'Core:AttributeDate?SmartSearch' => '

Format de date :
- aaaa-mm-jj
- Exemple : 2011-07-19 + %1$s
+ Exemple : %2$s

Opérateurs :
diff --git a/dictionaries/hu.dictionary.itop.core.php b/dictionaries/hu.dictionary.itop.core.php index c68a6f27f..90e9bbbf6 100755 --- a/dictionaries/hu.dictionary.itop.core.php +++ b/dictionaries/hu.dictionary.itop.core.php @@ -501,8 +501,8 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$s
+ Example: %2$s

Operators:
@@ -516,8 +516,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/it.dictionary.itop.core.php b/dictionaries/it.dictionary.itop.core.php index 46d38dd0b..17523e8bb 100644 --- a/dictionaries/it.dictionary.itop.core.php +++ b/dictionaries/it.dictionary.itop.core.php @@ -90,8 +90,8 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array( 'Core:AttributeDateTime?SmartSearch' => '

Formato data:
- aaaa-mm-gg hh:mm:ss
- Esempio: 2011-07-19 18:40:00 + %1$s
+ Esempio: %2$s

Operatori:
@@ -108,8 +108,8 @@ Se \'oraè omessa, di default è 00:00:00 'Core:AttributeDate?SmartSearch' => '

Formato data:
- aaaa-mm-gg
- Esempio: 2011-07-19 + %1$s
+ Esempio: %2$s

Operatori:
diff --git a/dictionaries/ja.dictionary.itop.core.php b/dictionaries/ja.dictionary.itop.core.php index 4ff9c4a03..af6819c83 100644 --- a/dictionaries/ja.dictionary.itop.core.php +++ b/dictionaries/ja.dictionary.itop.core.php @@ -360,8 +360,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- 例: 2011-07-19 18:40:00 + %1$s
+ 例: %2$s

Operators:
@@ -377,8 +377,8 @@ Operators:
'Core:AttributeDate?SmartSearch' => '

日付フォーマット:
- yyyy-mm-dd
- 例: 2011-07-19 + %1$s
+ 例: %2$s

演算子:
diff --git a/dictionaries/nl.dictionary.itop.core.php b/dictionaries/nl.dictionary.itop.core.php index 77dcd5c05..1fd1c087f 100644 --- a/dictionaries/nl.dictionary.itop.core.php +++ b/dictionaries/nl.dictionary.itop.core.php @@ -101,8 +101,8 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$s
+ Example: %2$s

Operators:
@@ -119,8 +119,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/pt_br.dictionary.itop.core.php b/dictionaries/pt_br.dictionary.itop.core.php index 996e81fd5..0df7d97fb 100644 --- a/dictionaries/pt_br.dictionary.itop.core.php +++ b/dictionaries/pt_br.dictionary.itop.core.php @@ -96,8 +96,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array( 'Core:AttributeDateTime?SmartSearch' => '

Data formato:
- yyyy-mm-dd hh:mm:ss
- Exemplo: 2011-07-19 18:40:00 + %1$s
+ Exemplo: %2$s

Operadores:
@@ -114,8 +114,8 @@ Se o tempo for omitido, o padrão é 00:00:00 'Core:AttributeDate?SmartSearch' => '

Data formato:
- yyyy-mm-dd
- Exemplo: 2011-07-19 + %1$s
+ Exemplo: %2$s

Operadores:
diff --git a/dictionaries/ru.dictionary.itop.core.php b/dictionaries/ru.dictionary.itop.core.php index 9782d1858..c6e0693cf 100644 --- a/dictionaries/ru.dictionary.itop.core.php +++ b/dictionaries/ru.dictionary.itop.core.php @@ -91,8 +91,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- гггг-мм-дд чч:мм:сс
- Пример: 2011-07-19 18:40:00 + %1$s
+ Пример: %2$s

Operators:
@@ -109,8 +109,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- гггг-мм-дд
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/tr.dictionary.itop.core.php b/dictionaries/tr.dictionary.itop.core.php index af036c80b..4c8a52863 100644 --- a/dictionaries/tr.dictionary.itop.core.php +++ b/dictionaries/tr.dictionary.itop.core.php @@ -448,8 +448,8 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$ss
+ Example: %2$s

Operators:
@@ -465,8 +465,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/dictionaries/zh.dictionary.itop.core.php b/dictionaries/zh.dictionary.itop.core.php index 9905581a6..66c9382a8 100644 --- a/dictionaries/zh.dictionary.itop.core.php +++ b/dictionaries/zh.dictionary.itop.core.php @@ -447,8 +447,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array( 'Core:AttributeDateTime?SmartSearch' => '

Date format:
- yyyy-mm-dd hh:mm:ss
- Example: 2011-07-19 18:40:00 + %1$s
+ Example: %2$s

Operators:
@@ -464,8 +464,8 @@ If the time is omitted, it defaults to 00:00:00 'Core:AttributeDate?SmartSearch' => '

Date format:
- yyyy-mm-dd
- Example: 2011-07-19 + %1$s
+ Example: %2$s

Operators:
diff --git a/pages/csvimport.php b/pages/csvimport.php index eff9d2949..1ccbd72b7 100644 --- a/pages/csvimport.php +++ b/pages/csvimport.php @@ -210,9 +210,9 @@ try $sEncoding = utils::ReadParam('encoding', 'UTF-8'); $sSynchroScope = utils::ReadParam('synchro_scope', '', false, 'raw_data'); $sDateTimeFormat = utils::ReadParam('date_time_format', 'default'); - $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', AttributeDateTime::GetFormat(), false, 'raw_data'); + $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', (string)AttributeDateTime::GetFormat(), false, 'raw_data'); - $sChosenDateFormat = ($sDateTimeFormat == 'default') ? AttributeDateTime::GetFormat() : $sCustomDateTimeFormat; + $sChosenDateFormat = ($sDateTimeFormat == 'default') ? (string)AttributeDateTime::GetFormat() : $sCustomDateTimeFormat; if (!empty($sSynchroScope)) { @@ -762,7 +762,7 @@ EOF $bAdvanced = utils::ReadParam('advanced', 0); $sEncoding = utils::ReadParam('encoding', 'UTF-8'); $sDateTimeFormat = utils::ReadParam('date_time_format', 'default'); - $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', AttributeDateTime::GetFormat(), false, 'raw_data'); + $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', (string)AttributeDateTime::GetFormat(), false, 'raw_data'); $sSynchroScope = utils::ReadParam('synchro_scope', '', false, 'raw_data'); if (!empty($sSynchroScope)) @@ -1104,7 +1104,7 @@ EOF $aFieldsMapping = utils::ReadParam('field', array(), false, 'raw_data'); $aSearchFields = utils::ReadParam('search_field', array(), false, 'field_name'); $sDateTimeFormat = utils::ReadParam('date_time_format', 'default'); - $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', AttributeDateTime::GetFormat(), false, 'raw_data'); + $sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', (string)AttributeDateTime::GetFormat(), false, 'raw_data'); // Create a truncated version of the data used for the fast preview // Take about 20 lines of data... knowing that some lines may contain carriage returns @@ -1167,8 +1167,8 @@ EOF $oPage->add('

'.Dict::Format('UI:CSVImport:Skip_N_LinesAtTheBeginning', '').'

'); $oPage->add(''); $oPage->add('

'.Dict::S('UI:CSVImport:DateAndTimeFormats').'

'); - $oPage->add('

'.Dict::Format('UI:CSVImport:DefaultDateTimeFormat_Format_Example', htmlentities(AttributeDateTime::GetFormat(), ENT_QUOTES, 'UTF-8'), date(AttributeDateTime::GetFormat())).'

'); - $oPage->add('

'.Dict::Format('UI:CSVImport:CustomDateTimeFormat', '').'

'); + $oPage->add('

'); + $oPage->add('

'); $oPage->add(''); $oPage->add(''); $oPage->add(''); @@ -1262,6 +1262,7 @@ EOF <<sPHPDateTimeFormat; + } + + /** + * + * @param string $sFormat + * @return \Combodo\iTop\Form\Field\DateTimeField + */ + public function SetPHPDateTimeFormat($sDateTimeFormat) + { + $this->sPHPDateTimeFormat = $sDateTimeFormat; + return $this; + } + + /** + * + * @return string + */ + public function GetJSDateTimeFormat() + { + return $this->sDateTimeFormat; + } + + /** + * + * @param string $sFormat + * @return \Combodo\iTop\Form\Field\DateTimeField + */ + public function SetJSDateTimeFormat($sDateTimeFormat) + { + $this->sDateTimeFormat = $sDateTimeFormat; + return $this; + } + + public function GetDisplayValue() + { + return \AttributeDatetime::Format($this->currentValue, $this->GetPHPDateTimeFormat()); + } } diff --git a/sources/renderer/bootstrap/bsformrenderer.class.inc.php b/sources/renderer/bootstrap/bsformrenderer.class.inc.php index 87d75c32a..91796e21e 100644 --- a/sources/renderer/bootstrap/bsformrenderer.class.inc.php +++ b/sources/renderer/bootstrap/bsformrenderer.class.inc.php @@ -52,6 +52,7 @@ class BsFormRenderer extends FormRenderer $this->AddSupportedField('SubFormField', 'BsSubFormFieldRenderer'); $this->AddSupportedField('SelectObjectField', 'BsSelectObjectFieldRenderer'); $this->AddSupportedField('LinkedSetField', 'BsLinkedSetFieldRenderer'); + $this->AddSupportedField('DateTimeField', 'BsSimpleFieldRenderer'); $this->AddSupportedField('FileUploadField', 'BsFileUploadFieldRenderer'); } diff --git a/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php index 837c4f495..a72de9343 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php @@ -51,6 +51,25 @@ class BsSimpleFieldRenderer extends FieldRenderer { switch ($sFieldClass) { + case 'Combodo\\iTop\\Form\\Field\\DateTimeField': + $oOutput->AddHtml('

'); + if ($this->oField->GetLabel() !== '') + { + $oOutput->AddHtml(''); + } + $oOutput->AddHtml('
'); + $oOutput->AddHtml('
'); + $oOutput->AddHtml(''); + $oOutput->AddHtml(''); + $oOutput->AddHtml('
'); + $oOutput->AddHtml('
'); + $sJSFormat = json_encode($this->oField->GetJSDateTimeFormat()); + $oOutput->AddJs( +<<oField->GetGlobalId()}').datetimepicker({format: $sJSFormat}); +EOF + ); + break; case 'Combodo\\iTop\\Form\\Field\\StringField': $oOutput->AddHtml('
'); if ($this->oField->GetLabel() !== '') @@ -230,6 +249,21 @@ EOF $oOutput->AddHtml('
'); break; + case 'Combodo\\iTop\\Form\\Field\\DateTimeField': + $oOutput->AddHtml('
'); + // Showing label / value only if read-only but not hidden + if (!$this->oField->GetHidden()) + { + if ($this->oField->GetLabel() !== '') + { + $oOutput->AddHtml(''); + } + $oOutput->AddHtml('
')->AddHtml($this->oField->GetDisplayValue(), true)->AddHtml('
'); + } + $oOutput->AddHtml(''); + $oOutput->AddHtml('
'); + break; + case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\SelectField': case 'Combodo\\iTop\\Form\\Field\\MultipleSelectField': @@ -317,6 +351,7 @@ EOF case 'Combodo\\iTop\\Form\\Field\\HiddenField': case 'Combodo\\iTop\\Form\\Field\\RadioField': case 'Combodo\\iTop\\Form\\Field\\CheckboxField': + case 'Combodo\\iTop\\Form\\Field\\DateTimeField': $oOutput->AddJs( <<add_comment("Separator: ".$sSep); $oP->add_comment("Qualifier: ".$sQualifier); $oP->add_comment("Charset Encoding:".$sCharSet); - if (strlen($sDateFormat) > 0) + if (($sDateFormat !== null) && (strlen($sDateFormat) > 0)) { - $oP->add_comment("Date format: '$sDateFormat'"); + $oP->add_comment("Date and time format: '$sDateFormat'"); + $oDateTimeFormat = new DateTimeFormat($sDateFormat); + $sDateOnlyFormat = $oDateTimeFormat->ToDateFormat(); + $oP->add_comment("Date format: '$sDateOnlyFormat'"); } else {