mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 18:48:51 +02:00
Advanced Search: Better support of dates in expressions
SVN:b1162[5464]
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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...
|
||||
//
|
||||
|
||||
@@ -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',
|
||||
));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user