diff --git a/docs/en/topics/datamodel.md b/docs/en/topics/datamodel.md index 285ddb7b1..efb129516 100755 --- a/docs/en/topics/datamodel.md +++ b/docs/en/topics/datamodel.md @@ -272,7 +272,7 @@ This would be equivalent to a SQL query of 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 behavior such as `":StartsWith"`, -`":EndsWith"`, `":PartialMatch"`, `":GreaterThan"`, `":LessThan"`, +`":EndsWith"`, `":PartialMatch"`, `":GreaterThan"`, `":GreaterThanOrEqual"`, `":LessThan"`, `":LessThanOrEqual"`, `":Negation"`. Each of these suffixes is represented in the ORM as a subclass of diff --git a/search/filters/ComparisonFilter.php b/search/filters/ComparisonFilter.php new file mode 100755 index 000000000..d15dc4a2a --- /dev/null +++ b/search/filters/ComparisonFilter.php @@ -0,0 +1,79 @@ += + * + * @package framework + * @subpackage search + */ +abstract class ComparisonFilter extends SearchFilter { + + /** + * Should return an operator to be used for comparisons + * + * @return string Operator + */ + abstract protected function getOperator(); + + /** + * Should return an inverse operator to be used for comparisons + * + * @return string Inverse operator + */ + abstract protected function getInverseOperator(); + + /** + * Applies a comparison filter to the query + * Handles SQL escaping for both numeric and string values + * + * @param DataQuery $query + * @return $this|DataQuery + */ + protected function applyOne(DataQuery $query) { + $this->model = $query->applyRelation($this->relation); + $value = $this->getDbFormattedValue(); + + if(is_numeric($value)) { + $filter = sprintf("%s %s %s", + $this->getDbName(), $this->getOperator(), Convert::raw2sql($value)); + } else { + $filter = sprintf("%s %s '%s'", + $this->getDbName(), $this->getOperator(), Convert::raw2sql($value)); + } + + return $query->where($filter); + } + + /** + * Applies a exclusion(inverse) filter to the query + * Handles SQL escaping for both numeric and string values + * + * @param DataQuery $query + * @return $this|DataQuery + */ + protected function excludeOne(DataQuery $query) { + $this->model = $query->applyRelation($this->relation); + $value = $this->getDbFormattedValue(); + + if(is_numeric($value)) { + $filter = sprintf("%s %s %s", + $this->getDbName(), $this->getInverseOperator(), Convert::raw2sql($value)); + } else { + $filter = sprintf("%s %s '%s'", + $this->getDbName(), $this->getInverseOperator(), Convert::raw2sql($value)); + } + + return $query->where($filter); + } + + public function isEmpty() { + return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === ''; + } +} diff --git a/search/filters/GreaterThanFilter.php b/search/filters/GreaterThanFilter.php old mode 100644 new mode 100755 index a17c3a2f5..bd5cd3046 --- a/search/filters/GreaterThanFilter.php +++ b/search/filters/GreaterThanFilter.php @@ -2,40 +2,20 @@ /** * Selects numerical/date content greater than the input * - * @todo documentation - * + * Can be used by SearchContext and DataList->filter, eg; + * Model::get()->filter("Field1:GreaterThan", $value); + * * @package framework * @subpackage search */ -class GreaterThanFilter extends SearchFilter { - - /** - * @return DataQuery - */ - protected function applyOne(DataQuery $query) { - $this->model = $query->applyRelation($this->relation); - $value = $this->getDbFormattedValue(); +class GreaterThanFilter extends ComparisonFilter { - 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); + protected function getOperator() { + return ">"; } - /** - * @return DataQuery - */ - protected function excludeOne(DataQuery $query) { - $this->model = $query->applyRelation($this->relation); - $value = $this->getDbFormattedValue(); + protected function getInverseOperator() { + return "<="; + } - 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() === array() || $this->getValue() === null || $this->getValue() === ''; - } } diff --git a/search/filters/GreaterThanOrEqualFilter.php b/search/filters/GreaterThanOrEqualFilter.php new file mode 100755 index 000000000..e71e47130 --- /dev/null +++ b/search/filters/GreaterThanOrEqualFilter.php @@ -0,0 +1,21 @@ +filter, eg; + * Model::get()->filter("Field1:GreaterThanOrEqual", $value); + * + * @package framework + * @subpackage search + */ +class GreaterThanOrEqualFilter extends ComparisonFilter { + + protected function getOperator() { + return ">="; + } + + protected function getInverseOperator() { + return "<"; + } + +} diff --git a/search/filters/LessThanFilter.php b/search/filters/LessThanFilter.php old mode 100644 new mode 100755 index 6c9538ab8..da1a77fef --- a/search/filters/LessThanFilter.php +++ b/search/filters/LessThanFilter.php @@ -1,41 +1,21 @@ filter, eg; + * Model::get()->filter("Field1:LessThan", $value); * - * @todo documentation - * * @package framework * @subpackage search */ -class LessThanFilter extends SearchFilter { - - /** - * @return DataQuery - */ - protected function applyOne(DataQuery $query) { - $this->model = $query->applyRelation($this->relation); - $value = $this->getDbFormattedValue(); +class LessThanFilter extends ComparisonFilter { - 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); + protected function getOperator() { + return "<"; } - /** - * @return DataQuery - */ - protected function excludeOne(DataQuery $query) { - $this->model = $query->applyRelation($this->relation); - $value = $this->getDbFormattedValue(); + protected function getInverseOperator() { + return ">="; + } - 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() === array() || $this->getValue() === null || $this->getValue() === ''; - } } diff --git a/search/filters/LessThanOrEqualFilter.php b/search/filters/LessThanOrEqualFilter.php new file mode 100755 index 000000000..c77685675 --- /dev/null +++ b/search/filters/LessThanOrEqualFilter.php @@ -0,0 +1,21 @@ +filter, eg; + * Model::get()->filter("Field1:LessThanOrEqual", $value); + * + * @package framework + * @subpackage search + */ +class LessThanOrEqualFilter extends ComparisonFilter { + + protected function getOperator() { + return "<="; + } + + protected function getInverseOperator() { + return ">"; + } + +} diff --git a/tests/model/DataListTest.php b/tests/model/DataListTest.php old mode 100644 new mode 100755 index d9112dcf6..2c647260a --- a/tests/model/DataListTest.php +++ b/tests/model/DataListTest.php @@ -445,17 +445,35 @@ class DataListTest extends SapphireTest { $list = DataObjectTest_TeamComment::get(); $list = $list->filter('TeamID:GreaterThan', $this->idFromFixture('DataObjectTest_Team', 'team1')); $this->assertEquals(1, $list->count()); - $this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Bob'); + $this->assertEquals('Phil', $list->first()->Name, 'First comment should be from Phil'); } - // public function testSimpleFilterLessThanFilter() { - // $list = DataObjectTest_TeamComment::get(); - // $list = $list->filter('TeamID:LessThan', - // $this->idFromFixture('DataObjectTest_TeamComment', 'comment2'))->sort('Name'); - // $this->assertEquals(2, $list->count()); - // $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob'); - // $this->assertEquals('Joe', $list->Last()->Name, 'Last comment should be from Joe'); - // } + public function testSimpleFilterGreaterThanOrEqualFilter() { + $list = DataObjectTest_TeamComment::get(); + $list = $list->filter('TeamID:GreaterThanOrEqual', + $this->idFromFixture('DataObjectTest_Team', 'team1'))->sort("ID"); + $this->assertEquals(3, $list->count()); + $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe'); + $this->assertEquals('Phil', $list->last()->Name, 'Last comment should be from Phil'); + } + + public function testSimpleFilterLessThanFilter() { + $list = DataObjectTest_TeamComment::get(); + $list = $list->filter('TeamID:LessThan', + $this->idFromFixture('DataObjectTest_Team', 'team2'))->sort('Name'); + $this->assertEquals(2, $list->count()); + $this->assertEquals('Bob', $list->first()->Name, 'First comment should be from Bob'); + $this->assertEquals('Joe', $list->Last()->Name, 'Last comment should be from Joe'); + } + + public function testSimpleFilterLessThanOrEqualFilter() { + $list = DataObjectTest_TeamComment::get(); + $list = $list->filter('TeamID:LessThanOrEqual', + $this->idFromFixture('DataObjectTest_Team', 'team1'))->sort('ID'); + $this->assertEquals(2, $list->count()); + $this->assertEquals('Joe', $list->first()->Name, 'First comment should be from Joe'); + $this->assertEquals('Bob', $list->Last()->Name, 'Last comment should be from Bob'); + } public function testSimplePartialMatchFilter() { $list = DataObjectTest_TeamComment::get();