mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch 'pulls/sqlite-case-matching-new'
This commit is contained in:
commit
142ad15a47
@ -883,6 +883,18 @@ abstract class SS_Database {
|
||||
return "'" . Convert::raw2sql($string) . "'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a WHERE clause for text matching.
|
||||
*
|
||||
* @param String $field Quoted field name
|
||||
* @param String $value Escaped search. Can include percentage wildcards.
|
||||
* @param boolean $exact Exact matches or wildcard support.
|
||||
* @param boolean $negate Negate the clause.
|
||||
* @param boolean $caseSensitive Perform case sensitive search.
|
||||
* @return String SQL
|
||||
*/
|
||||
abstract public function comparisonClause($field, $value, $exact = false, $negate = false, $caseSensitive = false);
|
||||
|
||||
/**
|
||||
* function to return an SQL datetime expression that can be used with the adapter in use
|
||||
* used for querying a datetime in a certain format
|
||||
|
@ -1056,6 +1056,28 @@ class MySQLDatabase extends SS_Database {
|
||||
$this->query('COMMIT AND ' . ($chain ? '' : 'NO ') . 'CHAIN;');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a WHERE clause for text matching.
|
||||
*
|
||||
* @param String $field Quoted field name
|
||||
* @param String $value Escaped search. Can include percentage wildcards.
|
||||
* @param boolean $exact Exact matches or wildcard support.
|
||||
* @param boolean $negate Negate the clause.
|
||||
* @param boolean $caseSensitive Enforce case sensitivity if TRUE or FALSE.
|
||||
* Stick with default collation if set to NULL.
|
||||
* @return String SQL
|
||||
*/
|
||||
public function comparisonClause($field, $value, $exact = false, $negate = false, $caseSensitive = null) {
|
||||
if($exact && $caseSensitive === null) {
|
||||
$comp = ($negate) ? '!=' : '=';
|
||||
} else {
|
||||
$comp = ($caseSensitive) ? 'LIKE BINARY' : 'LIKE';
|
||||
if($negate) $comp = 'NOT ' . $comp;
|
||||
}
|
||||
|
||||
return sprintf("%s %s '%s'", $field, $comp, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* function to return an SQL datetime expression that can be used with MySQL
|
||||
* used for querying a datetime in a certain format
|
||||
|
@ -17,27 +17,14 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class EndsWithFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
|
||||
public function setModifiers(array $modifiers) {
|
||||
if(($extras = array_diff($modifiers, array('not', 'nocase', 'case'))) != array()) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this) . ' does not accept ' . implode(', ', $extras) . ' as modifiers');
|
||||
}
|
||||
if(DB::getConn() instanceof PostgreSQLDatabase) {
|
||||
if(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE';
|
||||
} else {
|
||||
$comparison = 'ILIKE';
|
||||
}
|
||||
} elseif(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE BINARY';
|
||||
} else {
|
||||
$comparison = 'LIKE';
|
||||
}
|
||||
if($exclude) {
|
||||
$comparison = 'NOT ' . $comparison;
|
||||
}
|
||||
return $comparison;
|
||||
|
||||
parent::setModifiers($modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,12 +34,15 @@ class EndsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%%%s'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
'%' . Convert::raw2sql($this->getValue()),
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,13 +53,15 @@ class EndsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$connectives = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$connectives[] = sprintf(
|
||||
"%s %s '%%%s'",
|
||||
$connectives[] = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($value)
|
||||
'%' . Convert::raw2sql($value),
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$whereClause = implode(' OR ', $connectives);
|
||||
@ -83,12 +75,15 @@ class EndsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s NOT %s '%%%s'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
'%' . Convert::raw2sql($this->getValue()),
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,13 +94,15 @@ class EndsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$connectives = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$connectives[] = sprintf(
|
||||
"%s NOT %s '%%%s'",
|
||||
$connectives[] = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($value)
|
||||
'%' . Convert::raw2sql($value),
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$whereClause = implode(' AND ', $connectives);
|
||||
|
@ -14,33 +14,14 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class ExactMatchFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
|
||||
public function setModifiers(array $modifiers) {
|
||||
if(($extras = array_diff($modifiers, array('not', 'nocase', 'case'))) != array()) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this) . ' does not accept ' . implode(', ', $extras) . ' as modifiers');
|
||||
}
|
||||
if(!in_array('case', $modifiers) && !in_array('nocase', $modifiers)) {
|
||||
if($exclude) {
|
||||
return '!=';
|
||||
} else {
|
||||
return '=';
|
||||
}
|
||||
} elseif(DB::getConn() instanceof PostgreSQLDatabase) {
|
||||
if(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE';
|
||||
} else {
|
||||
$comparison = 'ILIKE';
|
||||
}
|
||||
} elseif(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE BINARY';
|
||||
} else {
|
||||
$comparison = 'LIKE';
|
||||
}
|
||||
if($exclude) {
|
||||
$comparison = 'NOT ' . $comparison;
|
||||
}
|
||||
return $comparison;
|
||||
|
||||
parent::setModifiers($modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,12 +31,15 @@ class ExactMatchFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%s'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
Convert::raw2sql($this->getValue()),
|
||||
true, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,12 +50,12 @@ class ExactMatchFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$values = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$values[] = Convert::raw2sql($value);
|
||||
}
|
||||
if($this->comparison(false) == '=') {
|
||||
// Neither :case nor :nocase
|
||||
if(!in_array('case', $modifiers) && !in_array('nocase', $modifiers)) {
|
||||
$valueStr = "'" . implode("', '", $values) . "'";
|
||||
return $query->where(sprintf(
|
||||
'%s IN (%s)',
|
||||
@ -80,11 +64,12 @@ class ExactMatchFilter extends SearchFilter {
|
||||
));
|
||||
} else {
|
||||
foreach($values as &$v) {
|
||||
$v = sprintf(
|
||||
"%s %s '%s'",
|
||||
$v = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
$v
|
||||
$v,
|
||||
true, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$where = implode(' OR ', $values);
|
||||
@ -99,12 +84,15 @@ class ExactMatchFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%s'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
Convert::raw2sql($this->getValue()),
|
||||
true, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,12 +103,12 @@ class ExactMatchFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$values = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$values[] = Convert::raw2sql($value);
|
||||
}
|
||||
if($this->comparison(false) == '=') {
|
||||
// Neither :case nor :nocase
|
||||
if(!in_array('case', $modifiers) && !in_array('nocase', $modifiers)) {
|
||||
$valueStr = "'" . implode("', '", $values) . "'";
|
||||
return $query->where(sprintf(
|
||||
'%s NOT IN (%s)',
|
||||
@ -129,11 +117,12 @@ class ExactMatchFilter extends SearchFilter {
|
||||
));
|
||||
} else {
|
||||
foreach($values as &$v) {
|
||||
$v = sprintf(
|
||||
"%s %s '%s'",
|
||||
$v = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
$v
|
||||
$v,
|
||||
true, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$where = implode(' OR ', $values);
|
||||
|
@ -11,33 +11,26 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class PartialMatchFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
|
||||
public function setModifiers(array $modifiers) {
|
||||
if(($extras = array_diff($modifiers, array('not', 'nocase', 'case'))) != array()) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this) . ' does not accept ' . implode(', ', $extras) . ' as modifiers');
|
||||
}
|
||||
if(DB::getConn() instanceof PostgreSQLDatabase) {
|
||||
if(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE';
|
||||
} else {
|
||||
$comparison = 'ILIKE';
|
||||
}
|
||||
} elseif(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE BINARY';
|
||||
} else {
|
||||
$comparison = 'LIKE';
|
||||
}
|
||||
if($exclude) {
|
||||
$comparison = 'NOT ' . $comparison;
|
||||
}
|
||||
return $comparison;
|
||||
|
||||
parent::setModifiers($modifiers);
|
||||
}
|
||||
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$comparison = $this->comparison(false);
|
||||
$where = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
'%' . Convert::raw2sql($this->getValue()) . '%',
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
|
||||
return $query->where($where);
|
||||
}
|
||||
@ -45,9 +38,15 @@ class PartialMatchFilter extends SearchFilter {
|
||||
protected function applyMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$where = array();
|
||||
$comparison = $this->comparison(false);
|
||||
$modifiers = $this->getModifiers();
|
||||
foreach($this->getValue() as $value) {
|
||||
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
|
||||
$where[]= DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
'%' . Convert::raw2sql($value) . '%',
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
|
||||
return $query->where(implode(' OR ', $where));
|
||||
@ -55,8 +54,14 @@ class PartialMatchFilter extends SearchFilter {
|
||||
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$comparison = $this->comparison(true);
|
||||
$where = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
'%' . Convert::raw2sql($this->getValue()) . '%',
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
|
||||
return $query->where($where);
|
||||
}
|
||||
@ -64,9 +69,15 @@ class PartialMatchFilter extends SearchFilter {
|
||||
protected function excludeMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$where = array();
|
||||
$comparison = $this->comparison(true);
|
||||
$modifiers = $this->getModifiers();
|
||||
foreach($this->getValue() as $value) {
|
||||
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
|
||||
$where[]= DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
'%' . Convert::raw2sql($value) . '%',
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
|
||||
return $query->where(implode(' AND ', $where));
|
||||
|
@ -55,7 +55,7 @@ abstract class SearchFilter extends Object {
|
||||
// sets $this->name and $this->relation
|
||||
$this->addRelation($fullName);
|
||||
$this->value = $value;
|
||||
$this->modifiers = array_map('strtolower', $modifiers);
|
||||
$this->setModifiers($modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,5 +278,17 @@ abstract class SearchFilter extends Object {
|
||||
public function isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines case sensitivity based on {@link getModifiers()}.
|
||||
*
|
||||
* @return Mixed TRUE or FALSE to enforce sensitivity, NULL to use field collation.
|
||||
*/
|
||||
protected function getCaseSensitive() {
|
||||
$modifiers = $this->getModifiers();
|
||||
if(in_array('case', $modifiers)) return true;
|
||||
else if(in_array('nocase', $modifiers)) return false;
|
||||
else return null;
|
||||
}
|
||||
|
||||
}
|
@ -17,27 +17,14 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class StartsWithFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
|
||||
public function setModifiers(array $modifiers) {
|
||||
if(($extras = array_diff($modifiers, array('not', 'nocase', 'case'))) != array()) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this) . ' does not accept ' . implode(', ', $extras) . ' as modifiers');
|
||||
}
|
||||
if(DB::getConn() instanceof PostgreSQLDatabase) {
|
||||
if(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE';
|
||||
} else {
|
||||
$comparison = 'ILIKE';
|
||||
}
|
||||
} elseif(in_array('case', $modifiers)) {
|
||||
$comparison = 'LIKE BINARY';
|
||||
} else {
|
||||
$comparison = 'LIKE';
|
||||
}
|
||||
if($exclude) {
|
||||
$comparison = 'NOT ' . $comparison;
|
||||
}
|
||||
return $comparison;
|
||||
|
||||
parent::setModifiers($modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,12 +34,15 @@ class StartsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
Convert::raw2sql($this->getValue()) . '%',
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,13 +53,15 @@ class StartsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function applyMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$connectives = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$connectives[] = sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$connectives[] = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($value)
|
||||
Convert::raw2sql($value) . '%',
|
||||
false, // exact?
|
||||
false, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$whereClause = implode(' OR ', $connectives);
|
||||
@ -83,12 +75,15 @@ class StartsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$modifiers = $this->getModifiers();
|
||||
$where = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
Convert::raw2sql($this->getValue()) . '%',
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
return $query->where($where);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,13 +94,15 @@ class StartsWithFilter extends SearchFilter {
|
||||
*/
|
||||
protected function excludeMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$modifiers = $this->getModifiers();
|
||||
$connectives = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$connectives[] = sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$connectives[] = DB::getConn()->comparisonClause(
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($value)
|
||||
Convert::raw2sql($value) . '%',
|
||||
false, // exact?
|
||||
true, // negate?
|
||||
$this->getCaseSensitive()
|
||||
);
|
||||
}
|
||||
$whereClause = implode(' AND ', $connectives);
|
||||
|
Loading…
Reference in New Issue
Block a user