This repository has been archived by the owner on Jun 11, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Control files for GIT and composer plus removal of run-tests which do…
…esn't belong to the package
- Loading branch information
crazyone-crazycoders
committed
Jul 27, 2013
1 parent
c707de4
commit 544de00
Showing
4 changed files
with
70 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,7 @@ | ||
.htaccess | ||
error_log | ||
sftp-config*.json | ||
vendor | ||
*.phar | ||
*.phar | ||
run-documentation | ||
run-tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,190 +1,94 @@ | ||
CrazyCodr/Data/Filter | ||
===================== | ||
|
||
This package contains facilities to easily filter data from any enumerable source. | ||
This package contains facilities to easily filter data from any enumerable source. | ||
|
||
This class features, for now, a single iterator that you can use to filter out data as you iterate it. It offers slightly more complex features that the ones of a SPL FilterIterator in a sense that you can manage multiple filters at once, clear the lot, dynamically add new conditions to it as you go, etc. | ||
This class features a single filter iterator accompagnied by filter group and a closure filter adapter that you can use to filter out data as you iterate it. It offers slightly more complex features that the ones of a SPL FilterIterator in a sense that you can manage multiple filters at once, clear the lot, dynamically add new conditions to it as you go, etc. | ||
|
||
Quick documentation | ||
------------------- | ||
Why should i use it over SPL FilterIterator | ||
------------------------------------------- | ||
|
||
1. The filter class is an iterator and filters out data live as you iterate. | ||
2. You can change the filter conditions live since it doesn't pre-process the inner iterator | ||
3. Calling `where()` allows you to add conditions to the filter class, you can chain `where()` as long as you want | ||
4. You can clear all filters by calling `clearFilters()` whenever you want | ||
5. The main filter object has a type : ANY or ALL stating if all filter conditions must be met or just any | ||
6. You can create groups of filters and assign ANY or ALL | ||
1. Every class is designed to be extended to create concrete filtering classes which makes for better TDD | ||
2. The iterator can be changed live (add/remove conditions/groups) to change the behavior of the iterator | ||
3. You can use your filters outside the scope of an iteration using $filter->shouldKeep(); | ||
|
||
Whats next | ||
How to use | ||
---------- | ||
|
||
1. Rework the code for version 2, will probably not be entirely compatible with version 1. Support for object oriented filterConditions and filterConditionGroups | ||
2. Add turnOn/turnOff possibilities on each filter and filterGroup | ||
|
||
Examples | ||
-------- | ||
1. Create a datasource that can be iterated | ||
2. Create ClosureFilter objects that will execute what you want to filter out | ||
3. Create a FilterGroup and add all filters to it | ||
4. Create a FilterIterator and add the datasource and filtercontainer to it | ||
5. Iterate, rinse, repeat... | ||
|
||
**Using prepared conditions just in time** | ||
Whats next for you? | ||
------------------- | ||
|
||
The fun aspect of this class is that you can prepare filtering closures in advance, they could be simple closures in another file that you test using unit tests. In this case, we prepare those closures in advance and add the right closures to the filtering process. | ||
1. Download the package through composer "crazycodr/data-filter" and then look in the documentation directory of the package to know more about it, it's actually quite simple but so powerful | ||
2. Look at the example | ||
3. Try and build some tests using real life data such as CSV files | ||
4. Use in production | ||
|
||
```PHP | ||
A few quick examples | ||
-------------------- | ||
|
||
//Setup the filters | ||
$filterOutToyota = function($data, $key){ return $data->make != 'Toyota'; } | ||
$filterOutFord = function($data, $key){ return $data->make != 'Ford'; } | ||
$filterOutSUV = function($data, $key){ return $data->make != 'suv'; } | ||
$filterOutSubCompacts = function($data, $key){ return $data->type != 'subcompact'; } | ||
|
||
//Setup the data | ||
$data = <...> | ||
|
||
//Setup the filtering | ||
$filteredData = new \CrazyCodr\Data\Filter($data); | ||
if($_GET['filters']['make']['toyota'] == 1){ $filteredData->where($filterOutToyota); } | ||
if($_GET['filters']['make']['ford'] == 1){ $filteredData->where($filterOutToyota); } | ||
|
||
//Loop | ||
foreach($filteredData as $make) | ||
{ | ||
<...> | ||
} | ||
|
||
``` | ||
**Basic setup for all examples below** | ||
|
||
**Chaining support** | ||
|
||
CrazyCodr Data Filter supports chaining of filter functions so you can skip repeating over and over again the original object that you called when creating a filter. | ||
This code here will be used in all examples, paste it in front of each example, it will save use some display space. | ||
|
||
```PHP | ||
//You can chain the data filtering to create many conditions | ||
$data = <...>; | ||
$filteredData = new \CrazyCodr\Data\Filter($data); | ||
$filteredData | ||
->where(function($data, $key){ return $key != 'world'; }) | ||
->where(function($data, $key){ return $key != 'canada'; }) | ||
->where(function($data, $key){ return $data->user != 'crazycone'; }); | ||
include('../vendor/autoload.php'); | ||
use \CrazyCodr\Data\Filter as cdf; | ||
|
||
//Setup sample data to work with | ||
$data = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); | ||
|
||
//Create your filters, alternatively, it is better to create concrete classes, it becomes much more testable | ||
$oddNumbers = new cdf\ClosureFilter(function($data){ return ($data % 2) == 1; }); | ||
$evenNumbers = new cdf\ClosureFilter(function($data){ return ($data % 2) == 0; }); | ||
$moreThan10 = new cdf\ClosureFilter(function($data){ return $data > 10; }); | ||
$moreThan15 = new cdf\ClosureFilter(function($data){ return $data > 15; }); | ||
$lessThan10 = new cdf\ClosureFilter(function($data){ return $data < 10; }); | ||
$lessThan5 = new cdf\ClosureFilter(function($data){ return $data < 5; }); | ||
``` | ||
|
||
**Dynamically adding constraints** | ||
**Basic usage** | ||
|
||
You can add constraint as you loop. The CrazyCodr Data Filter is not a preprocessor filter, it filters as you iterate. Thus, you can add filters to it as we go. Although not the best method this code below allows you to create a dynamic distinct filter base on the model of the vehicule. | ||
The fun aspect of this class is that you can prepare filtering closures in advance, they could be simple closures in another file that you test using unit tests. In this case, we prepare those closures in advance and add the right closures to the filtering process. | ||
|
||
```PHP | ||
class CrazyCodr_Data_Filter_Example1_Mock { | ||
public $year; | ||
public $make; | ||
public $model; | ||
public $type; | ||
public function __construct($year, $make, $model, $type){ | ||
$this->year = $year; | ||
$this->make = $make; | ||
$this->model = $model; | ||
$this->type = $type; | ||
} | ||
} | ||
//Basic filter setup | ||
$filteredData = new cdf\FilterIterator(new cdf\FilterGroup(), $data); | ||
|
||
$data = array( | ||
new CrazyCodr_Data_Filter_Example1_Mock(2010, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Elantra', 'Compact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2013, 'Hyundai', 'Accent', 'SubCompact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2009, 'Hyundai', 'SantaFee', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Genesis', 'Intermediate'), | ||
); | ||
$filteredData = new \CrazyCodr\Data\Filter($data); | ||
//Display data | ||
$filteredData->addFilter($oddNumbers); | ||
foreach($filteredData as $data) | ||
{ | ||
$filterOutThisName = $data->model; | ||
$filteredData->where( | ||
function($data)use($filterOutThisName){ | ||
echo 'Filtering on '.$filterOutThisName.'<br>'; | ||
return $data->model != $filterOutThisName; | ||
} | ||
); | ||
var_dump($data); | ||
echo '<br>'; | ||
echo $data.','; | ||
} | ||
``` | ||
|
||
**Using OR / ANY constraints instead of AND / ALL** | ||
|
||
When creating the filter, you can use the second parameter to set the filter to ANY mode and use multiple conditions to add possible values to the result. | ||
|
||
```PHP | ||
class CrazyCodr_Data_Filter_Example1_Mock { | ||
public $year; | ||
public $make; | ||
public $model; | ||
public $type; | ||
public function __construct($year, $make, $model, $type){ | ||
$this->year = $year; | ||
$this->make = $make; | ||
$this->model = $model; | ||
$this->type = $type; | ||
} | ||
} | ||
|
||
$data = array( | ||
new CrazyCodr_Data_Filter_Example1_Mock(2010, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Elantra', 'Compact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2013, 'Hyundai', 'Accent', 'SubCompact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2009, 'Hyundai', 'SantaFee', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Genesis', 'Intermediate'), | ||
); | ||
$filteredData = new \CrazyCodr\Data\Filter($data, \CrazyCodr\Data\Filter::FILTER_TYPE_ANY); | ||
$filteredData->where(function($a){ return $a->make == 'Hyundai'; }); | ||
$filteredData->where(function($a){ return $a->make == 'Toyota'; }); | ||
|
||
//Will return all items that are from Toyota or Hyundai, change the type to ALL (default) and it | ||
//fails on all tests because no car can be of Toyota AND Hyundai | ||
foreach($filteredData as $data) | ||
{ | ||
var_dump($data); | ||
echo '<br>'; | ||
} | ||
Results in | ||
``` | ||
1,3,5,7,9,11,13,15,17,19, | ||
``` | ||
|
||
**Creating groups of constraints** | ||
**Support for grouped constraints** | ||
|
||
When calling `where` you can specify a name for the group of constraint to add this new filter closure under. When you do, i'll regroup all constraint of the same name under a same operator. Passing the type of constraint when calling where sets that group's constraint type | ||
By default, the FilterIterator uses a simple FilterGroup for better extension. The FilterGroup can be set to ANY mode instead of AND mode (default) and then the conditions complement each other. | ||
|
||
```PHP | ||
class CrazyCodr_Data_Filter_Example1_Mock { | ||
public $year; | ||
public $make; | ||
public $model; | ||
public $type; | ||
public function __construct($year, $make, $model, $type){ | ||
$this->year = $year; | ||
$this->make = $make; | ||
$this->model = $model; | ||
$this->type = $type; | ||
} | ||
} | ||
//You can set the filter group to use a ANY condition, by default, it uses a ALL condition | ||
$filteredData = new cdf\FilterIterator(new cdf\FilterGroup(cdf\FilterGroup::CONTAINER_TYPE_ANY), $data); | ||
|
||
$data = array( | ||
new CrazyCodr_Data_Filter_Example1_Mock(2010, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Tucson', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2012, 'Hyundai', 'Elantra', 'Compact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2013, 'Hyundai', 'Accent', 'SubCompact'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2009, 'Hyundai', 'SantaFee', 'SUV'), | ||
new CrazyCodr_Data_Filter_Example1_Mock(2011, 'Hyundai', 'Genesis', 'Intermediate'), | ||
); | ||
$filteredData = new \CrazyCodr\Data\Filter($data); | ||
$filteredData->where(function($a){ return $a->year == 2012; }); | ||
$filteredData->where(function($a){ return $a->type == 'SUV'; }, 'typeGroup', \CrazyCodr\Data\Filter::FILTER_TYPE_ANY); | ||
$filteredData->where(function($a){ return $a->type == 'Compact'; }, 'typeGroup', \CrazyCodr\Data\Filter::FILTER_TYPE_ANY); | ||
|
||
//Will return all items that are from SUV or Compact type since the group is on ANY | ||
//but will return only 2012 models because the whole filter is set on ALL | ||
//Display data | ||
$filteredData->addFilter($oddNumbers); | ||
$filteredData->addFilter($moreThan15); | ||
foreach($filteredData as $data) | ||
{ | ||
var_dump($data); | ||
echo '<br>'; | ||
echo $data.','; | ||
} | ||
``` | ||
Results in | ||
``` | ||
1,3,5,7,9,11,13,15,16,17,18,19,20, | ||
``` |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.