crazycodr / data-filter
用于使用比 filter iterator spl 类更灵活的模式从可枚举源过滤数据
Requires (Dev)
- phpdocumentor/phpdocumentor: 2.*
- phpunit/phpunit: 3.7.*
README
此包包含从任何可枚举源轻松过滤实时迭代数据的工具。
此类具有一个过滤器迭代器,并附带不同的过滤器/过滤器组,您可以使用它们从任何可迭代数据源过滤传入的数据。通过此类包,您可以创建简单的或复杂的过滤器组,过滤器还可以在运行时修改,因为它是一个迭代器上的迭代器。
目录
安装
要安装它,只需将此需求包含到您的 composer.json 中
{ "require": { "crazycodr/data-filter": "2.*" } }
然后根据需要运行 composer install/update。
创建基本过滤迭代器
创建过滤迭代器至少需要三项
- 一个 FilterGroup,用于包含迭代器的不同过滤器
- 一个 FilterIterator,用于迭代您的数据并提供过滤功能
- 一个 Filter,用于检测当前数据是否应保留或从迭代中丢弃
(注意:此代码假设您有一个基于数组的源数据,具有:名称、类型、性别和年龄列)
//Create the male only filter $maleOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'male'; }); $sexBasedFilter = new FilterIterator(new FilterGroup(), $data); $sexBasedFilter->addFilter($maleOnlyFilter); //Iterate our data source and automatically only get males foreach($sexBasedFilter as $employee) { echo 'Employee: '.$employee['name'].'<br>'; }
同时支持多个过滤器
库同时支持多个过滤器,并将尊重短路模式。(条件只有在必要时才会完全评估)
在这种情况下,我们必须将 FilterGroup 切换到 "ANY" 模式,否则没有任何东西会通过。
//Create the male only filter and the "female is called julie" $maleOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'male'; }); $julieFemalesOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'female' && $a['name'] == 'Julie'; }); $sexBasedFilter = new FilterIterator(new FilterGroup(FilterGroup::CONTAINER_TYPE_ANY), $data); $sexBasedFilter->addFilter($maleOnlyFilter); $sexBasedFilter->addFilter($julieFemalesOnlyFilter); //Iterate our data source and automatically only get males or females called Julie foreach($sexBasedFilter as $employee) { echo 'Employee: '.$employee['name'].'<br>'; }
构建复杂的过滤组
最后一个示例显示了添加许多条件的闭包过滤器。如果您想将其分解或组合成许多不同的闭包过滤器,如以下所示怎么办?
- 男性或30岁或以下
- 仅男性
- 30岁或以下
- 女性或30岁以上
- 仅女性
- 30岁以上
//Setup the basic filters $maleOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'male'; }); $femalesOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'female'; }); $age30OrLess = new ClosureFilter(function($a){ return $a['age'] <= 30; }); $age30OrMore = new ClosureFilter(function($a){ return $a['age'] >= 30; }); //Setup the groups $fullMaleFilter = new FilterGroup(); $fullFemaleFilter = new FilterGroup(); $fullMaleFilter->addFilter($maleOnlyFilter); $fullMaleFilter->addFilter($age30OrLess); $fullFemaleFilter->addFilter($femalesOnlyFilter); $fullFemaleFilter->addFilter($age30OrMore); //Create the master filter $sexBasedFilter = new FilterIterator(new FilterGroup(FilterGroup::CONTAINER_TYPE_ANY), $data); $sexBasedFilter->addFilter($fullMaleFilter); $sexBasedFilter->addFilter($fullFemaleFilter); //Iterate our data source and automatically only get males of 30 or less or females of 30 or more foreach($sexBasedFilter as $employee) { echo 'Employee: '.$employee['name'].'<br>'; }
要记住的重要方面是,默认情况下,FilterGroups 是 "ALL" 组,当需要时必须将其更改为 "ANY" 组。
在迭代器上下文之外使用组件
您不需要使用过滤迭代器... ClosureFilter 和 FilterGroup 可以在循环之外使用。通常使用具体的/非具体的类构建条件,并使用一些数据调用 "shouldKeep"。
//Create the male only filter and the "female is called julie" $maleOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'male'; }); $julieFemalesOnlyFilter = new ClosureFilter(function($a){ return $a['sex'] == 'female' && $a['name'] == 'Julie'; }); $filter = new FilterGroup(FilterGroup::CONTAINER_TYPE_ANY); $filter->addFilter($maleOnlyFilter); $filter->addFilter($julieFemalesOnlyFilter); if($filter->shouldKeep($data)) { //Do something }
创建自己的可测试类
此库的目的是不必每次都创建迭代器和它们子组件,并能够轻松地测试所有内容。为此,只需创建迭代器和子组件的具体扩展,然后进行测试即可。
class MaleOnlyFilter extends ClosureFilter { public function __construct() { parent::__construct(new ClosureFilter(function($a){ return $a['sex'] == 'male'; })); } }
class FemaleOnlyFilter extends ClosureFilter { public function __construct() { parent::__construct(new ClosureFilter(function($a){ return $a['sex'] == 'female'; })); } }
class SexBasedFilterIterator extends FilterIterator { public function __construct($data) { parent::__construct(new FilterGroup(), $data); $this->addFilter(new MaleOnlyFilter()); $this->addFilter(new FemaleOnlyFilter()); } }
这可能看起来有些极端,但这种方式可以创建一个可重用和可测试的实体类。请注意,数据提供者(DataProviders)是测试组件的一个好方法,但当测试迭代器时,使用数据提供者看起来会显得很奇怪。
class MaleOnlyFilterTest extends PHPUnit_Framework_TestCase { /** * @dataProvider maleOnlyFilterDataProvider */ public function testShouldKeep($data) { $filter = new MaleOnlyFilter(); $this->assertEquals($data['expected'], $filter->shouldKeep($data['testdata'])); } public function maleOnlyFilterDataProvider() { return array( array( 'expected' => true, 'testdata' => array('name' => 'John doe', 'age' => 35, 'sex' => 'male'), ), array( 'expected' => false, 'testdata' => array('name' => 'Jone doe', 'age' => 30, 'sex' => 'female'), ), ); } }