Skip to content

Commit

Permalink
ENH Search all summary fields and split words
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Aug 13, 2021
1 parent b2a85e7 commit 0d3b9de
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 15 deletions.
51 changes: 44 additions & 7 deletions src/Forms/GridField/GridFieldFilterHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\Forms\FieldList;
Expand Down Expand Up @@ -218,9 +219,31 @@ public function getManipulatedData(GridField $gridField, SS_List $dataList)
return $dataList;
}

// remove summary_fields key if using advanced filter
if (array_key_exists('summary_fields', $filterArguments)) {
if (count($filterArguments) !== 1) {
unset($filterArguments['summary_fields']);
}
}

$disjunctive = false;
if (array_key_exists('summary_fields', $filterArguments)) {
$disjunctive = true;
$words = explode(' ', $filterArguments['summary_fields']); // split on words
$filterArguments = [];
$dataClass = $dataList->dataClass();
$fields = Injector::inst()->get($dataClass)->config()->get('searchable_fields');
if (empty($fields)) {
$fields = Injector::inst()->get($dataClass)->config()->get('summary_fields');
}
foreach ($fields as $field) {
$filterArguments[$field] = $words;
}
}

$dataListClone = clone($dataList);
$results = $this->getSearchContext($gridField)
->getQuery($filterArguments, false, false, $dataListClone);
->getQuery($filterArguments, false, false, $dataListClone, $disjunctive);

return $results;
}
Expand Down Expand Up @@ -287,6 +310,7 @@ public function getSearchFieldSchema(GridField $gridField)
if (array_key_exists($gridField->getName(), $params)) {
$params = $params[$gridField->getName()];
}
$originalParams = $params;
if ($context->getSearchParams()) {
$params = array_merge($context->getSearchParams(), $params);
}
Expand All @@ -297,12 +321,25 @@ public function getSearchFieldSchema(GridField $gridField)

$name = $gridField->Title ?: singleton($gridField->getModelClass())->i18n_plural_name();

// Prefix "Search__" onto the filters for the React component
$filters = $context->getSearchParams();
if (!$this->useLegacyFilterHeader && !empty($filters)) {
$filters = array_combine(array_map(function ($key) {
return 'Search__' . $key;
}, array_keys($filters)), $filters);
// Filters have a "Search__" prefix added for the React component
$filters = [];
if (count($originalParams) === 1 && array_key_exists('summary_fields', $originalParams)) {
// summary fields search
$filters = ['summary_fields' => $originalParams['summary_fields']];
if (!$this->useLegacyFilterHeader) {
$filters['Search__summary_fields'] = $originalParams['summary_fields'];
}
} else {
// advanced search
$filters = $context->getSearchParams();
if (array_key_exists('summary_fields', $filters)) {
unset($filters['summary_fields']);
}
if (!$this->useLegacyFilterHeader && !empty($filters)) {
$filters = array_combine(array_map(function ($key) {
return 'Search__' . $key;
}, array_keys($filters)), $filters);
}
}

$searchAction = GridField_FormAction::create($gridField, 'filter', false, 'filter', null);
Expand Down
7 changes: 7 additions & 0 deletions src/ORM/DataObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\FormScaffolder;
use SilverStripe\Forms\CompositeValidator;
use SilverStripe\Forms\HiddenField;
use SilverStripe\i18n\i18n;
use SilverStripe\i18n\i18nEntityProvider;
use SilverStripe\ORM\Connect\MySQLSchemaManager;
Expand Down Expand Up @@ -2378,6 +2379,12 @@ public function scaffoldSearchFields($_params = null)
(array)$_params
);
$fields = new FieldList();

// Adds a 'search all summary fields' field to be used as the default search field
// The gridfield search simply picks the first field from the list
// See GridFieldFilterHeader.php and SearchContext.php
$fields->push(HiddenField::create('summary_fields', 'Summary fields search'));

foreach ($this->searchableFields() as $fieldName => $spec) {
if ($params['restrictFields'] && !in_array($fieldName, $params['restrictFields'])) {
continue;
Expand Down
37 changes: 29 additions & 8 deletions src/ORM/Search/SearchContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,11 @@ protected function applyBaseTableFields()
* Falls back to {@link DataObject::$default_sort} if not provided.
* @param array|bool|string $limit
* @param DataList $existingQuery
* @param bool $disjunctive Use OR to connect WHERE clauses between fields instead of AND
* @return DataList
* @throws Exception
*/
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null)
public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null, $disjunctive = false)
{
/** DataList $query */
$query = null;
Expand Down Expand Up @@ -173,13 +174,33 @@ public function getQuery($searchParams, $sort = false, $limit = false, $existing
$query = $query->sort($sort);
$this->setSearchParams($searchParams);

foreach ($this->searchParams as $key => $value) {
$key = str_replace('__', '.', $key);
if ($filter = $this->getFilter($key)) {
$filter->setModel($this->modelClass);
$filter->setValue($value);
if (!$filter->isEmpty()) {
$query = $query->alterDataQuery([$filter, 'apply']);
if ($disjunctive) {
// WHERE .. OR
$disjunctiveParams = $this->searchParams;
foreach ($this->searchParams as $key => $value) {
if ($filter = $this->getFilter($key)) {
// TODO: replace with some sort of reverse lookup on DataListFilter config in case someone
// adds their own filter type that doesn't end in 'Filter'
$parts = explode('\\', get_class($filter));
$classNoNamespace = end($parts);
if (preg_match('#^([A-Za-z0-9]+)Filter$#', $classNoNamespace, $matches)) {
$modifier = $matches[1]; // e.g. PartialMatch
$disjunctiveParams[$key . ':' . $modifier] = $value;
unset($disjunctiveParams[$key]);
}
}
}
$query = $query->filterAny($disjunctiveParams);
} else {
// WHERE .. AND
foreach ($this->searchParams as $key => $value) {
$key = str_replace('__', '.', $key);
if ($filter = $this->getFilter($key)) {
$filter->setModel($this->modelClass);
$filter->setValue($value);
if (!$filter->isEmpty()) {
$query = $query->alterDataQuery([$filter, 'apply']);
}
}
}
}
Expand Down

0 comments on commit 0d3b9de

Please sign in to comment.