diff --git a/README.md b/README.md index 66ab25f..a5389d3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # FullTextSearch module [![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-fulltextsearch.png?branch=master)](http://travis-ci.org/silverstripe/silverstripe-fulltextsearch) diff --git a/code/search/SearchVariantSubsites.php b/code/search/SearchVariantSubsites.php index 8f52ac2..63ad366 100644 --- a/code/search/SearchVariantSubsites.php +++ b/code/search/SearchVariantSubsites.php @@ -60,9 +60,21 @@ class SearchVariantSubsites extends SearchVariant )); } - + /** + * This field has been altered to allow a user to obtain search results for a particular subsite + * When attempting to do this in project code, SearchVariantSubsites kicks and overwrites any filter you've applied + * This fix prevents the module from doing this if a filter is applied on the index or the query, or if a field is + * being excluded specifically before being executed. + * + * A pull request has been raised for this issue. Once accepted this forked module can be deleted and the parent + * project should be used instead. + */ public function alterQuery($query, $index) { + if ($this->isFieldFiltered('_subsite', $query)) { + return; + } + $subsite = Subsite::currentSubsiteID(); $query->filter('_subsite', array($subsite, SearchQuery::$missing)); } @@ -109,4 +121,19 @@ class SearchVariantSubsites extends SearchVariant $writes[$key]['statefulids'] = $next; } } + + /** + * Determine if a field with a certain name is filtered by the search query or on the index + * This is the equivalent of saying "show me the results that do ONLY contain this value" + * @param $field string name of the field being filtered + * @param $query SearchQuery currently being executed + * @param $index SearchIndex which specifies a filter field + * @return bool true if $field is being filtered, false if it is not being filtered + */ + protected function isFieldFiltered($field, $query) + { + $queryHasFilter = !empty($query->require[$field]); + + return $queryHasFilter; + } } diff --git a/tests/SearchVariantSubsitesTest.php b/tests/SearchVariantSubsitesTest.php new file mode 100644 index 0000000..eb29375 --- /dev/null +++ b/tests/SearchVariantSubsitesTest.php @@ -0,0 +1,91 @@ +markTestSkipped('The subsites module is not installed'); + } + + if (self::$index === null) { + self::$index = singleton('SearchVariantSubsiteTest'); + } + + SearchUpdater::bind_manipulation_capture(); + + Config::inst()->update('Injector', 'SearchUpdateProcessor', array( + 'class' => 'SearchUpdateImmediateProcessor' + )); + + FullTextSearch::force_index_list(self::$index); + SearchUpdater::clear_dirty_indexes(); + } + + public function testQueryIsAlteredWhenSubsiteNotSet() + { + $index = new SolrIndexTest_FakeIndex(); + $query = new SearchQuery(); + + //typical behaviour: nobody is explicitly filtering on subsite, so the search variant adds a filter to the query + $this->assertArrayNotHasKey('_subsite', $query->require); + $variant = new SearchVariantSubsites(); + $variant->alterDefinition('SearchUpdaterTest_Container', $index); + $variant->alterQuery($query, $index); + + //check that the "default" query has been put in place: it's not empty, and we're searching on Subsite ID:0 and + // an object of SearchQuery::missing + $this->assertNotEmpty($query->require['_subsite']); + $this->assertEquals(0, $query->require['_subsite'][0]); + + //check that SearchQuery::missing is set (by default, it is an object of stdClass) + $this->assertInstanceOf('stdClass', $query->require['_subsite'][1]); + } + + + public function testQueryIsAlteredWhenSubsiteIsSet() + { + //now we want to test if somebody has already applied the _subsite filter to the query + $index = new SolrIndexTest_FakeIndex(); + $query = new SearchQuery(); + + //check that _subsite is not applied yet + //this key should not be exist until the SearchVariant applies it later + $this->assertArrayNotHasKey('_subsite', $query->require); + + //apply the subsite filter on the query (for example, if it's passed into a controller and set before searching) + //we've chosen an arbirary value of 2 here, to check if it is changed later + $query->filter('_subsite', 2); + $this->assertNotEmpty($query->require['_subsite']); + + //apply the search variant's definition and query + $variant = new SearchVariantSubsites(); + $variant->alterDefinition('SearchUpdaterTest_Container', $index); + + //the protected function isFieldFiltered is implicitly tested here + $variant->alterQuery($query, $index); + + //confirm that the query has been altered, but NOT with default values + //first check that _subsite filter is not empty + $this->assertNotEmpty($query->require['_subsite']); + //subsite filter first value is not 0 + $this->assertNotEquals(0, $query->require['_subsite'][0]); + + //subsite filter SearchQuery::missing should not be set so its expected location is empty + $this->assertArrayNotHasKey(1, $query->require['_subsite']); + + //subsite filter has been modified with our arbitrary test value. The second value is not set + //this proves that the query has not been altered by the variant + $this->assertEquals(2, $query->require['_subsite'][0]); + + } + +} +