mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-09-18 15:36:30 +02:00
8dd644d25d
Namespace all templates Move difflib and BBCodeParser2 to thirdparty Remove deprecated API marked for removal in 4.0
101 lines
2.9 KiB
PHP
Executable File
101 lines
2.9 KiB
PHP
Executable File
<?php
|
|
|
|
namespace SilverStripe\ORM\Filters;
|
|
|
|
use SilverStripe\ORM\DataQuery;
|
|
use SilverStripe\ORM\DataObject;
|
|
use SilverStripe\Core\Config\Config;
|
|
use Exception;
|
|
|
|
/**
|
|
* Filters by full-text matching on the given field.
|
|
*
|
|
* Full-text indexes are only available with MyISAM tables. The following column types are
|
|
* supported:
|
|
* - Char
|
|
* - Varchar
|
|
* - Text
|
|
*
|
|
* To enable full-text matching on fields, you also need to add an index to the
|
|
* database table, using the {$indexes} hash in your DataObject subclass:
|
|
*
|
|
* <code>
|
|
* private static $indexes = array(
|
|
* 'SearchFields' => 'fulltext(Name, Title, Description)'
|
|
* );
|
|
* </code>
|
|
*
|
|
* @todo Add support for databases besides MySQL
|
|
*/
|
|
class FulltextFilter extends SearchFilter {
|
|
|
|
protected function applyOne(DataQuery $query) {
|
|
$this->model = $query->applyRelation($this->relation);
|
|
$predicate = sprintf("MATCH (%s) AGAINST (?)", $this->getDbName());
|
|
return $query->where(array($predicate => $this->getValue()));
|
|
}
|
|
|
|
protected function excludeOne(DataQuery $query) {
|
|
$this->model = $query->applyRelation($this->relation);
|
|
$predicate = sprintf("NOT MATCH (%s) AGAINST (?)", $this->getDbName());
|
|
return $query->where(array($predicate => $this->getValue()));
|
|
}
|
|
|
|
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>
|
|
*
|
|
* @throws Exception
|
|
* @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 $this->prepareColumns($index['value']);
|
|
} else {
|
|
// Parse a fulltext string (eg. fulltext ("ColumnA", "ColumnB")) to figure out which columns
|
|
// we need to search.
|
|
if(preg_match('/^fulltext\s+\((.+)\)$/i', $index, $matches)) {
|
|
return $this->prepareColumns($matches[1]);
|
|
} else {
|
|
throw new Exception(sprintf(
|
|
"Invalid fulltext index format for '%s' on '%s'",
|
|
$this->getName(),
|
|
$this->model
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
return parent::getDbName();
|
|
}
|
|
|
|
/**
|
|
* Adds table identifier to the every column.
|
|
* Columns must have table identifier to prevent duplicate column name error.
|
|
*
|
|
* @param array $columns
|
|
* @return string
|
|
*/
|
|
protected function prepareColumns($columns) {
|
|
$cols = preg_split('/"?\s*,\s*"?/', trim($columns, '(") '));
|
|
$table = DataObject::getSchema()->tableForField($this->model, current($cols));
|
|
$cols = array_map(function($col) use ($table) {
|
|
return sprintf('"%s"."%s"', $table, $col);
|
|
}, $cols);
|
|
return implode(',', $cols);
|
|
}
|
|
|
|
}
|