mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API Allow use of :not, :nocase and :case modifiers to SearchFilters.
More modifiers can be added to each class as desired.
This commit is contained in:
parent
2faf7d112d
commit
c49f7566c3
@ -205,13 +205,18 @@ This would be equivalent to a SQL query of
|
||||
|
||||
### Search Filter Modifiers
|
||||
|
||||
The where clauses showcased in the previous two sections (filter and exclude) specify case-insensitive exact
|
||||
The where clauses showcased in the previous two sections (filter and exclude) specify exact
|
||||
matches by default. However, there are a number of suffixes that you can put on field names to change this
|
||||
behaviour `":StartsWith"`, `":EndsWith"`, `":PartialMatch"`, `":GreaterThan"`, `":LessThan"`, `":Negation"`.
|
||||
|
||||
Each of these suffixes is represented in the ORM as a subclass of `[api:SearchFilter]`. Developers can define
|
||||
their own SearchFilters if needing to extend the ORM filter and exclude behaviours.
|
||||
|
||||
These suffixes can also take modifiers themselves. The modifiers currently supported are `":not"`, `":nocase"`
|
||||
and `":case"`. These negate the filter, make it case-insensitive and make it case-sensitive respectively. The
|
||||
default comparison uses the database's default. For MySQL and MSSQL, this is case-insensitive. For PostgreSQL,
|
||||
this is case-sensitive.
|
||||
|
||||
The following is a query which will return everyone whose first name doesn't start with S, who has logged in
|
||||
since 1/1/2011.
|
||||
|
||||
|
@ -374,38 +374,15 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
* Return a new instance of the list with an added filter
|
||||
*/
|
||||
public function addFilter($filterArray) {
|
||||
$SQL_Statements = array();
|
||||
foreach($filterArray as $field => $value) {
|
||||
if(is_array($value)) {
|
||||
$customQuery = 'IN (\''.implode('\',\'',Convert::raw2sql($value)).'\')';
|
||||
} else {
|
||||
$customQuery = '= \''.Convert::raw2sql($value).'\'';
|
||||
}
|
||||
|
||||
if(stristr($field,':')) {
|
||||
$fieldArgs = explode(':', $field);
|
||||
$field = array_shift($fieldArgs);
|
||||
foreach($fieldArgs as $fieldArg){
|
||||
$comparisor = $this->applyFilterContext($field, $fieldArg, $value);
|
||||
}
|
||||
} else {
|
||||
if($field == 'ID') {
|
||||
$field = sprintf('"%s"."ID"', ClassInfo::baseDataClass($this->dataClass));
|
||||
} else {
|
||||
$field = '"' . Convert::raw2sql($field) . '"';
|
||||
$filterType = array_shift($fieldArgs);
|
||||
$modifiers = $fieldArgs;
|
||||
$this->applyFilterContext($field, $filterType, $modifiers, $value);
|
||||
}
|
||||
|
||||
$SQL_Statements[] = $field . ' ' . $customQuery;
|
||||
}
|
||||
}
|
||||
|
||||
if(!count($SQL_Statements)) return $this;
|
||||
|
||||
return $this->alterDataQuery_30(function($query) use ($SQL_Statements){
|
||||
foreach($SQL_Statements as $SQL_Statement){
|
||||
$query->where($SQL_Statement);
|
||||
}
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -459,16 +436,22 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
*
|
||||
* @param string $field - the fieldname in the db
|
||||
* @param string $comparisators - example StartsWith, relates to a filtercontext
|
||||
* @param array $modifiers - Modifiers to pass to the filter, ie not,nocase
|
||||
* @param string $value - the value that the filtercontext will use for matching
|
||||
* @todo Deprecated SearchContexts and pull their functionality into the core of the ORM
|
||||
*/
|
||||
private function applyFilterContext($field, $comparisators, $value) {
|
||||
private function applyFilterContext($field, $comparisators, $modifiers, $value) {
|
||||
$t = singleton($this->dataClass())->dbObject($field);
|
||||
if($comparisators) {
|
||||
$className = "{$comparisators}Filter";
|
||||
if(!class_exists($className)){
|
||||
throw new InvalidArgumentException('There are no '.$comparisators.' comparisator');
|
||||
} else {
|
||||
$className = 'ExactMatchFilter';
|
||||
}
|
||||
$t = new $className($field,$value);
|
||||
if(!class_exists($className)){
|
||||
$className = 'ExactMatchFilter';
|
||||
array_unshift($modifiers, $comparisators);
|
||||
}
|
||||
$t = new $className($field, $value, $modifiers);
|
||||
$t->apply($this->dataQuery());
|
||||
}
|
||||
|
||||
@ -508,28 +491,22 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
|
||||
$field = array_shift($fieldArgs);
|
||||
$filterType = array_shift($fieldArgs);
|
||||
$modifiers = $fieldArgs;
|
||||
$list->excludeFilterContext($field, $filterType, $modifiers, $value, $subquery);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the comparisator to the sql query
|
||||
*
|
||||
* @param string $field - the fieldname in the db
|
||||
* @param string $comparisators - example StartsWith, relates to a filtercontext
|
||||
* @param string $value - the value that the filtercontext will use for matching
|
||||
* @param DataQuery $dataQuery - The (sub)query to add the exclusion clauses to
|
||||
* @todo Deprecated SearchContexts and pull their functionality into the core of the ORM
|
||||
*/
|
||||
private function excludeFilterContext($field, $comparisators, $modifiers, $value, $dataQuery) {
|
||||
$t = singleton($this->dataClass())->dbObject($field);
|
||||
$className = "{$comparisators}Filter";
|
||||
// This is here since PHP 5.3 can't call protected/private methods in a closure.
|
||||
$t = singleton($list->dataClass())->dbObject($field);
|
||||
if($filterType) {
|
||||
$className = "{$filterType}Filter";
|
||||
} else {
|
||||
$className = 'ExactMatchFilter';
|
||||
}
|
||||
if(!class_exists($className)){
|
||||
throw new InvalidArgumentException('There are no '.$comparisators.' comparisator');
|
||||
$className = 'ExactMatchFilter';
|
||||
array_unshift($modifiers, $filterType);
|
||||
}
|
||||
$t = new $className($field, $value, $modifiers);
|
||||
$t->exclude($dataQuery);
|
||||
$t->exclude($subquery);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,6 +17,28 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class EndsWithFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a match on the trailing characters of a field value.
|
||||
@ -28,7 +50,7 @@ class EndsWithFilter extends SearchFilter {
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%%%s'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -46,7 +68,7 @@ class EndsWithFilter extends SearchFilter {
|
||||
$connectives[] = sprintf(
|
||||
"%s %s '%%%s'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($value)
|
||||
);
|
||||
}
|
||||
@ -64,7 +86,7 @@ class EndsWithFilter extends SearchFilter {
|
||||
return $query->where(sprintf(
|
||||
"%s NOT %s '%%%s'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -82,7 +104,7 @@ class EndsWithFilter extends SearchFilter {
|
||||
$connectives[] = sprintf(
|
||||
"%s NOT %s '%%%s'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($value)
|
||||
);
|
||||
}
|
||||
|
@ -14,6 +14,34 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class ExactMatchFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an exact match (equals) on a field value.
|
||||
@ -23,8 +51,9 @@ class ExactMatchFilter extends SearchFilter {
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s = '%s'",
|
||||
"%s %s '%s'",
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -41,12 +70,26 @@ class ExactMatchFilter extends SearchFilter {
|
||||
foreach($this->getValue() as $value) {
|
||||
$values[] = Convert::raw2sql($value);
|
||||
}
|
||||
if($this->comparison(false) == '=') {
|
||||
// Neither :case nor :nocase
|
||||
$valueStr = "'" . implode("', '", $values) . "'";
|
||||
return $query->where(sprintf(
|
||||
'%s IN (%s)',
|
||||
$this->getDbName(),
|
||||
$valueStr
|
||||
));
|
||||
} else {
|
||||
foreach($values as &$v) {
|
||||
$v = sprintf(
|
||||
"%s %s '%s'",
|
||||
$this->getDbName(),
|
||||
$this->comparison(false),
|
||||
$v
|
||||
);
|
||||
}
|
||||
$where = implode(' OR ', $values);
|
||||
return $query->where($where);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,8 +100,9 @@ class ExactMatchFilter extends SearchFilter {
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s != '%s'",
|
||||
"%s %s '%s'",
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -75,12 +119,26 @@ class ExactMatchFilter extends SearchFilter {
|
||||
foreach($this->getValue() as $value) {
|
||||
$values[] = Convert::raw2sql($value);
|
||||
}
|
||||
if($this->comparison(false) == '=') {
|
||||
// Neither :case nor :nocase
|
||||
$valueStr = "'" . implode("', '", $values) . "'";
|
||||
return $query->where(sprintf(
|
||||
'%s NOT IN (%s)',
|
||||
$this->getDbName(),
|
||||
$valueStr
|
||||
));
|
||||
} else {
|
||||
foreach($values as &$v) {
|
||||
$v = sprintf(
|
||||
"%s %s '%s'",
|
||||
$this->getDbName(),
|
||||
$this->comparison(true),
|
||||
$v
|
||||
);
|
||||
}
|
||||
$where = implode(' OR ', $values);
|
||||
return $query->where($where);
|
||||
}
|
||||
}
|
||||
|
||||
public function isEmpty() {
|
||||
|
@ -13,9 +13,9 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class ExactMatchMultiFilter extends SearchFilter {
|
||||
function __construct($fullName, $value = false) {
|
||||
function __construct($fullName, $value = false, array $modifiers = array()) {
|
||||
Deprecation::notice('3.1', 'Use ExactMatchFilter instead.');
|
||||
parent::__construct($fullName, $value);
|
||||
parent::__construct($fullName, $value, $modifiers);
|
||||
}
|
||||
|
||||
public function apply(DataQuery $query) {
|
||||
@ -24,7 +24,7 @@ class ExactMatchMultiFilter extends SearchFilter {
|
||||
} else {
|
||||
$values = $this->getValue();
|
||||
}
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $values);
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->apply($query);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class ExactMatchMultiFilter extends SearchFilter {
|
||||
} else {
|
||||
$values = $this->getValue();
|
||||
}
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $values);
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->exclude($query);
|
||||
}
|
||||
|
||||
|
@ -2,28 +2,33 @@
|
||||
/**
|
||||
* Matches on rows where the field is not equal to the given value.
|
||||
*
|
||||
* @deprecated 3.1 Use ExactMatchFilter:not instead
|
||||
* @package framework
|
||||
* @subpackage search
|
||||
*/
|
||||
class NegationFilter extends SearchFilter {
|
||||
// Deprecate this once modifiers are done
|
||||
function __construct($fullName, $value = false, array $modifiers = array()) {
|
||||
Deprecation::notice('3.1', 'Use ExactMatchFilter:not instead.');
|
||||
$modifiers[] = 'not';
|
||||
parent::__construct($fullName, $value, $modifiers);
|
||||
}
|
||||
|
||||
public function apply(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s != '%s'",
|
||||
$this->getDbName(),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $this->getValue(), $this->getModifiers());
|
||||
return $filter->apply($query);
|
||||
}
|
||||
|
||||
protected function applyOne(DataQuery $query) {
|
||||
/* NO OP */
|
||||
}
|
||||
|
||||
public function exclude(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s = '%s'",
|
||||
$this->getDbName(),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
$filter = new ExactMatchFilter($this->getFullName(), $this->getValue(), $this->getModifiers());
|
||||
return $filter->exclude($query);
|
||||
}
|
||||
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
/* NO OP */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,32 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class PartialMatchFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
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;
|
||||
}
|
||||
|
||||
protected function applyOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
|
||||
$comparison = $this->comparison(false);
|
||||
$where = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
|
||||
|
||||
return $query->where($where);
|
||||
@ -23,7 +45,7 @@ class PartialMatchFilter extends SearchFilter {
|
||||
protected function applyMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$where = array();
|
||||
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
|
||||
$comparison = $this->comparison(false);
|
||||
foreach($this->getValue() as $value) {
|
||||
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
|
||||
}
|
||||
@ -33,8 +55,8 @@ class PartialMatchFilter extends SearchFilter {
|
||||
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
|
||||
$where = sprintf("%s NOT %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
|
||||
$comparison = $this->comparison(true);
|
||||
$where = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
|
||||
|
||||
return $query->where($where);
|
||||
}
|
||||
@ -42,9 +64,9 @@ class PartialMatchFilter extends SearchFilter {
|
||||
protected function excludeMany(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
$where = array();
|
||||
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
|
||||
$comparison = $this->comparison(true);
|
||||
foreach($this->getValue() as $value) {
|
||||
$where[]= sprintf("%s NOT %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
|
||||
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
|
||||
}
|
||||
|
||||
return $query->where(implode(' AND ', $where));
|
||||
|
@ -30,6 +30,11 @@ abstract class SearchFilter extends Object {
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $modifiers;
|
||||
|
||||
/**
|
||||
* @var string Name of a has-one, has-many or many-many relation (not the classname).
|
||||
* Set in the constructor as part of the name in dot-notation, and used in
|
||||
@ -43,12 +48,14 @@ abstract class SearchFilter extends Object {
|
||||
* the necessary tables (e.g. "Comments.Name" to join the "Comments" has-many relationship and
|
||||
* search the "Name" column when applying this filter to a SiteTree class).
|
||||
* @param mixed $value
|
||||
* @param array $modifiers
|
||||
*/
|
||||
public function __construct($fullName, $value = false) {
|
||||
public function __construct($fullName, $value = false, array $modifiers = array()) {
|
||||
$this->fullName = $fullName;
|
||||
// sets $this->name and $this->relation
|
||||
$this->addRelation($fullName);
|
||||
$this->value = $value;
|
||||
$this->modifiers = array_map('strtolower', $modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,6 +103,24 @@ abstract class SearchFilter extends Object {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current modifiers to apply to the filter
|
||||
*
|
||||
* @param array $modifiers
|
||||
*/
|
||||
public function setModifiers(array $modifiers) {
|
||||
$this->modifiers = array_map('strtolower', $modifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the current modifiers to apply to the filter.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getModifiers() {
|
||||
return $this->modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* The original name of the field.
|
||||
*
|
||||
@ -177,6 +202,10 @@ abstract class SearchFilter extends Object {
|
||||
* @return DataQuery
|
||||
*/
|
||||
public function apply(DataQuery $query) {
|
||||
if(($key = array_search('not', $this->modifiers)) !== false) {
|
||||
unset($this->modifiers[$key]);
|
||||
return $this->exclude($query);
|
||||
}
|
||||
if(is_array($this->value)) {
|
||||
return $this->applyMany($query);
|
||||
} else {
|
||||
@ -209,6 +238,10 @@ abstract class SearchFilter extends Object {
|
||||
* @return DataQuery
|
||||
*/
|
||||
public function exclude(DataQuery $query) {
|
||||
if(($key = array_search('not', $this->modifiers)) !== false) {
|
||||
unset($this->modifiers[$key]);
|
||||
return $this->apply($query);
|
||||
}
|
||||
if(is_array($this->value)) {
|
||||
return $this->excludeMany($query);
|
||||
} else {
|
||||
|
@ -17,6 +17,28 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class StartsWithFilter extends SearchFilter {
|
||||
protected function comparison($exclude = false) {
|
||||
$modifiers = $this->getModifiers();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a match on the starting characters of a field value.
|
||||
@ -28,7 +50,7 @@ class StartsWithFilter extends SearchFilter {
|
||||
return $query->where(sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -46,7 +68,7 @@ class StartsWithFilter extends SearchFilter {
|
||||
$connectives[] = sprintf(
|
||||
"%s %s '%s%%'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(false),
|
||||
Convert::raw2sql($value)
|
||||
);
|
||||
}
|
||||
@ -62,9 +84,9 @@ class StartsWithFilter extends SearchFilter {
|
||||
protected function excludeOne(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s NOT %s '%s%%'",
|
||||
"%s %s '%s%%'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($this->getValue())
|
||||
));
|
||||
}
|
||||
@ -80,9 +102,9 @@ class StartsWithFilter extends SearchFilter {
|
||||
$connectives = array();
|
||||
foreach($this->getValue() as $value) {
|
||||
$connectives[] = sprintf(
|
||||
"%s NOT %s '%s%%'",
|
||||
"%s %s '%s%%'",
|
||||
$this->getDbName(),
|
||||
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
|
||||
$this->comparison(true),
|
||||
Convert::raw2sql($value)
|
||||
);
|
||||
}
|
||||
|
@ -13,9 +13,9 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class StartsWithMultiFilter extends SearchFilter {
|
||||
function __construct($fullName, $value = false) {
|
||||
function __construct($fullName, $value = false, array $modifiers = array()) {
|
||||
Deprecation::notice('3.1', 'Use StartsWithFilter instead.');
|
||||
parent::__construct($fullName, $value);
|
||||
parent::__construct($fullName, $value, $modifiers);
|
||||
}
|
||||
|
||||
public function apply(DataQuery $query) {
|
||||
@ -24,7 +24,7 @@ class StartsWithMultiFilter extends SearchFilter {
|
||||
} else {
|
||||
$values = $this->getValue();
|
||||
}
|
||||
$filter = new StartsWithFilter($this->getFullName(), $values);
|
||||
$filter = new StartsWithFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->apply($query);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class StartsWithMultiFilter extends SearchFilter {
|
||||
} else {
|
||||
$values = $this->getValue();
|
||||
}
|
||||
$filter = new StartsWithFilter($this->getFullName(), $values);
|
||||
$filter = new StartsWithFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->exclude($query);
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,14 @@
|
||||
* @subpackage search
|
||||
*/
|
||||
class SubstringFilter extends PartialMatchFilter {
|
||||
public function __construct($fullName, $value = false) {
|
||||
public function __construct($fullName, $value = false, array $modifiers = array()) {
|
||||
Deprecation::notice('3.0', 'PartialMatchFilter instead.');
|
||||
parent::__construct($fullName, $value);
|
||||
parent::__construct($fullName, $value, $modifiers);
|
||||
}
|
||||
|
||||
public function apply(DataQuery $query) {
|
||||
$values = $this->getValue();
|
||||
$filter = new PartialMatchFilter($this->getFullName(), $values);
|
||||
$filter = new PartialMatchFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->apply($query);
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ class SubstringFilter extends PartialMatchFilter {
|
||||
|
||||
public function exclude(DataQuery $query) {
|
||||
$values = $this->getValue();
|
||||
$filter = new PartialMatchFilter($this->getFullName(), $values);
|
||||
$filter = new PartialMatchFilter($this->getFullName(), $values, $this->getModifiers());
|
||||
return $filter->exclude($query);
|
||||
}
|
||||
|
||||
|
@ -442,10 +442,21 @@ class DataListTest extends SapphireTest {
|
||||
$list = $list->filter(array(
|
||||
'Name'=>array('Bob','Phil'),
|
||||
'TeamID'=>array($this->idFromFixture('DataObjectTest_Team', 'team1'))));
|
||||
$this->assertEquals(1, $list->count(), 'There should be one comments');
|
||||
$this->assertEquals(1, $list->count(), 'There should be one comment');
|
||||
$this->assertEquals('Bob', $list->first()->Name, 'Only comment should be from Bob');
|
||||
}
|
||||
|
||||
public function testFilterWithModifiers() {
|
||||
$list = DataObjectTest_TeamComment::get();
|
||||
$nocaseList = $list->filter('Name:nocase', 'bob');
|
||||
$this->assertEquals(1, $nocaseList->count(), 'There should be one comment');
|
||||
$caseList = $list->filter('Name:case', 'bob');
|
||||
$this->assertEquals(0, $caseList->count(), 'There should be no comments');
|
||||
$gtList = $list->filter('TeamID:GreaterThan:not',
|
||||
$this->idFromFixture('DataObjectTest_Team', 'team1'));
|
||||
$this->assertEquals(2, $gtList->count());
|
||||
}
|
||||
|
||||
public function testFilterAndExcludeById() {
|
||||
$id = $this->idFromFixture('DataObjectTest_SubTeam', 'subteam1');
|
||||
$list = DataObjectTest_SubTeam::get()->filter('ID', $id);
|
||||
|
Loading…
x
Reference in New Issue
Block a user