diff --git a/core/dict.class.inc.php b/core/dict.class.inc.php index e3a2a9c8e..0e2cdd466 100644 --- a/core/dict.class.inc.php +++ b/core/dict.class.inc.php @@ -20,7 +20,7 @@ * Class Dict * Management of localizable strings * - * @copyright Copyright (C) 2010-2012 Combodo SARL + * @copyright Copyright (C) 2010-2018 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ @@ -65,6 +65,11 @@ class Dict protected static $m_aData = array(); protected static $m_sApplicationPrefix = null; + /** + * @param $sLanguageCode + * + * @throws \DictExceptionUnknownLanguage + */ public static function SetDefaultLanguage($sLanguageCode) { if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) @@ -74,6 +79,11 @@ class Dict self::$m_sDefaultLanguage = $sLanguageCode; } + /** + * @param $sLanguageCode + * + * @throws \DictExceptionUnknownLanguage + */ public static function SetUserLanguage($sLanguageCode) { if (!array_key_exists($sLanguageCode, self::$m_aLanguages)) @@ -113,7 +123,6 @@ class Dict * @param string $sDefault Default value if there is no match in the dictionary * @param bool $bUserLanguageOnly True to allow the use of the default language as a fallback, false otherwise * - * @throws DictExceptionMissingString * @return string */ public static function S($sStringCode, $sDefault = null, $bUserLanguageOnly = false) @@ -124,7 +133,7 @@ class Dict if (!array_key_exists(self::GetUserLanguage(), self::$m_aData)) { - // It may happen, when something happens before the dictionnaries get loaded + // It may happen, when something happens before the dictionaries get loaded return $sStringCode; } $aCurrentDictionary = self::$m_aData[self::GetUserLanguage()]; @@ -155,25 +164,12 @@ class Dict } // Could not find the string... // - switch (self::$m_iErrorMode) + if (is_null($sDefault)) { - case DICT_ERR_STRING: - if (is_null($sDefault)) - { - return $sStringCode; - } - else - { - return $sDefault; - } - break; - - case DICT_ERR_EXCEPTION: - default: - throw new DictExceptionMissingString(self::$m_sCurrentLanguage, $sStringCode); - break; + return $sStringCode; } - return 'bug!'; + + return $sDefault; } @@ -285,6 +281,9 @@ class Dict /** * Clone a string in every language (if it exists in that language) + * + * @param $sSourceCode + * @param $sDestCode */ public static function CloneString($sSourceCode, $sDestCode) { diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index faefb0e25..dd3a73192 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -160,7 +160,7 @@ abstract class Expression public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) { return array( - 'widget' => AttributeDefinition::SEARCH_WIDGET_TYPE, + 'widget' => AttributeDefinition::SEARCH_WIDGET_TYPE_RAW, 'oql' => $this->Render($aArgs, $bRetrofitParams), 'label' => $this->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef), 'source' => get_class($this), @@ -315,27 +315,6 @@ class BinaryExpression extends Expression return $this->m_sOperator; } - // recursive rendering - public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) - { - $sOperator = Dict::S($this->GetOperator(), " {$this->GetOperator()} "); - $oLeftExpr = $this->GetLeftExpr(); - if ($oLeftExpr instanceof FieldExpression) - { - $oAttDef = $oLeftExpr->GetAttDef($oSearch->GetJoinedClasses()); - } - $oRightExpr = $this->GetRightExpr(); - if ($oRightExpr instanceof FieldExpression) - { - $oAttDef = $oRightExpr->GetAttDef($oSearch->GetJoinedClasses()); - } - - $sLeft = $oLeftExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef); - $sRight = $oRightExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef); - - return "({$sLeft}{$sOperator}{$sRight})"; - } - // recursive rendering public function Render(&$aArgs = null, $bRetrofitParams = false) { @@ -444,6 +423,67 @@ class BinaryExpression extends Expression $this->GetRightExpr()->RenameAlias($sOldName, $sNewName); } + // recursive rendering + public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) + { + $bReverseOperator = false; + $oLeftExpr = $this->GetLeftExpr(); + if ($oLeftExpr instanceof FieldExpression) + { + $oAttDef = $oLeftExpr->GetAttDef($oSearch->GetJoinedClasses()); + } + $oRightExpr = $this->GetRightExpr(); + if ($oRightExpr instanceof FieldExpression) + { + $oAttDef = $oRightExpr->GetAttDef($oSearch->GetJoinedClasses()); + $bReverseOperator = true; + } + + $sLeft = $oLeftExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef); + $sRight = $oRightExpr->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef); + + if ($bReverseOperator) + { + // switch left and right expressions so reverse the operator + // Note that the operation is the same so < becomes > and not >= + switch ($this->GetOperator()) + { + case '>': + $sOperator = '<'; + break; + case '<': + $sOperator = '>'; + break; + case '>=': + $sOperator = '<='; + break; + case '<=': + $sOperator = '>='; + break; + default: + $sOperator = $this->GetOperator(); + break; + } + $sOperator = $this->OperatorToNaturalLanguage($sOperator, $oAttDef); + + return "({$sRight}{$sOperator}{$sLeft})"; + } + + $sOperator = $this->GetOperator(); + $sOperator = $this->OperatorToNaturalLanguage($sOperator, $oAttDef); + + return "({$sLeft}{$sOperator}{$sRight})"; + } + + private function OperatorToNaturalLanguage($sOperator, $oAttDef) + { + if ($oAttDef instanceof AttributeDateTime) + { + return Dict::S('Expression:Operator:Date:'.$sOperator, " $sOperator "); + } + + return Dict::S('Expression:Operator:'.$sOperator, " $sOperator "); + } public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) { @@ -473,10 +513,10 @@ class BinaryExpression extends Expression $aCriteriaLeft = $oLeftExpr->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef); $aCriteriaRight = $oRightExpr->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef); - $aCriteria = array_merge($aCriteriaLeft, $aCriteriaRight); if ($bReverseOperator) { + $aCriteria = array_merge($aCriteriaRight, $aCriteriaLeft); // switch left and right expressions so reverse the operator // Note that the operation is the same so < becomes > and not >= switch ($this->GetOperator()) @@ -500,6 +540,7 @@ class BinaryExpression extends Expression } else { + $aCriteria = array_merge($aCriteriaLeft, $aCriteriaRight); $aCriteria['operator'] = $this->GetOperator(); } $aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams); @@ -598,7 +639,7 @@ class ScalarExpression extends UnaryExpression * @param AttributeDefinition $oAttDef * * @return array|string - * @throws Exception + * @throws \Exception */ public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) { @@ -748,7 +789,9 @@ class FieldExpression extends UnaryExpression * @param AttributeDefinition $oAttDef * * @return array|string - * @throws Exception + * @throws \CoreException + * @throws \DictExceptionMissingString + * @throws \Exception */ public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) { @@ -1458,6 +1501,60 @@ class FunctionExpression extends Expression } return $sRes; } + + public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) + { + if ($this->m_sVerb != 'DATE_SUB' && $this->m_sVerb != 'DATE_ADD' && $this->m_sVerb != 'NOW') + { + return $this->Render($aArgs, $bRetrofitParams); + } + $sOperation = ''; + switch ($this->m_sVerb) + { + case 'NOW': + $sOperation = ''; + break; + case 'DATE_SUB': + $sOperation = '-'; + break; + case 'DATE_ADD': + $sOperation = '+'; + break; + } + + foreach($this->m_aArgs as $oExpression) + { + $sOperation .= $oExpression->Display($oSearch, $aArgs, $bRetrofitParams, $oAttDef); + } + + return $sOperation; + } + + public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) + { + if ($this->m_sVerb != 'DATE_SUB' && $this->m_sVerb != 'DATE_ADD' && $this->m_sVerb != 'NOW') + { + return parent::GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef); + } + + $aCriteria = array('widget' => 'date_time'); + + foreach($this->m_aArgs as $oExpression) + { + $aCriteria = array_merge($oExpression->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef), $aCriteria); + } + + if ($this->m_sVerb == 'NOW') + { + $aCriteria['is_relative'] = true; + } + else + { + $aCriteria['verb'] = $this->m_sVerb; + } + + return $aCriteria; + } } class IntervalExpression extends Expression @@ -1544,6 +1641,19 @@ class IntervalExpression extends Expression { $this->m_oValue->RenameAlias($sOldName, $sNewName); } + + public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) + { + $aCriteria = $this->m_oValue->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef); + $aCriteria['unit'] = $this->m_sUnit; + + return $aCriteria; + } + + public function Display($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) + { + return $this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit; + } } class CharConcatExpression extends Expression diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 8c901c0f7..5f69811ca 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -311,6 +311,17 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:URP_AttributeGrant/Attribute:attcode+' => 'attribute code', )); +// +// Expression to Natural language +// +Dict::Add('EN US', 'English', 'English', array( + 'Expression:Unit:Short:DAY' => 'd', + 'Expression:Unit:Short:WEEK' => 'w', + 'Expression:Unit:Short:MONTH' => 'm', + 'Expression:Unit:Short:YEAR' => 'y', +)); + + // // String from the User Interface: menu, messages, buttons, etc... // diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index c440b27aa..afc3544f8 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -1219,4 +1219,17 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé 'UI:Search:Criteria:Title:String:StartsWith' => '%1$s commence par %2$s', 'UI:Search:Criteria:Title:String:EndsWith' => '%1$s fini par %2$s', 'UI:Search:Criteria:Title:Enum:In' => '%1$s parmi %2$s', -)); \ No newline at end of file +)); + + +// +// Expression to Natural language +// +Dict::Add('FR FR', 'French', 'Français', array( + 'Expression:Operator:AND' => 'ET', + 'Expression:Operator:OR' => 'OU', + 'Expression:Unit:Short:DAY' => 'j', + 'Expression:Unit:Short:WEEK' => 's', + 'Expression:Unit:Short:MONTH' => 'm', + 'Expression:Unit:Short:YEAR' => 'a', +)); diff --git a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php index 24ce40b57..73ff8ffb4 100644 --- a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php +++ b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php @@ -30,10 +30,17 @@ use AttributeDefinition; use Combodo\iTop\Application\Search\CriterionConversionAbstract; use DateInterval; use DateTime; +use Dict; class CriterionToSearchForm extends CriterionConversionAbstract { + /** + * @param array $aAndCriterionRaw + * @param array $aFieldsByCategory + * + * @return array + */ public static function Convert($aAndCriterionRaw, $aFieldsByCategory) { $aAllFields = array(); @@ -50,6 +57,8 @@ class CriterionToSearchForm extends CriterionConversionAbstract $aMappingOperatorToFunction = array( AttributeDefinition::SEARCH_WIDGET_TYPE_STRING => 'TextToSearchForm', AttributeDefinition::SEARCH_WIDGET_TYPE_ENUM => 'EnumToSearchForm', + AttributeDefinition::SEARCH_WIDGET_TYPE_DATE => 'DateToSearchForm', + AttributeDefinition::SEARCH_WIDGET_TYPE_DATE_TIME => 'DateTimeToSearchForm', ); foreach($aAndCriterionRaw as $aCriteria) @@ -181,6 +190,7 @@ class CriterionToSearchForm extends CriterionConversionAbstract $aCurrCriterion['values'][] = array('value' => $sLastDate, 'label' => $sLastDate); $aCurrCriterion['oql'] = "({$aPrevCriterion['oql']} AND {$aCurrCriterion['oql']})"; + $aCurrCriterion['label'] = $aPrevCriterion['label'].' '.Dict::S('Expression:Operator:AND', 'AND').' '.$aCurrCriterion['label']; $aMergedCriterion[] = $aCurrCriterion; @@ -236,6 +246,7 @@ class CriterionToSearchForm extends CriterionConversionAbstract $aCurrCriterion['values'][] = array('value' => $sLastDate, 'label' => $sLastDate); $aCurrCriterion['oql'] = "({$aPrevCriterion['oql']} AND {$aCurrCriterion['oql']})"; + $aCurrCriterion['label'] = $aPrevCriterion['label'].' '.Dict::S('Expression:Operator:AND', 'AND').' '.$aCurrCriterion['label']; $aMergedCriterion[] = $aCurrCriterion; @@ -323,4 +334,44 @@ class CriterionToSearchForm extends CriterionConversionAbstract return $aCriteria; } + + protected static function DateToSearchForm($aCriteria, $aFields) + { + return DateTimeToSearchForm($aCriteria, $aFields); + } + + protected static function DateTimeToSearchForm($aCriteria, $aFields) + { + if (!array_key_exists('is_relative', $aCriteria) || !$aCriteria['is_relative']) + { + return $aCriteria; + } + + if (isset($aCriteria['values'][0]['value'])) + { + $sLabel = $aCriteria['values'][0]['value']; + if (isset($aCriteria['verb'])) + { + switch ($aCriteria['verb']) + { + case 'DATE_SUB': + $sLabel = '-'.$sLabel; + break; + case 'DATE_ADD': + $sLabel = '+'.$sLabel; + break; + } + } + if (isset($aCriteria['unit'])) + { + $sLabel .= Dict::S('Expression:Unit:Short:'.$aCriteria['unit'], $aCriteria['unit']); + } + $aCriteria['values'][0]['label'] = $sLabel; + } + + // Temporary until the JS widget support relative dates + $aCriteria['widget'] = AttributeDefinition::SEARCH_WIDGET_TYPE_RAW; + + return $aCriteria; + } } \ No newline at end of file