diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index 8d49afdfe..deae190c4 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -1024,7 +1024,14 @@ class FieldExpression extends UnaryExpression */ public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null) { - $oAttDef = $this->GetAttDef($oSearch->GetJoinedClasses()); + if (method_exists($oSearch, 'GetJoinedClasses')) + { + $oAttDef = $this->GetAttDef($oSearch->GetJoinedClasses()); + } + else + { + $oAttDef = $this->GetAttDef($oSearch->GetSelectedClasses()); + } if (!is_null($oAttDef)) { $sSearchType = $oAttDef->GetSearchType(); diff --git a/sources/application/search/criterionconversion/criteriontooql.class.inc.php b/sources/application/search/criterionconversion/criteriontooql.class.inc.php index 27a8292b3..2da91a4fa 100644 --- a/sources/application/search/criterionconversion/criteriontooql.class.inc.php +++ b/sources/application/search/criterionconversion/criteriontooql.class.inc.php @@ -156,6 +156,8 @@ class CriterionToOQL extends CriterionConversionAbstract { case AttributeDefinition::SEARCH_WIDGET_TYPE_NUMERIC: case AttributeDefinition::SEARCH_WIDGET_TYPE_EXTERNAL_FIELD: + case AttributeDefinition::SEARCH_WIDGET_TYPE_DATE: + case AttributeDefinition::SEARCH_WIDGET_TYPE_DATE_TIME: return "ISNULL({$sRef})"; } } @@ -165,6 +167,18 @@ class CriterionToOQL extends CriterionConversionAbstract protected static function NotEmptyToOql($sRef, $aCriteria) { + if (isset($aCriteria['widget'])) + { + switch ($aCriteria['widget']) + { + case AttributeDefinition::SEARCH_WIDGET_TYPE_NUMERIC: + case AttributeDefinition::SEARCH_WIDGET_TYPE_EXTERNAL_FIELD: + case AttributeDefinition::SEARCH_WIDGET_TYPE_DATE: + case AttributeDefinition::SEARCH_WIDGET_TYPE_DATE_TIME: + return "ISNULL({$sRef}) = 0"; + } + } + return "({$sRef} != '')"; } diff --git a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php index 6daa18b55..59027f63f 100644 --- a/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php +++ b/sources/application/search/criterionconversion/criteriontosearchform.class.inc.php @@ -22,6 +22,7 @@ /** * Convert structures from OQL expressions into structure for the search form */ + namespace Combodo\iTop\Application\Search\CriterionConversion; @@ -123,13 +124,17 @@ class CriterionToSearchForm extends CriterionConversionAbstract } // Regroup criterion by variable name (no ref first) - usort($aAndCriterion, function ($a, $b) { + usort($aAndCriterion, function ($a, $b) + { if (array_key_exists('ref', $a) || array_key_exists('ref', $b)) { if (array_key_exists('ref', $a) && array_key_exists('ref', $b)) { $iRefCmp = strcmp($a['ref'], $b['ref']); - if ($iRefCmp != 0) return $iRefCmp; + if ($iRefCmp != 0) + { + return $iRefCmp; + } return strcmp($a['operator'], $b['operator']); } @@ -190,15 +195,22 @@ class CriterionToSearchForm extends CriterionConversionAbstract } // Sort by label criterion by variable name (no ref first) - usort($aMergedCriterion, function ($a, $b) { + usort($aMergedCriterion, function ($a, $b) + { if (($a['widget'] === AttributeDefinition::SEARCH_WIDGET_TYPE_RAW) || ($b['widget'] === AttributeDefinition::SEARCH_WIDGET_TYPE_RAW)) { if (($a['widget'] === AttributeDefinition::SEARCH_WIDGET_TYPE_RAW) && ($b['widget'] === AttributeDefinition::SEARCH_WIDGET_TYPE_RAW)) { - if (!isset($a['label'])) return -1; - if (!isset($b['label'])) return 1; + if (!isset($a['label'])) + { + return -1; + } + if (!isset($b['label'])) + { + return 1; + } return strcmp($a['label'], $b['label']); } if ($a['widget'] === AttributeDefinition::SEARCH_WIDGET_TYPE_RAW) @@ -209,8 +221,14 @@ class CriterionToSearchForm extends CriterionConversionAbstract return 1; } - if (!isset($a['label'])) return -1; - if (!isset($b['label'])) return 1; + if (!isset($a['label'])) + { + return -1; + } + if (!isset($b['label'])) + { + return 1; + } return strcmp($a['label'], $b['label']); }); @@ -440,22 +458,22 @@ class CriterionToSearchForm extends CriterionConversionAbstract case ('' == $sValue and ($sOperator == 'LIKE')): $aCriteria['operator'] = CriterionConversionAbstract::OP_EMPTY; break; - case ('' == $sValue and $sOperator == '!='): + case (($sOperator == '=') && isset($aCriteria['has_undefined']) && ($sValue == '0')): $aCriteria['operator'] = CriterionConversionAbstract::OP_NOT_EMPTY; break; - case ($sOperator == 'LIKE' && $bStartWithPercent && $bEndWithPercent): + case (($sOperator == 'LIKE') && $bStartWithPercent && $bEndWithPercent): $aCriteria['operator'] = CriterionConversionAbstract::OP_CONTAINS; $sValue = substr($sValue, 1, -1); $aCriteria['values'][0]['value'] = $sValue; $aCriteria['values'][0]['label'] = "$sValue"; break; - case ($sOperator == 'LIKE' && $bStartWithPercent): + case (($sOperator == 'LIKE') && $bStartWithPercent): $aCriteria['operator'] = CriterionConversionAbstract::OP_ENDS_WITH; $sValue = substr($sValue, 1); $aCriteria['values'][0]['value'] = $sValue; $aCriteria['values'][0]['label'] = "$sValue"; break; - case ($sOperator == 'LIKE' && $bEndWithPercent): + case (($sOperator == 'LIKE') && $bEndWithPercent): $aCriteria['operator'] = CriterionConversionAbstract::OP_STARTS_WITH; $sValue = substr($sValue, 0, -1); $aCriteria['values'][0]['value'] = $sValue; @@ -471,30 +489,47 @@ class CriterionToSearchForm extends CriterionConversionAbstract if (!array_key_exists('is_relative', $aCriteria) || !$aCriteria['is_relative']) { // Convert '=' in 'between' - if (isset($aCriteria['operator']) && ($aCriteria['operator'] === '=')) + if (isset($aCriteria['operator'])) { - $aCriteria['operator'] = CriterionConversionAbstract::OP_BETWEEN_DATES; - $sWidget = $aCriteria['widget']; - if ($sWidget == AttributeDefinition::SEARCH_WIDGET_TYPE_DATE) + switch ($aCriteria['operator']) { - $aCriteria['values'][1] = $aCriteria['values'][0]; - } - else - { - $sDate = $aCriteria['values'][0]['value']; - $oDate = new DateTime($sDate); + case '=': + if (isset($aCriteria['has_undefined']) && (isset($aCriteria['values'][0]['value']) && ($aCriteria['values'][0]['value'] == 0))) + { + // Special case for NOT EMPTY + $aCriteria['operator'] = CriterionConversionAbstract::OP_NOT_EMPTY; + } + else + { + $aCriteria['operator'] = CriterionConversionAbstract::OP_BETWEEN_DATES; + $sWidget = $aCriteria['widget']; + if ($sWidget == AttributeDefinition::SEARCH_WIDGET_TYPE_DATE) + { + $aCriteria['values'][1] = $aCriteria['values'][0]; + } + else + { + $sDate = $aCriteria['values'][0]['value']; + $oDate = new DateTime($sDate); - $sFirstDateValue = $oDate->format(AttributeDateTime::GetSQLFormat()); - $sFirstDateLabel = AttributeDateTime::GetFormat()->Format($sFirstDateValue); - $aCriteria['values'][0] = array('value' => $sFirstDateValue, 'label' => "$sFirstDateLabel"); + $sFirstDateValue = $oDate->format(AttributeDateTime::GetSQLFormat()); + $sFirstDateLabel = AttributeDateTime::GetFormat()->Format($sFirstDateValue); + $aCriteria['values'][0] = array('value' => $sFirstDateValue, 'label' => "$sFirstDateLabel"); - $oDate->add(DateInterval::createFromDateString('1 day')); - $oDate->sub(DateInterval::createFromDateString('1 second')); + $oDate->add(DateInterval::createFromDateString('1 day')); + $oDate->sub(DateInterval::createFromDateString('1 second')); - $sLastDateValue = $oDate->format(AttributeDateTime::GetSQLFormat()); - $sLastDateLabel = AttributeDateTime::GetFormat()->Format($sLastDateValue); - $aCriteria['values'][1] = array('value' => $sLastDateValue, 'label' => "$sLastDateLabel"); + $sLastDateValue = $oDate->format(AttributeDateTime::GetSQLFormat()); + $sLastDateLabel = AttributeDateTime::GetFormat()->Format($sLastDateValue); + $aCriteria['values'][1] = array('value' => $sLastDateValue, 'label' => "$sLastDateLabel"); + } + } + break; + + case 'ISNULL': + $aCriteria['operator'] = CriterionConversionAbstract::OP_EMPTY; + break; } } @@ -531,9 +566,19 @@ class CriterionToSearchForm extends CriterionConversionAbstract protected static function NumericToSearchForm($aCriteria, $aFields) { - if ($aCriteria['operator'] == 'ISNULL') + switch ($aCriteria['operator']) { - $aCriteria['operator'] = CriterionConversionAbstract::OP_EMPTY; + case 'ISNULL': + $aCriteria['operator'] = CriterionConversionAbstract::OP_EMPTY; + break; + + case '=': + if (isset($aCriteria['has_undefined']) && (isset($aCriteria['values'][0]['value']) && ($aCriteria['values'][0]['value'] == 0))) + { + // Special case for NOT EMPTY + $aCriteria['operator'] = CriterionConversionAbstract::OP_NOT_EMPTY; + } + break; } return $aCriteria; diff --git a/sources/application/search/searchform.class.inc.php b/sources/application/search/searchform.class.inc.php index 9e99fd6b0..34f947905 100644 --- a/sources/application/search/searchform.class.inc.php +++ b/sources/application/search/searchform.class.inc.php @@ -33,6 +33,7 @@ use DBObjectSet; use Dict; use Exception; use Expression; +use FieldExpression; use IssueLog; use MetaModel; use TrueExpression; @@ -436,6 +437,7 @@ class SearchForm public function GetCriterion($oSearch, $aFields, $aArgs = array(), $bIsRemovable = true) { $aOrCriterion = array(); + $bIsEmptyExpression = true; if (method_exists($oSearch, 'GetCriteria')) { @@ -450,7 +452,6 @@ class SearchForm } $aORExpressions = Expression::Split($oExpression, 'OR'); - $bIsEmptyExpression = true; foreach($aORExpressions as $oORSubExpr) { $aAndCriterion = array(); @@ -467,12 +468,12 @@ class SearchForm $aAndCriterion = CriterionToSearchForm::Convert($aAndCriterion, $aFields, $oSearch->GetJoinedClasses(), $bIsRemovable); $aOrCriterion[] = array('and' => $aAndCriterion); } + } - if ($bIsEmptyExpression) - { - // Add default criterion - $aOrCriterion = $this->GetDefaultCriterion($oSearch); - } + if ($bIsEmptyExpression) + { + // Add default criterion + $aOrCriterion = $this->GetDefaultCriterion($oSearch); } return array('or' => $aOrCriterion); @@ -597,8 +598,12 @@ class SearchForm $sAlias = $oSearch->GetClassAlias(); foreach($aList as $sAttCode) { - $oFieldExpression = new \FieldExpression($sAttCode, $sAlias); - $aAndCriterion[] = $oFieldExpression->GetCriterion($oSearch); + $oFieldExpression = new FieldExpression($sAttCode, $sAlias); + $aCriterion = $oFieldExpression->GetCriterion($oSearch); + if (isset($aCriterion['widget']) && ($aCriterion['widget'] != AttributeDefinition::SEARCH_WIDGET_TYPE_RAW)) + { + $aAndCriterion[] = $aCriterion; + } } // Overwrite with default criterion $aOrCriterion = array(array('and' => $aAndCriterion));