Advanced Search: Better support of dates in expressions

SVN:b1162[5464]
This commit is contained in:
Eric Espié
2018-03-20 10:38:52 +00:00
parent d04fb645ec
commit e33596960a
5 changed files with 230 additions and 46 deletions

View File

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

View File

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

View File

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

View File

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

View File

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