API Add exclude() method to SearchFilters that excludes items that match the filter.

This commit is contained in:
Simon Welsh 2012-09-06 19:54:44 +12:00
parent 38e7df2e91
commit 79b3f8ac45
13 changed files with 408 additions and 81 deletions

View File

@ -21,9 +21,9 @@ class EndsWithFilter extends SearchFilter {
/**
* Applies a match on the trailing characters of a field value.
*
* @return unknown
* @return DataQuery
*/
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s %s '%%%s'",
@ -32,8 +32,65 @@ class EndsWithFilter extends SearchFilter {
Convert::raw2sql($this->getValue())
));
}
/**
* Applies a match on the trailing characters of a field value.
* Matches against one of the many values.
*
* @return DataQuery
*/
protected function applyMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$connectives = array();
foreach($this->getValue() as $value) {
$connectives[] = sprintf(
"%s %s '%%%s'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($value)
);
}
$whereClause = implode(' OR ', $connectives);
return $query->where($whereClause);
}
/**
* Excludes a match on the trailing characters of a field value.
*
* @return DataQuery
*/
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s NOT %s '%%%s'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($this->getValue())
));
}
/**
* Excludes a match on the trailing characters of a field value.
* Excludes a field if it matches any of the values.
*
* @return DataQuery
*/
protected function excludeMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$connectives = array();
foreach($this->getValue() as $value) {
$connectives[] = sprintf(
"%s NOT %s '%%%s'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($value)
);
}
$whereClause = implode(' AND ', $connectives);
return $query->where($whereClause);
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -18,9 +18,9 @@ class ExactMatchFilter extends SearchFilter {
/**
* Applies an exact match (equals) on a field value.
*
* @return unknown
* @return DataQuery
*/
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s = '%s'",
@ -28,8 +28,62 @@ class ExactMatchFilter extends SearchFilter {
Convert::raw2sql($this->getValue())
));
}
/**
* Applies an exact match (equals) on a field value against multiple
* possible values.
*
* @return DataQuery
*/
protected function applyMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$values = array();
foreach($this->getValue() as $value) {
$values[] = Convert::raw2sql($value);
}
$valueStr = "'" . implode("', '", $values) . "'";
return $query->where(sprintf(
'%s IN (%s)',
$this->getDbName(),
$valueStr
));
}
/**
* Excludes an exact match (equals) on a field value.
*
* @return DataQuery
*/
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s != '%s'",
$this->getDbName(),
Convert::raw2sql($this->getValue())
));
}
/**
* Excludes an exact match (equals) on a field value against multiple
* possible values.
*
* @return DataQuery
*/
protected function excludeMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$values = array();
foreach($this->getValue() as $value) {
$values[] = Convert::raw2sql($value);
}
$valueStr = "'" . implode("', '", $values) . "'";
return $query->where(sprintf(
'%s NOT IN (%s)',
$this->getDbName(),
$valueStr
));
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -7,46 +7,46 @@
/**
* Checks if a value is in a given set.
* SQL syntax used: Column IN ('val1','val2')
* @deprecated 3.1 Use ExactMatchFilter instead
*
* @todo Add negation (NOT IN)6
* @package framework
* @subpackage search
*/
class ExactMatchMultiFilter extends SearchFilter {
function __construct($fullName, $value = false) {
Deprecation::notice('3.1', 'Use ExactMatchFilter instead.');
parent::__construct($fullName, $value);
}
public function apply(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
// hack
// PREVIOUS $values = explode(',',$this->getValue());
$values = array();
if (is_string($this->getValue())) {
if (!is_array($this->getValue())) {
$values = explode(',',$this->getValue());
} else {
$values = $this->getValue();
}
else {
foreach($this->getValue() as $v) {
$values[] = $v;
}
$filter = new ExactMatchFilter($this->getFullName(), $values);
return $filter->apply($query);
}
protected function applyOne(DataQuery $query) {
/* NO OP */
}
public function exclude(DataQuery $query) {
if (!is_array($this->getValue())) {
$values = explode(',',$this->getValue());
} else {
$values = $this->getValue();
}
if(! $values) return false;
for($i = 0; $i < count($values); $i++) {
if(! is_numeric($values[$i])) {
// @todo Fix string replacement to only replace leading and tailing quotes
$values[$i] = str_replace("'", '', $values[$i]);
$values[$i] = Convert::raw2sql($values[$i]);
}
}
$SQL_valueStr = "'" . implode("','", $values) . "'";
return $query->where(sprintf(
"%s IN (%s)",
$this->getDbName(),
$SQL_valueStr
));
$filter = new ExactMatchFilter($this->getFullName(), $values);
return $filter->exclude($query);
}
protected function excludeOne(DataQuery $query) {
/* NO OP */
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -27,7 +27,7 @@
*/
class FulltextFilter extends SearchFilter {
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
return $query->where(sprintf(
"MATCH (%s) AGAINST ('%s')",
$this->getDbName(),
@ -35,7 +35,15 @@ class FulltextFilter extends SearchFilter {
));
}
protected function excludeOne(DataQuery $query) {
return $query->where(sprintf(
"NOT MATCH (%s) AGAINST ('%s')",
$this->getDbName(),
Convert::raw2sql($this->getValue())
));
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -10,9 +10,9 @@
class GreaterThanFilter extends SearchFilter {
/**
* @return $query
* @return DataQuery
*/
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$value = $this->getDbFormattedValue();
@ -21,8 +21,21 @@ class GreaterThanFilter extends SearchFilter {
return $query->where($filter);
}
/**
* @return DataQuery
*/
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$value = $this->getDbFormattedValue();
if(is_numeric($value)) $filter = sprintf("%s <= %s", $this->getDbName(), Convert::raw2sql($value));
else $filter = sprintf("%s <= '%s'", $this->getDbName(), Convert::raw2sql($value));
return $query->where($filter);
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -10,9 +10,9 @@
class LessThanFilter extends SearchFilter {
/**
* @return $query
* @return DataQuery
*/
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$value = $this->getDbFormattedValue();
@ -21,8 +21,21 @@ class LessThanFilter extends SearchFilter {
return $query->where($filter);
}
/**
* @return DataQuery
*/
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$value = $this->getDbFormattedValue();
if(is_numeric($value)) $filter = sprintf("%s >= %s", $this->getDbName(), Convert::raw2sql($value));
else $filter = sprintf("%s >= '%s'", $this->getDbName(), Convert::raw2sql($value));
return $query->where($filter);
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -6,6 +6,7 @@
* @subpackage search
*/
class NegationFilter extends SearchFilter {
// Deprecate this once modifiers are done
public function apply(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
@ -16,5 +17,13 @@ class NegationFilter extends SearchFilter {
));
}
public function exclude(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s = '%s'",
$this->getDbName(),
Convert::raw2sql($this->getValue())
));
}
}

View File

@ -12,23 +12,45 @@
*/
class PartialMatchFilter extends SearchFilter {
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
$where = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
return $query->where($where);
}
protected function applyMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$where = array();
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
if(is_array($this->getValue())) {
foreach($this->getValue() as $value) {
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
}
} else {
$where[] = sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($this->getValue()));
foreach($this->getValue() as $value) {
$where[]= sprintf("%s %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
}
return $query->where(implode(' OR ', $where));
}
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()));
return $query->where($where);
}
protected function excludeMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$where = array();
$comparison = (DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE';
foreach($this->getValue() as $value) {
$where[]= sprintf("%s NOT %s '%%%s%%'", $this->getDbName(), $comparison, Convert::raw2sql($value));
}
return $query->where(implode(' AND ', $where));
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -173,10 +173,66 @@ abstract class SearchFilter extends Object {
/**
* Apply filter criteria to a SQL query.
*
* @param SQLQuery $query
* @return SQLQuery
* @param DataQuery $query
* @return DataQuery
*/
abstract public function apply(DataQuery $query);
public function apply(DataQuery $query) {
if(is_array($this->value)) {
return $this->applyMany($query);
} else {
return $this->applyOne($query);
}
}
/**
* Apply filter criteria to a SQL query with a single value.
*
* @param DataQuery $query
* @return DataQuery
*/
abstract protected function applyOne(DataQuery $query);
/**
* Apply filter criteria to a SQL query with an array of values.
*
* @param DataQuery $query
* @return DataQuery
*/
protected function applyMany(DataQuery $query) {
throw new InvalidArgumentException(get_class($this) . "can't be used to filter by a list of items.");
}
/**
* Exclude filter criteria from a SQL query.
*
* @param DataQuery $query
* @return DataQuery
*/
public function exclude(DataQuery $query) {
if(is_array($this->value)) {
return $this->excludeMany($query);
} else {
return $this->excludeOne($query);
}
}
/**
* Exclude filter criteria from a SQL query with a single value.
*
* @param DataQuery $query
* @return DataQuery
*/
abstract protected function excludeOne(DataQuery $query);
/**
* Exclude filter criteria from a SQL query with an array of values.
*
* @param DataQuery $query
* @return DataQuery
*/
protected function excludeMany(DataQuery $query) {
throw new InvalidArgumentException(get_class($this) . "can't be used to filter by a list of items.");
}
/**
* Determines if a field has a value,

View File

@ -19,11 +19,11 @@
class StartsWithFilter extends SearchFilter {
/**
* Applies a substring match on a field value.
* Applies a match on the starting characters of a field value.
*
* @return unknown
* @return DataQuery
*/
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s %s '%s%%'",
@ -32,8 +32,65 @@ class StartsWithFilter extends SearchFilter {
Convert::raw2sql($this->getValue())
));
}
/**
* Applies a match on the starting characters of a field value.
* Matches against one of the many values.
*
* @return DataQuery
*/
protected function applyMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$connectives = array();
foreach($this->getValue() as $value) {
$connectives[] = sprintf(
"%s %s '%s%%'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($value)
);
}
$whereClause = implode(' OR ', $connectives);
return $query->where($whereClause);
}
/**
* Excludes a match on the starting characters of a field value.
*
* @return DataQuery
*/
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s NOT %s '%s%%'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($this->getValue())
));
}
/**
* Excludes a match on the starting characters of a field value.
* Excludes a field if it matches any of the values.
*
* @return DataQuery
*/
protected function excludeMany(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$connectives = array();
foreach($this->getValue() as $value) {
$connectives[] = sprintf(
"%s NOT %s '%s%%'",
$this->getDbName(),
(DB::getConn() instanceof PostgreSQLDatabase) ? 'ILIKE' : 'LIKE',
Convert::raw2sql($value)
);
}
$whereClause = implode(' AND ', $connectives);
return $query->where($whereClause);
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -6,29 +6,47 @@
/**
* Checks if a value starts with one of the items of in a given set.
* SQL syntax used: Column IN ('val1','val2')
* @deprecated 3.1 Use StartsWithFilter instead
*
* @todo Add negation (NOT IN)6
* @package framework
* @subpackage search
*/
class StartsWithMultiFilter extends SearchFilter {
function __construct($fullName, $value = false) {
Deprecation::notice('3.1', 'Use StartsWithFilter instead.');
parent::__construct($fullName, $value);
}
public function apply(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
$values = explode(',', $this->getValue());
foreach($values as $value) {
$matches[] = sprintf("%s LIKE '%s%%'",
$this->getDbName(),
Convert::raw2sql(str_replace("'", '', $value))
);
if (!is_array($this->getValue())) {
$values = explode(',',$this->getValue());
} else {
$values = $this->getValue();
}
return $query->where(implode(" OR ", $matches));
$filter = new StartsWithFilter($this->getFullName(), $values);
return $filter->apply($query);
}
protected function applyOne(DataQuery $query) {
/* NO OP */
}
public function exclude(DataQuery $query) {
if (!is_array($this->getValue())) {
$values = explode(',',$this->getValue());
} else {
$values = $this->getValue();
}
$filter = new StartsWithFilter($this->getFullName(), $values);
return $filter->exclude($query);
}
protected function excludeOne(DataQuery $query) {
/* NO OP */
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -14,20 +14,31 @@
class SubstringFilter extends PartialMatchFilter {
public function __construct($fullName, $value = false) {
Deprecation::notice('3.0', 'PartialMatchFilter instead.');
SearchFilter::__construct($fullName, $value);
parent::__construct($fullName, $value);
}
public function apply(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"LOCATE('%s', %s) != 0",
Convert::raw2sql($this->getValue()),
$this->getDbName()
));
$values = $this->getValue();
$filter = new PartialMatchFilter($this->getFullName(), $values);
return $filter->apply($query);
}
protected function applyOne(DataQuery $query) {
/* NO OP */
}
public function exclude(DataQuery $query) {
$values = $this->getValue();
$filter = new PartialMatchFilter($this->getFullName(), $values);
return $filter->exclude($query);
}
protected function excludeOne(DataQuery $query) {
/* NO OP */
}
public function isEmpty() {
return $this->getValue() == null || $this->getValue() == '';
return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
}
}

View File

@ -25,7 +25,7 @@ class WithinRangeFilter extends SearchFilter {
$this->max = $max;
}
public function apply(DataQuery $query) {
protected function applyOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s >= '%s' AND %s <= '%s'",
@ -35,6 +35,15 @@ class WithinRangeFilter extends SearchFilter {
Convert::raw2sql($this->max)
));
}
}
protected function excludeOne(DataQuery $query) {
$this->model = $query->applyRelation($this->relation);
return $query->where(sprintf(
"%s < '%s' OR %s > '%s'",
$this->getDbName(),
Convert::raw2sql($this->min),
$this->getDbName(),
Convert::raw2sql($this->max)
));
}
}