silverstripe /
silverstripe-fulltextsearch
| 1 | <?php |
||
| 2 | |||
| 3 | namespace SilverStripe\FullTextSearch\Search; |
||
| 4 | |||
| 5 | use SilverStripe\Core\ClassInfo; |
||
| 6 | use SilverStripe\Core\Config\Config; |
||
| 7 | use SilverStripe\ORM\DataObject; |
||
| 8 | use SilverStripe\FullTextSearch\Search\Indexes\SearchIndex; |
||
| 9 | use ReflectionClass; |
||
| 10 | |||
| 11 | /** |
||
| 12 | * Base class to manage active search indexes. |
||
| 13 | */ |
||
| 14 | class FullTextSearch |
||
| 15 | { |
||
| 16 | protected static $all_indexes = null; |
||
| 17 | |||
| 18 | protected static $indexes_by_subclass = array(); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Optional list of index names to limit to. If left empty, all subclasses of SearchIndex |
||
| 22 | * will be used |
||
| 23 | * |
||
| 24 | * @var array |
||
| 25 | * @config |
||
| 26 | */ |
||
| 27 | private static $indexes = array(); |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 28 | |||
| 29 | /** |
||
| 30 | * Get all the instantiable search indexes (so all the user created indexes, but not the connector or library level |
||
| 31 | * abstract indexes). Can optionally be filtered to only return indexes that are subclasses of some class |
||
| 32 | * |
||
| 33 | * @static |
||
| 34 | * @param string $class - Class name to filter indexes by, so that all returned indexes are subclasses of provided |
||
| 35 | * class |
||
| 36 | * @param bool $rebuild - If true, don't use cached values |
||
| 37 | */ |
||
| 38 | public static function get_indexes($class = null, $rebuild = false) |
||
| 39 | { |
||
| 40 | if ($rebuild) { |
||
| 41 | self::$all_indexes = null; |
||
| 42 | self::$indexes_by_subclass = array(); |
||
| 43 | } |
||
| 44 | |||
| 45 | if (!$class) { |
||
| 46 | if (self::$all_indexes === null) { |
||
| 47 | // Get declared indexes, or otherwise default to all subclasses of SearchIndex |
||
| 48 | $classes = Config::inst()->get(__CLASS__, 'indexes') |
||
| 49 | ?: ClassInfo::subclassesFor(SearchIndex::class); |
||
| 50 | |||
| 51 | $hidden = array(); |
||
| 52 | $candidates = array(); |
||
| 53 | foreach ($classes as $class) { |
||
| 54 | // Check if this index is disabled |
||
| 55 | $hides = $class::config()->hide_ancestor; |
||
| 56 | if ($hides) { |
||
| 57 | $hidden[] = $hides; |
||
| 58 | } |
||
| 59 | |||
| 60 | // Check if this index is abstract |
||
| 61 | $ref = new ReflectionClass($class); |
||
| 62 | if (!$ref->isInstantiable()) { |
||
| 63 | continue; |
||
| 64 | } |
||
| 65 | |||
| 66 | $candidates[] = $class; |
||
| 67 | } |
||
| 68 | |||
| 69 | if ($hidden) { |
||
| 70 | $candidates = array_diff($candidates, $hidden); |
||
| 71 | } |
||
| 72 | |||
| 73 | // Create all indexes |
||
| 74 | $concrete = array(); |
||
| 75 | foreach ($candidates as $class) { |
||
| 76 | $concrete[$class] = singleton($class); |
||
| 77 | } |
||
| 78 | |||
| 79 | self::$all_indexes = $concrete; |
||
| 80 | } |
||
| 81 | |||
| 82 | return self::$all_indexes; |
||
| 83 | } else { |
||
| 84 | if (!isset(self::$indexes_by_subclass[$class])) { |
||
| 85 | $all = self::get_indexes(); |
||
| 86 | |||
| 87 | $valid = array(); |
||
| 88 | foreach ($all as $indexclass => $instance) { |
||
| 89 | if (is_subclass_of($indexclass, $class)) { |
||
| 90 | $valid[$indexclass] = $instance; |
||
| 91 | } |
||
| 92 | } |
||
| 93 | |||
| 94 | self::$indexes_by_subclass[$class] = $valid; |
||
| 95 | } |
||
| 96 | |||
| 97 | return self::$indexes_by_subclass[$class]; |
||
| 98 | } |
||
| 99 | } |
||
| 100 | |||
| 101 | /** |
||
| 102 | * Sometimes, like when in tests, you want to restrain the actual indexes to a subset |
||
| 103 | * |
||
| 104 | * Call with one argument - an array of class names, index instances or classname => indexinstance pairs (can be |
||
| 105 | * mixed). |
||
| 106 | * Alternatively call with multiple arguments, each of which is a class name or index instance |
||
| 107 | * |
||
| 108 | * From then on, fulltext search system will only see those indexes passed in this most recent call. |
||
| 109 | * |
||
| 110 | * Passing in no arguments resets back to automatic index list |
||
| 111 | * |
||
| 112 | * Alternatively you can use `FullTextSearch.indexes` to configure a list of indexes via config. |
||
| 113 | */ |
||
| 114 | public static function force_index_list() |
||
| 115 | { |
||
| 116 | $indexes = func_get_args(); |
||
| 117 | |||
| 118 | // No arguments = back to automatic |
||
| 119 | if (!$indexes) { |
||
|
0 ignored issues
–
show
The expression
$indexes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||
| 120 | self::get_indexes(null, true); |
||
| 121 | return; |
||
| 122 | } |
||
| 123 | |||
| 124 | // Arguments can be a single array |
||
| 125 | if (is_array($indexes[0])) { |
||
| 126 | $indexes = $indexes[0]; |
||
| 127 | } |
||
| 128 | |||
| 129 | // Reset to empty first |
||
| 130 | self::$all_indexes = array(); |
||
| 131 | self::$indexes_by_subclass = array(); |
||
| 132 | |||
| 133 | // And parse out alternative type combos for arguments and add to allIndexes |
||
| 134 | foreach ($indexes as $class => $index) { |
||
| 135 | if (is_string($index)) { |
||
| 136 | $class = $index; |
||
| 137 | $index = singleton($class); |
||
| 138 | } |
||
| 139 | if (is_numeric($class)) { |
||
| 140 | $class = get_class($index); |
||
| 141 | } |
||
| 142 | |||
| 143 | self::$all_indexes[$class] = $index; |
||
| 144 | } |
||
| 145 | } |
||
| 146 | } |
||
| 147 |