diff --git a/src/Search/Variants/SearchVariant.php b/src/Search/Variants/SearchVariant.php index 410cf52..ea70abf 100644 --- a/src/Search/Variants/SearchVariant.php +++ b/src/Search/Variants/SearchVariant.php @@ -2,11 +2,10 @@ namespace SilverStripe\FullTextSearch\Search\Variants; -use SilverStripe\ORM\DataObject; +use ReflectionClass; use SilverStripe\Core\ClassInfo; use SilverStripe\Core\Config\Configurable; use SilverStripe\FullTextSearch\Utils\CombinationsArrayIterator; -use ReflectionClass; /** * A Search Variant handles decorators and other situations where the items to reindex or search through are modified @@ -93,6 +92,7 @@ abstract class SearchVariant public static function variants($class = null, $includeSubclasses = true) { if (!$class) { + // Build up and cache a list of all search variants (subclasses of SearchVariant) if (self::$variants === null) { $classes = ClassInfo::subclassesFor(static::class); @@ -166,6 +166,42 @@ abstract class SearchVariant return self::$call_instances[$key]; } + /** + * Similar to {@link SearchVariant::with}, except will only use variants that apply to at least one of the classes + * in the input array, where {@link SearchVariant::with} will run the query on the specific class you give it. + * + * @param string[] $classes + * @return SearchVariant_Caller + */ + public static function withCommon(array $classes = []) + { + // Allow caching + $cacheKey = sha1(serialize($classes)); + if (isset(self::$call_instances[$cacheKey])) { + return self::$call_instances[$cacheKey]; + } + + // Construct new array of variants applicable to at least one class in the list + $commonVariants = []; + foreach ($classes as $class => $options) { + // Extract relevant class options + $includeSubclasses = isset($options['include_children']) ? $options['include_children'] : true; + + // Get the variants for the current class + $variantsForClass = self::variants($class, $includeSubclasses); + + // Merge the variants applicable to the current class into the list of common variants, using + // the variant instance to replace any previous versions for the same class name (should be singleton + // anyway). + $commonVariants = array_replace($commonVariants, $variantsForClass); + } + + // Cache for future calls + self::$call_instances[$cacheKey] = new SearchVariant_Caller($commonVariants); + + return self::$call_instances[$cacheKey]; + } + /** * A shortcut to with when calling without passing in a class, * diff --git a/src/Solr/SolrIndex.php b/src/Solr/SolrIndex.php index 24fa5de..ef3a82b 100644 --- a/src/Solr/SolrIndex.php +++ b/src/Solr/SolrIndex.php @@ -5,6 +5,7 @@ namespace SilverStripe\FullTextSearch\Solr; use SilverStripe\Control\Director; use SilverStripe\Core\Environment; use SilverStripe\FulltextSearch\Search\Indexes\SearchIndex; +use SilverStripe\FullTextSearch\Search\Variants\SearchVariant_Caller; use SilverStripe\FullTextSearch\Solr\Services\SolrService; use SilverStripe\FulltextSearch\Search\Queries\SearchQuery; use SilverStripe\FullTextSearch\Search\Queries\SearchQuery_Range; @@ -710,12 +711,7 @@ abstract class SolrIndex extends SearchIndex public function search(SearchQuery $query, $offset = -1, $limit = -1, $params = array()) { $service = $this->getService(); - - $searchClass = count($query->classes) == 1 - ? $query->classes[0]['class'] - : null; - SearchVariant::with($searchClass) - ->call('alterQuery', $query, $this); + $this->applySearchVariants($query); $q = array(); // Query $fq = array(); // Filter query @@ -870,6 +866,21 @@ abstract class SolrIndex extends SearchIndex return $ret; } + /** + * With a common set of variants that are relevant to at least one class in the list (from either the query or + * the current index), allow them to alter the query to add their variant column conditions. + * + * @param SearchQuery $query + */ + protected function applySearchVariants(SearchQuery $query) + { + $classes = count($query->classes) ? $query->classes : $this->getClasses(); + + /** @var SearchVariant_Caller $variantCaller */ + $variantCaller = SearchVariant::withCommon($classes); + $variantCaller->call('alterQuery', $query, $this); + } + /** * Solr requires namespaced classes to have double escaped backslashes * diff --git a/tests/SolrIndexTest.php b/tests/SolrIndexTest.php index 73bf11d..6d5925e 100644 --- a/tests/SolrIndexTest.php +++ b/tests/SolrIndexTest.php @@ -172,7 +172,7 @@ class SolrIndexTest extends SapphireTest $this->equalTo([ 'qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 ' . SearchUpdaterTest_Container::class . '_Field2^2.1 _text', - 'fq' => '+(_versionedstage:"" (*:* -_versionedstage:[* TO *]))', + 'fq' => '', ]), $this->anything() )->willReturn($this->getFakeRawSolrResponse());