mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-25 11:38:44 +02:00
N°3238 - Fix multi-words search in FilterBrick and ManageBrick
This commit is contained in:
@@ -624,14 +624,29 @@ class DBObjectSearch extends DBSearch
|
||||
public function AddCondition_FullText($sNeedle)
|
||||
{
|
||||
// Transform the full text condition into additional condition expression
|
||||
$aFullTextFields = array();
|
||||
foreach (MetaModel::ListAttributeDefs($this->GetClass()) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aAttCodes = [];
|
||||
foreach (MetaModel::ListAttributeDefs($this->GetClass()) as $sAttCode => $oAttDef) {
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
if ($oAttDef->IsExternalKey()) continue;
|
||||
if (!$oAttDef->IsSearchable()) continue;
|
||||
$aAttCodes[] = $sAttCode;
|
||||
}
|
||||
$this->AddCondition_FullTextOnAttributes($aAttCodes, $sNeedle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aAttCodes array of attCodes to search into
|
||||
* @param string $sNeedle one word to be searched
|
||||
*
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function AddCondition_FullTextOnAttributes(array $aAttCodes, $sNeedle)
|
||||
{
|
||||
$aFullTextFields = [];
|
||||
foreach ($aAttCodes as $sAttCode) {
|
||||
$aFullTextFields[] = new FieldExpression($sAttCode, $this->GetClassAlias());
|
||||
}
|
||||
|
||||
$oTextFields = new CharConcatWSExpression(' ', $aFullTextFields);
|
||||
|
||||
$sQueryParam = str_replace('.', '', uniqid('needle_', true));
|
||||
|
||||
@@ -404,6 +404,8 @@ abstract class DBSearch
|
||||
*/
|
||||
abstract public function AddCondition_FullText($sFullText);
|
||||
|
||||
abstract public function AddCondition_FullTextOnAttributes(array $aAttCodes, $sNeedle);
|
||||
|
||||
/**
|
||||
* Perform a join, the remote class being matched by the mean of its primary key
|
||||
*
|
||||
|
||||
@@ -376,6 +376,14 @@ class DBUnionSearch extends DBSearch
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_FullTextOnAttributes(array $aAttCodes, $sNeedle)
|
||||
{
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$oSearch->AddCondition_FullTextOnAttributes($aAttCodes, $sNeedle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DBObjectSearch $oFilter
|
||||
* @param $sExtKeyAttCode
|
||||
|
||||
@@ -84,8 +84,9 @@ class BrowseBrickController extends BrickController
|
||||
$sDataLoading = ($sDataLoading !== null) ? $sDataLoading : $oRequestManipulator->ReadParam('sDataLoading',
|
||||
$oBrick->GetDataLoading());
|
||||
// Getting search value
|
||||
$sSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
|
||||
if (!empty($sSearchValue))
|
||||
$sRawSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
|
||||
$sSearchValue = html_entity_decode($sRawSearchValue);
|
||||
if (strlen($sSearchValue) > 0)
|
||||
{
|
||||
$sDataLoading = AbstractBrick::ENUM_DATA_LOADING_LAZY;
|
||||
}
|
||||
@@ -167,13 +168,16 @@ class BrowseBrickController extends BrickController
|
||||
|
||||
// Adding search clause
|
||||
// Note : For know the search is naive and looks only for the exact match. It doesn't search for words separately
|
||||
if (!empty($sSearchValue))
|
||||
if (strlen($sSearchValue) > 0)
|
||||
{
|
||||
// - Cleaning the search value by exploding and trimming spaces
|
||||
$aSearchValues = explode(' ', $sSearchValue);
|
||||
array_walk($aSearchValues, function (&$sSearchValue /*, $sKey*/) {
|
||||
trim($sSearchValue);
|
||||
});
|
||||
$aExplodedSearchValues = explode(' ', $sSearchValue);
|
||||
$aSearchValues = [];
|
||||
foreach ($aExplodedSearchValues as $sValue) {
|
||||
if (strlen($sValue) > 0) {
|
||||
$aSearchValues[] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
// - Retrieving fields to search
|
||||
$aSearchFields = array($aLevelsProperties[$aLevelsPropertiesKeys[$i]]['name_att']);
|
||||
@@ -257,7 +261,7 @@ class BrowseBrickController extends BrickController
|
||||
{
|
||||
$aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->SetSelectedClasses($aLevelsClasses);
|
||||
|
||||
if (!empty($sSearchValue))
|
||||
if (strlen($sSearchValue) > 0)
|
||||
{
|
||||
// Note : This could be way more simpler if we had a SetInternalParam($sParam, $value) verb
|
||||
$aQueryParams = $aLevelsProperties[$aLevelsPropertiesKeys[$i]]['search']->GetInternalParams();
|
||||
@@ -452,7 +456,7 @@ class BrowseBrickController extends BrickController
|
||||
'sBrickId' => $sBrickId,
|
||||
'sBrowseMode' => $sBrowseMode,
|
||||
'aBrowseButtons' => $aBrowseButtons,
|
||||
'sSearchValue' => $sSearchValue,
|
||||
'sSearchValue' => $sRawSearchValue,
|
||||
'sDataLoading' => $sDataLoading,
|
||||
'aItems' => json_encode($aItems),
|
||||
'iItemsCount' => count($aItems),
|
||||
|
||||
@@ -894,64 +894,50 @@ class ManageBrickController extends BrickController
|
||||
$oRequestManipulator = $this->get('request_manipulator');
|
||||
|
||||
// Getting search value
|
||||
$sSearchValue = $oRequestManipulator->ReadParam('sSearchValue', '');
|
||||
$sRawSearchValue = trim($oRequestManipulator->ReadParam('sSearchValue', ''));
|
||||
$sSearchValue = html_entity_decode($sRawSearchValue);
|
||||
|
||||
// - Adding search clause if necessary
|
||||
// Note : This is a very naive search at the moment
|
||||
if (!empty($sSearchValue))
|
||||
{
|
||||
if (strlen($sSearchValue) > 0) {
|
||||
// Putting only valid attributes as one can define attributes of leaf classes in the brick definition (<fields>), but at this stage we are working on the abstract class.
|
||||
// Note: This won't fix everything as the search will not be looking in all fields.
|
||||
$aSearchListItems = array();
|
||||
foreach ($aColumnsAttrs as $sColumnAttr)
|
||||
{
|
||||
// Skip invalid attcodes
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sColumnAttr))
|
||||
{
|
||||
$aSearchListItems = [];
|
||||
foreach ($aColumnsAttrs as $sColumnAttr) {
|
||||
// Skip invalid attCodes
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sColumnAttr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For external key, force search on the friendlyname instead of the ID.
|
||||
// This should be addressed more globally with the bigger issue, see N°1970
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sColumnAttr);
|
||||
if($oAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeExternalKey) {
|
||||
$sColumnAttr .= '_friendlyname';
|
||||
}
|
||||
|
||||
$aSearchListItems[] = $sColumnAttr;
|
||||
}
|
||||
|
||||
$oFullBinExpr = null;
|
||||
foreach ($aSearchListItems as $sSearchItemAttr)
|
||||
{
|
||||
$oBinExpr = new BinaryExpression(new FieldExpression($sSearchItemAttr, $oQuery->GetClassAlias()),
|
||||
'LIKE', new VariableExpression('search_value'));
|
||||
// At each iteration we build the complete expression for the search like ( (field1 LIKE %search%) OR (field2 LIKE %search%) OR (field3 LIKE %search%) ...)
|
||||
if (is_null($oFullBinExpr))
|
||||
{
|
||||
$oFullBinExpr = $oBinExpr;
|
||||
if (preg_match('/^"(.*)"$/', $sSearchValue, $aMatches)) {
|
||||
// The text is surrounded by double-quotes, remove the quotes and treat it as one single expression
|
||||
$aSearchNeedles = [$aMatches[1]];
|
||||
} else {
|
||||
// Split the text on the blanks and treat this as a search for <word1> AND <word2> AND <word3>
|
||||
$aExplodedSearchNeedles = explode(' ', $sSearchValue);
|
||||
$aSearchNeedles = [];
|
||||
foreach ($aExplodedSearchNeedles as $sValue) {
|
||||
if (strlen($sValue) > 0) {
|
||||
$aSearchNeedles[] = $sValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFullBinExpr = new BinaryExpression($oFullBinExpr, 'OR', $oBinExpr);
|
||||
}
|
||||
}
|
||||
foreach ($aSearchNeedles as $sSearchWord) {
|
||||
$oQuery->AddCondition_FullTextOnAttributes($aSearchListItems, $sSearchWord);
|
||||
}
|
||||
}
|
||||
|
||||
// Then add the complete expression to the query
|
||||
if (!is_null($oFullBinExpr))
|
||||
{
|
||||
// - Adding expression to the query
|
||||
$oQuery->AddConditionExpression($oFullBinExpr);
|
||||
// - Setting expression parameters
|
||||
// Note : This could be way more simpler if we had a SetInternalParam($sParam, $value) verb
|
||||
$aQueryParams = $oQuery->GetInternalParams();
|
||||
$aQueryParams['search_value'] = '%'.$sSearchValue.'%';
|
||||
$oQuery->SetInternalParams($aQueryParams);
|
||||
}
|
||||
}
|
||||
|
||||
$aData['sSearchValue'] = $sSearchValue;
|
||||
$aData['sSearchValue'] = $sRawSearchValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -576,7 +576,13 @@ try
|
||||
else
|
||||
{
|
||||
// Split the text on the blanks and treat this as a search for <word1> AND <word2> AND <word3>
|
||||
$aFullTextNeedles = explode(' ', $sFullText);
|
||||
$aExplodedFullTextNeedles = explode(' ', $sFullText);
|
||||
$aFullTextNeedles = [];
|
||||
foreach ($aExplodedFullTextNeedles as $sValue) {
|
||||
if (strlen($sValue) > 0) {
|
||||
$aFullTextNeedles[] = $sValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the needle length
|
||||
|
||||
Reference in New Issue
Block a user