From 9974457971fdd6713cd003388fff5c06bf6de62e Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Wed, 28 Jul 2010 15:18:52 +0000 Subject: [PATCH] Enhancing the search (Trac #147): now allows to pass some "magic patterns" when doing a standard search without any operator. Specially useful for searching on ranges of dates/datetimes SVN:trunk[638] --- application/cmdbabstract.class.inc.php | 8 +- application/user.preferences.class.inc.php | 2 +- core/attributedef.class.inc.php | 97 ++++++++++++++++++++++ core/cmdbchangeop.class.inc.php | 6 +- core/dbobject.class.php | 2 +- core/dbobjectsearch.class.php | 14 +++- pages/ajax.csvimport.php | 2 +- pages/ajax.render.php | 2 +- pages/audit.php | 6 +- setup/xmldataloader.class.inc.php | 2 +- 10 files changed, 124 insertions(+), 17 deletions(-) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index d9cc79603..7dcab390c 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -112,7 +112,7 @@ abstract class cmdbAbstractObject extends CMDBObject // action menu $oSingletonFilter = new DBObjectSearch(get_class($this)); - $oSingletonFilter->AddCondition('id', array($this->GetKey())); + $oSingletonFilter->AddCondition('id', $this->GetKey(), '='); $oBlock = new MenuBlock($oSingletonFilter, 'popup', false); $oBlock->Display($oPage, -1); $oPage->add("

GetIcon()."\" style=\"margin-right:10px;margin-top: -16px;vertical-align:middle;\">\n"); @@ -124,8 +124,8 @@ abstract class cmdbAbstractObject extends CMDBObject { // history block (with as a tab) $oHistoryFilter = new DBObjectSearch('CMDBChangeOp'); - $oHistoryFilter->AddCondition('objkey', $this->GetKey()); - $oHistoryFilter->AddCondition('objclass', get_class($this)); + $oHistoryFilter->AddCondition('objkey', $this->GetKey(), '='); + $oHistoryFilter->AddCondition('objclass', get_class($this), '='); $oBlock = new HistoryBlock($oHistoryFilter, 'table', false); $oBlock->Display($oPage, -1); } @@ -163,7 +163,7 @@ abstract class cmdbAbstractObject extends CMDBObject $oPage->p(" ".$oAttDef->GetDescription()); $oFilter = new DBObjectSearch($sTargetClass); - $oFilter->AddCondition($oAttDef->GetExtKeyToMe(), $this->GetKey()); + $oFilter->AddCondition($oAttDef->GetExtKeyToMe(), $this->GetKey(),'='); $oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock->Display($oPage, 0); diff --git a/application/user.preferences.class.inc.php b/application/user.preferences.class.inc.php index a63472c57..cc7de9975 100644 --- a/application/user.preferences.class.inc.php +++ b/application/user.preferences.class.inc.php @@ -125,7 +125,7 @@ class appUserPreferences extends DBObject { if (self::$oUserPrefs != null) return; $oSearch = new DBObjectSearch('appUserPreferences'); - $oSearch->AddCondition('userid', UserRights::GetUser()); + $oSearch->AddCondition('userid', UserRights::GetUser(), '='); $oSet = new DBObjectSet($oSearch); $oObj = $oSet->Fetch(); if ($oObj == null) diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index ed15f836f..a1ba2adf6 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -260,6 +260,35 @@ abstract class AttributeDefinition if (!$oValSetDef) return null; return $oValSetDef->GetValues($aArgs, $sBeginsWith); } + + /** + * Parses a string to find some smart search patterns and build the corresponding search/OQL condition + * Each derived class is reponsible for defining and processing their own smart patterns, the base class + * does nothing special, and just calls the default (loose) operator + * @param string $sSearchText The search string to analyze for smart patterns + * @param FieldExpression The FieldExpression representing the atttribute code in this OQL query + * @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) + { + $sParamName = $oField->GetParent().'_'.$oField->GetName(); + $oRightExpr = new VariableExpression($sParamName); + $sOperator = $this->GetBasicFilterLooseOperator(); + switch ($sOperator) + { + case 'Contains': + $aParams[$sParamName] = "%$sSearchText%"; + $sSQLOperator = 'LIKE'; + break; + + default: + $sSQLOperator = $sOperator; + $aParams[$sParamName] = $sSearchText; + } + $oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr); + return $oNewCondition; + } } /** @@ -1189,6 +1218,74 @@ class AttributeDateTime extends AttributeDBField $sEscaped = str_replace($sFrom, $sTo, (string)$sValue); return '"'.$sEscaped.'"'; } + + /** + * Parses a string to find some smart search patterns and build the corresponding search/OQL condition + * Each derived class is reponsible for defining and processing their own smart patterns, the base class + * does nothing special, and just calls the default (loose) operator + * @param string $sSearchText The search string to analyze for smart patterns + * @param FieldExpression The FieldExpression representing the atttribute code in this OQL query + * @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) + { + // Possible smart patterns + $aPatterns = array( + 'between' => array('pattern' => '/^\[(.*),(.*)\]$/', 'operator' => 'n/a'), + 'greater than or equal' => array('pattern' => '/^>=(.*)$/', 'operator' => '>='), + 'greater than' => array('pattern' => '/^>(.*)$/', 'operator' => '>'), + 'less than or equal' => array('pattern' => '/^<=(.*)$/', 'operator' => '<='), + 'less than' => array('pattern' => '/^<(.*)$/', 'operator' => '<'), + ); + + $sPatternFound = ''; + $aMatches = array(); + foreach($aPatterns as $sPatName => $sPattern) + { + if (preg_match($sPattern['pattern'], $sSearchText, $aMatches)) + { + $sPatternFound = $sPatName; + break; + } + } + + switch($sPatternFound) + { + case 'between': + + $sParamName1 = $oField->GetParent().'_'.$oField->GetName().'_1'; + $oRightExpr = new VariableExpression($sParamName1); + $aParams[$sParamName1] = $aMatches[1]; + $oCondition1 = new BinaryExpression($oField, '>=', $oRightExpr); + + $sParamName2 = $oField->GetParent().'_'.$oField->GetName().'_2'; + $oRightExpr = new VariableExpression($sParamName2); + $sOperator = $this->GetBasicFilterLooseOperator(); + $aParams[$sParamName2] = $aMatches[2]; + $oCondition2 = new BinaryExpression($oField, '<=', $oRightExpr); + + $oNewCondition = new BinaryExpression($oCondition1, 'AND', $oCondition2); + break; + + case 'greater than': + case 'greater than or equal': + case 'less than': + case 'less than or equal': + $sSQLOperator = $aPatterns[$sPatternFound]['operator']; + $sParamName = $oField->GetParent().'_'.$oField->GetName(); + $oRightExpr = new VariableExpression($sParamName); + $aParams[$sParamName] = $aMatches[1]; + $oNewCondition = new BinaryExpression($oField, $sSQLOperator, $oRightExpr); + + break; + + default: + $oNewCondition = parent::GetSmartConditionExpression($sSearchText, $oField, &$aParams); + } + + return $oNewCondition; + } } /** diff --git a/core/cmdbchangeop.class.inc.php b/core/cmdbchangeop.class.inc.php index 3a0d53216..ab520fe92 100644 --- a/core/cmdbchangeop.class.inc.php +++ b/core/cmdbchangeop.class.inc.php @@ -212,7 +212,7 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute $oTargetObjectClass = $this->Get('objclass'); $oTargetObjectKey = $this->Get('objkey'); $oTargetSearch = new DBObjectSearch($oTargetObjectClass); - $oTargetSearch->AddCondition('id', $oTargetObjectKey); + $oTargetSearch->AddCondition('id', $oTargetObjectKey, '='); $oMonoObjectSet = new DBObjectSet($oTargetSearch); if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) @@ -301,7 +301,7 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute $oTargetObjectClass = $this->Get('objclass'); $oTargetObjectKey = $this->Get('objkey'); $oTargetSearch = new DBObjectSearch($oTargetObjectClass); - $oTargetSearch->AddCondition('id', $oTargetObjectKey); + $oTargetSearch->AddCondition('id', $oTargetObjectKey, '='); $oMonoObjectSet = new DBObjectSet($oTargetSearch); if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) @@ -360,7 +360,7 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute $oTargetObjectClass = $this->Get('objclass'); $oTargetObjectKey = $this->Get('objkey'); $oTargetSearch = new DBObjectSearch($oTargetObjectClass); - $oTargetSearch->AddCondition('id', $oTargetObjectKey); + $oTargetSearch->AddCondition('id', $oTargetObjectKey, '='); $oMonoObjectSet = new DBObjectSet($oTargetSearch); if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) diff --git a/core/dbobject.class.php b/core/dbobject.class.php index a349e8815..aeae90620 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1101,7 +1101,7 @@ abstract class DBObject if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) continue; $oSearch = new DBObjectSearch($sRemoteClass); - $oSearch->AddCondition($sExtKeyAttCode, $this->GetKey()); + $oSearch->AddCondition($sExtKeyAttCode, $this->GetKey(), '='); $oSet = new CMDBObjectSet($oSearch); if ($oSet->Count() > 0) { diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index 190a3a309..9ea745129 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -224,15 +224,25 @@ class DBObjectSearch MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass())); $oFilterDef = MetaModel::GetClassFilterDef($this->GetClass(), $sFilterCode); + $oField = new FieldExpression($sFilterCode, $this->GetClassAlias()); if (empty($sOpCode)) { - $sOpCode = $oFilterDef->GetLooseOperator(); + if ($sFilterCode == 'id') + { + $sOpCode = '='; + } + else + { + $oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode); + $oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams); + $this->AddConditionExpression($oNewCondition); + return; + } } MyHelpers::CheckKeyInArray('operator', $sOpCode, $oFilterDef->GetOperators()); // Preserve backward compatibility - quick n'dirty way to change that API semantic // - $oField = new FieldExpression($sFilterCode, $this->GetClassAlias()); switch($sOpCode) { case 'SameDay': diff --git a/pages/ajax.csvimport.php b/pages/ajax.csvimport.php index 5a79dfcf7..d3e06168d 100644 --- a/pages/ajax.csvimport.php +++ b/pages/ajax.csvimport.php @@ -330,7 +330,7 @@ EOF case 'get_csv_template': $sClassName = utils::ReadParam('class_name'); $oSearch = new DBObjectSearch($sClassName); - $oSearch->AddCondition('id', 0); // Make sure we create an empty set + $oSearch->AddCondition('id', 0, '='); // Make sure we create an empty set $oSet = new CMDBObjectSet($oSearch); $sResult = cmdbAbstractObject::GetSetAsCSV($oSet); //$aCSV = explode("\n", $sCSV); diff --git a/pages/ajax.render.php b/pages/ajax.render.php index da7dfefe0..7c5fbceb4 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -280,7 +280,7 @@ switch($operation) $iCount = 0; $oFilter = $oContext->NewFilter($sClass); $oFilter->AddCondition($sAttCode, $sName, 'Begins with'); - //$oFilter->AddCondition('org_id', $sOrg); + //$oFilter->AddCondition('org_id', $sOrg, '='); $oSet = new CMDBObjectSet($oFilter, array($sAttCode => true)); while( ($iCount < $iMaxCount) && ($oObj = $oSet->fetch()) ) { diff --git a/pages/audit.php b/pages/audit.php index a7fd54ff0..d3c282fee 100644 --- a/pages/audit.php +++ b/pages/audit.php @@ -92,7 +92,7 @@ switch($operation) $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); if (!empty($currentOrganization)) { - $oDefinitionFilter->AddCondition('org_id', $currentOrganization); + $oDefinitionFilter->AddCondition('org_id', $currentOrganization, '='); } $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); $oErrorObjectSet = GetRuleResultSet($iRuleIndex, $oDefinitionFilter); @@ -124,14 +124,14 @@ switch($operation) { if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id')) { - $oDefinitionFilter->AddCondition('org_id', $currentOrganization); + $oDefinitionFilter->AddCondition('org_id', $currentOrganization, '='); } } $aResults = array(); $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); $iCount = $oDefinitionSet->Count(); $oRulesFilter = new CMDBSearchFilter('AuditRule'); - $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey()); + $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '='); $oRulesSet = new DBObjectSet($oRulesFilter); while($oAuditRule = $oRulesSet->fetch() ) { diff --git a/setup/xmldataloader.class.inc.php b/setup/xmldataloader.class.inc.php index f849f3125..035c38a1a 100644 --- a/setup/xmldataloader.class.inc.php +++ b/setup/xmldataloader.class.inc.php @@ -252,7 +252,7 @@ class XMLDataLoader { if ($oTargetObj->Get($sAttCode) != '') { - $oSearch->AddCondition($sAttCode, $oTargetObj->Get($sAttCode)); + $oSearch->AddCondition($sAttCode, $oTargetObj->Get($sAttCode), '='); $iConditionsCount++; } }