Created
October 12, 2015 19:39
-
-
Save jhoffmann/a4efad333d7d82b612c0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This allows a user to utilize ElasticSearch (FTS) query syntax when filtering records | |
* for a module's list view | |
* | |
* For the supported syntax, see: | |
* http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#_simple_query_string_syntax | |
* | |
* @link PSD-1310 | |
* @author jwh | |
*/ | |
require_once('clients/base/api/FilterApi.php'); | |
class FTSFilterApi extends FilterApi | |
{ | |
// Point the existing endpoint at our custom filter method. | |
public function registerApiRest() | |
{ | |
return array( | |
'filterModuleGet' => array( | |
'reqType' => 'GET', | |
'path' => array('<module>', 'filter'), | |
'pathVars' => array('module', ''), | |
'method' => 'filterCustomList', | |
'jsonParams' => array('filter'), | |
'shortHelp' => 'Lists filtered records.', | |
'longHelp' => 'include/api/help/module_filter_get_help.html', | |
), | |
); | |
} | |
/** | |
* Custom filter endpoint to allow for boolean searches of full text fields using FTS. | |
* | |
* @link PSD-1310 | |
* @author jwh | |
*/ | |
public function filterCustomList(ServiceBase $api, array $args, $acl = 'list') | |
{ | |
if (!empty($args['filter'])) { | |
$args['filter'] = $this->transformBooleans($args['filter'], $args['module']); | |
} | |
return $this->filterList($api, $args, $acl); | |
} | |
/** | |
* Go through our filter arguments and find our $boolean search strings, | |
* pass them to FTS, and use the result as a $in filter. We also have to clear our | |
* custom $boolean keys or it breaks SugarQuery. | |
* | |
* @link PSD-1310 | |
* @author jwh | |
*/ | |
protected function transformBooleans(array $params, $module, &$parent = null) | |
{ | |
foreach ($params as $k => &$v) { | |
if (is_array($v) && in_array('$boolean', array_keys($v), true)) { | |
// Clear out our pseudo filter and populate it with the results from our Elastic search | |
$matches = $this->filterUsingFTS(current($v), $module); | |
// Seed the $in array with a 'none' string so if we don't get results from FTS we don't just | |
// show the results using the remaining filter params | |
$parent[-99]['id']['$in'] = array_merge((array) $parent[-99]['id']['$in'], array('none'), $matches); | |
unset($params[$k]); | |
} elseif (is_array($v)) { | |
$params[$k] = $this->transformBooleans($v, $module, $params); | |
} | |
} | |
return $params; | |
} | |
/** | |
* Pass our query string over to FTS and return a set of matching records. We limit the result set to 500 | |
* records for performance reasons, keeping in mind other filter params and ACL access may reduce the visible | |
* list as well. We can't tell FTS to only return records where the status is 'Open' for example, but the user | |
* might be filtering on that. | |
* | |
* @link PSD-1310 | |
* @author jwh | |
*/ | |
protected function filterUsingFTS($q, $module) { | |
$searchEngine = SugarSearchEngineFactory::getInstance(SugarSearchEngineFactory::getFTSEngineNameFromConfig()); | |
if ($searchEngine instanceof SugarSearchEngineAbstractBase) { | |
$rs = $searchEngine->search($q, 0, 500, array('moduleFilter' => array($module))); | |
if ($rs !== null) { | |
foreach ($rs as $result) { | |
$esMatches[] = $result->getId(); | |
} | |
} | |
return (array) $esMatches; | |
} | |
return array(); | |
} | |
// Uncomment in order to log the SQL being generated for debug purposes | |
// public function filterListSetup(ServiceBase $api, array $args, $acl = 'list') | |
// { | |
// $p = parent::filterListSetup($api, $args, $acl); | |
// _ppl($p[1]->compileSql()); | |
// return $p; | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment