From 9d03a6856c72b171b52a599268dea84eacc2c89e Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 4 Aug 2020 22:02:20 +1200 Subject: [PATCH] FIX Retain custom sort on custom lists in GridFieldAddExistingAutoCompleter Forcing sort by the first search field isn't always appropriate. When a custom search list is used, we can set the expectation that custom sorting is intended as well. As an example, this can be used to autocomplete based on FULLTEXT indexes, and sort based on relevancy. --- .../GridFieldAddExistingAutocompleter.php | 18 ++++++-- .../GridFieldAddExistingAutocompleterTest.php | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/Forms/GridField/GridFieldAddExistingAutocompleter.php b/src/Forms/GridField/GridFieldAddExistingAutocompleter.php index 2d5bbe215..afec2e03c 100644 --- a/src/Forms/GridField/GridFieldAddExistingAutocompleter.php +++ b/src/Forms/GridField/GridFieldAddExistingAutocompleter.php @@ -223,8 +223,8 @@ class GridFieldAddExistingAutocompleter implements GridField_HTMLProvider, GridF */ public function doSearch($gridField, $request) { + $searchStr = $request->getVar('gridfield_relationsearch'); $dataClass = $gridField->getModelClass(); - $allList = $this->searchList ? $this->searchList : DataList::create($dataClass); $searchFields = ($this->getSearchFields()) ? $this->getSearchFields() @@ -241,12 +241,22 @@ class GridFieldAddExistingAutocompleter implements GridField_HTMLProvider, GridF $params = []; foreach ($searchFields as $searchField) { $name = (strpos($searchField, ':') !== false) ? $searchField : "$searchField:StartsWith"; - $params[$name] = $request->getVar('gridfield_relationsearch'); + $params[$name] = $searchStr; } - $results = $allList + + $results = null; + if ($this->searchList) { + // Assume custom sorting, don't apply default sorting + $results = $this->searchList; + } else { + $results = DataList::create($dataClass) + ->sort(strtok($searchFields[0], ':'), 'ASC'); + } + + // Apply baseline filtering and limits which should hold regardless of any customisations + $results = $results ->subtract($gridField->getList()) ->filterAny($params) - ->sort(strtok($searchFields[0], ':'), 'ASC') ->limit($this->getResultsLimit()); $json = []; diff --git a/tests/php/Forms/GridField/GridFieldAddExistingAutocompleterTest.php b/tests/php/Forms/GridField/GridFieldAddExistingAutocompleterTest.php index 7c1aca2c6..86ddcf22c 100644 --- a/tests/php/Forms/GridField/GridFieldAddExistingAutocompleterTest.php +++ b/tests/php/Forms/GridField/GridFieldAddExistingAutocompleterTest.php @@ -2,10 +2,14 @@ namespace SilverStripe\Forms\Tests\GridField; +use SilverStripe\Control\HTTPRequest; use SilverStripe\Core\Convert; use SilverStripe\Dev\CSSContentParser; use SilverStripe\Dev\FunctionalTest; +use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter; +use SilverStripe\Forms\GridField\GridFieldConfig; +use SilverStripe\Forms\GridField\GridFieldDataColumns; use SilverStripe\Forms\Tests\GridField\GridFieldAddExistingAutocompleterTest\TestController; use SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader; use SilverStripe\Forms\Tests\GridField\GridFieldTest\Permissions; @@ -127,4 +131,44 @@ class GridFieldAddExistingAutocompleterTest extends FunctionalTest new ArrayList([$team1, $team2]) ); } + + public function testRetainsCustomSort() + { + $component = new GridFieldAddExistingAutocompleter($targetFragment = 'before', ['Test']); + $component->setSearchFields(['Name']); + + $grid = $this->getGridFieldForComponent($component); + $grid->setList(Team::get()->filter('Name', 'force-empty-list')); + + $component->setSearchList(Team::get()); + $request = new HTTPRequest('GET', '', ['gridfield_relationsearch' => 'Team']); + $response = $component->doSearch($grid, $request); + $this->assertFalse($response->isError()); + $result = json_decode($response->getBody(), true); + $this->assertEquals( + ['Team 1', 'Team 2', 'Team 3', 'Team 4'], + array_map(function ($item) { return $item['label']; }, $result) + ); + + $component->setSearchList(Team::get()->sort('Name', 'DESC')); + $request = new HTTPRequest('GET', '', ['gridfield_relationsearch' => 'Team']); + $response = $component->doSearch($grid, $request); + $this->assertFalse($response->isError()); + $result = json_decode($response->getBody(), true); + $this->assertEquals( + ['Team 4', 'Team 3', 'Team 2', 'Team 1'], + array_map(function ($item) { return $item['label']; }, $result) + ); + } + + protected function getGridFieldForComponent($component) + { + $config = GridFieldConfig::create()->addComponents( + $component, + new GridFieldDataColumns() + ); + + return (new GridField('testfield', 'testfield')) + ->setConfig($config); + } }