silverstripe-fulltextsearch/src/Search/FullTextSearch.php
Robbie Averill 861f87514d API Update Subsite integration, remove Polyhome variant
Add a method to clear cached variants from SearchVariant, and a configuration flag for whether
a variant should be enabled or not. Add a FullTextSearch TestState class which will globally
disable the queuedjobs and fulltextsearch shutdown handlers during tests, and is not used to
clear cached variants on each test to prevent global state leakage.

Also removes Phockito as a test dependency.
2017-12-05 14:29:53 +13:00

147 lines
4.6 KiB
PHP

<?php
namespace SilverStripe\FullTextSearch\Search;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\DataObject;
use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex;
use ReflectionClass;
/**
* Base class to manage active search indexes.
*/
class FullTextSearch
{
protected static $all_indexes = null;
protected static $indexes_by_subclass = array();
/**
* Optional list of index names to limit to. If left empty, all subclasses of SearchIndex
* will be used
*
* @var array
* @config
*/
private static $indexes = array();
/**
* Get all the instantiable search indexes (so all the user created indexes, but not the connector or library level
* abstract indexes). Can optionally be filtered to only return indexes that are subclasses of some class
*
* @static
* @param string $class - Class name to filter indexes by, so that all returned indexes are subclasses of provided
* class
* @param bool $rebuild - If true, don't use cached values
*/
public static function get_indexes($class = null, $rebuild = false)
{
if ($rebuild) {
self::$all_indexes = null;
self::$indexes_by_subclass = array();
}
if (!$class) {
if (self::$all_indexes === null) {
// Get declared indexes, or otherwise default to all subclasses of SearchIndex
$classes = Config::inst()->get(__CLASS__, 'indexes')
?: ClassInfo::subclassesFor(SearchIndex::class);
$hidden = array();
$candidates = array();
foreach ($classes as $class) {
// Check if this index is disabled
$hides = $class::config()->hide_ancestor;
if ($hides) {
$hidden[] = $hides;
}
// Check if this index is abstract
$ref = new ReflectionClass($class);
if (!$ref->isInstantiable()) {
continue;
}
$candidates[] = $class;
}
if ($hidden) {
$candidates = array_diff($candidates, $hidden);
}
// Create all indexes
$concrete = array();
foreach ($candidates as $class) {
$concrete[$class] = singleton($class);
}
self::$all_indexes = $concrete;
}
return self::$all_indexes;
} else {
if (!isset(self::$indexes_by_subclass[$class])) {
$all = self::get_indexes();
$valid = array();
foreach ($all as $indexclass => $instance) {
if (is_subclass_of($indexclass, $class)) {
$valid[$indexclass] = $instance;
}
}
self::$indexes_by_subclass[$class] = $valid;
}
return self::$indexes_by_subclass[$class];
}
}
/**
* Sometimes, like when in tests, you want to restrain the actual indexes to a subset
*
* Call with one argument - an array of class names, index instances or classname => indexinstance pairs (can be
* mixed).
* Alternatively call with multiple arguments, each of which is a class name or index instance
*
* From then on, fulltext search system will only see those indexes passed in this most recent call.
*
* Passing in no arguments resets back to automatic index list
*
* Alternatively you can use `FullTextSearch.indexes` to configure a list of indexes via config.
*/
public static function force_index_list()
{
$indexes = func_get_args();
// No arguments = back to automatic
if (!$indexes) {
self::get_indexes(null, true);
return;
}
// Arguments can be a single array
if (is_array($indexes[0])) {
$indexes = $indexes[0];
}
// Reset to empty first
self::$all_indexes = array();
self::$indexes_by_subclass = array();
// And parse out alternative type combos for arguments and add to allIndexes
foreach ($indexes as $class => $index) {
if (is_string($index)) {
$class = $index;
$index = singleton($class);
}
if (is_numeric($class)) {
$class = get_class($index);
}
self::$all_indexes[$class] = $index;
}
}
}