mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
FIX FulltextFilter did not work and was not usable
This commit is contained in:
parent
f2edf34297
commit
40c5b8b675
42
search/filters/FulltextFilter.php
Normal file → Executable file
42
search/filters/FulltextFilter.php
Normal file → Executable file
@ -17,17 +17,17 @@
|
||||
* database table, using the {$indexes} hash in your DataObject subclass:
|
||||
*
|
||||
* <code>
|
||||
* static $indexes = array(
|
||||
* private static $indexes = array(
|
||||
* 'SearchFields' => 'fulltext(Name, Title, Description)'
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* @package framework
|
||||
* @subpackage search
|
||||
* @todo Add support for databases besides MySQL
|
||||
*/
|
||||
class FulltextFilter extends SearchFilter {
|
||||
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"MATCH (%s) AGAINST ('%s')",
|
||||
$this->getDbName(),
|
||||
@ -36,6 +36,7 @@ class FulltextFilter extends SearchFilter {
|
||||
}
|
||||
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"NOT MATCH (%s) AGAINST ('%s')",
|
||||
$this->getDbName(),
|
||||
@ -46,4 +47,39 @@ class FulltextFilter extends SearchFilter {
|
||||
public function isEmpty() {
|
||||
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation allows for a list of columns to be passed into MATCH() instead of just one.
|
||||
*
|
||||
* @example
|
||||
* <code>
|
||||
* MyDataObject::get()->filter('SearchFields:fulltext', 'search term')
|
||||
* </code>
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDbName() {
|
||||
$indexes = Config::inst()->get($this->model, "indexes");
|
||||
if(is_array($indexes) && array_key_exists($this->getName(), $indexes)) {
|
||||
$index = $indexes[$this->getName()];
|
||||
if(is_array($index) && array_key_exists("value", $index)) {
|
||||
return $index['value'];
|
||||
} else {
|
||||
// Parse a fulltext string (eg. fulltext ("ColumnA", "ColumnB")) to figure out which columns
|
||||
// we need to search.
|
||||
if(preg_match('/^fulltext\ \((.+)\)$/i', $index, $matches)) {
|
||||
return $matches[1];
|
||||
} else {
|
||||
throw new Exception("Invalid fulltext index format for '" . $this->getName()
|
||||
. "' on '" . $this->model . "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
throw new Exception($this->getName() . ' is not a fulltext index on ' . $this->model . '.');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -166,6 +166,11 @@ abstract class SearchFilter extends Object {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
// Ensure that we're dealing with a DataObject.
|
||||
if (!is_subclass_of($this->model, 'DataObject')) {
|
||||
throw new Exception("Model supplied to " . get_class($this) . " should be an instance of DataObject.");
|
||||
}
|
||||
|
||||
$candidateClass = ClassInfo::table_for_object_field(
|
||||
$this->model,
|
||||
$this->name
|
||||
@ -178,7 +183,7 @@ abstract class SearchFilter extends Object {
|
||||
return '"' . implode('"."', $parts) . '"';
|
||||
}
|
||||
|
||||
return "\"$candidateClass\".\"$this->name\"";
|
||||
return "\"{$candidateClass}\".\"{$this->name}\"";
|
||||
}
|
||||
|
||||
/**
|
||||
|
61
tests/search/FulltextFilterTest.php
Executable file
61
tests/search/FulltextFilterTest.php
Executable file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
class FulltextFilterTest extends SapphireTest {
|
||||
|
||||
protected static $fixture_file = "FulltextFilterTest.yml";
|
||||
|
||||
|
||||
public function testFilter() {
|
||||
if(DB::getConn() instanceof MySQLDatabase) {
|
||||
$baseQuery = FulltextDataObject::get();
|
||||
$this->assertEquals(3, $baseQuery->count(), "FulltextDataObject count does not match.");
|
||||
|
||||
// First we'll text the 'SearchFields' which has been set using an array
|
||||
$search = $baseQuery->filter("SearchFields:fulltext", 'SilverStripe');
|
||||
$this->assertEquals(1, $search->count());
|
||||
|
||||
$search = $baseQuery->exclude("SearchFields:fulltext", "SilverStripe");
|
||||
$this->assertEquals(2, $search->count());
|
||||
|
||||
// Now we'll run the same tests on 'OtherSearchFields' which should yield the same resutls
|
||||
// but has been set using a string.
|
||||
$search = $baseQuery->filter("OtherSearchFields:fulltext", 'SilverStripe');
|
||||
$this->assertEquals(1, $search->count());
|
||||
|
||||
$search = $baseQuery->exclude("OtherSearchFields:fulltext", "SilverStripe");
|
||||
$this->assertEquals(2, $search->count());
|
||||
|
||||
// Edgecase
|
||||
$this->setExpectedException("Exception");
|
||||
$search = $baseQuery->exclude("Madeup:fulltext", "SilverStripe");
|
||||
} else {
|
||||
$this->markTestSkipped("FulltextFilter only supports MySQL syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class FulltextDataObject extends DataObject {
|
||||
|
||||
private static $db = array(
|
||||
"ColumnA" => "Varchar(255)",
|
||||
"ColumnB" => "HTMLText",
|
||||
"ColumnC" => "Varchar(255)",
|
||||
"ColumnD" => "HTMLText",
|
||||
);
|
||||
|
||||
private static $indexes = array(
|
||||
'SearchFields' => array(
|
||||
'type' => 'fulltext',
|
||||
'name' => 'SearchFields',
|
||||
'value' => '"ColumnA", "ColumnB"',
|
||||
),
|
||||
'OtherSearchFields' => 'fulltext ("ColumnC", "ColumnD")',
|
||||
);
|
||||
|
||||
private static $create_table_options = array(
|
||||
"MySQLDatabase" => "ENGINE=MyISAM",
|
||||
);
|
||||
|
||||
}
|
16
tests/search/FulltextFilterTest.yml
Normal file
16
tests/search/FulltextFilterTest.yml
Normal file
@ -0,0 +1,16 @@
|
||||
FulltextDataObject:
|
||||
object1:
|
||||
ColumnA: 'SilverStripe'
|
||||
CluumnB: <p>Some content about SilverStripe.</p>
|
||||
ColumnC: 'SilverStripe'
|
||||
ColumnD: '<p>Some content about SilverStripe.</p>
|
||||
object2:
|
||||
ColumnA: 'Test Row'
|
||||
ColumnB: '<p>Some information about this test row.</p>'
|
||||
ColumnC: 'Test Row'
|
||||
ColumnD: '<p>Some information about this test row.</p>'
|
||||
object3:
|
||||
ColumnA: 'Fulltext Search'
|
||||
ColumnB: '<p>Testing fulltext search.</p>'
|
||||
ColumnC: 'Fulltext Search
|
||||
ColumnD: '<p>Testing fulltext search.</p>'
|
Loading…
x
Reference in New Issue
Block a user