crazycodr/data-filter

此包已被废弃,不再维护。没有建议的替代包。

用于使用比 filter iterator spl 类更灵活的模式从可枚举源过滤数据

2.0.2 2013-08-22 15:57 UTC

This package is auto-updated.

Last update: 2022-02-01 12:26:14 UTC


README

此包包含从任何可枚举源轻松过滤实时迭代数据的工具。

此类具有一个过滤器迭代器,并附带不同的过滤器/过滤器组,您可以使用它们从任何可迭代数据源过滤传入的数据。通过此类包,您可以创建简单的或复杂的过滤器组,过滤器还可以在运行时修改,因为它是一个迭代器上的迭代器。

目录

  1. 安装
  2. 创建基本过滤迭代器
  3. 同时支持多个过滤器
  4. 构建复杂的过滤组
  5. 在迭代器上下文之外使用组件
  6. 创建可测试的类

安装

要安装它,只需将此需求包含到您的 composer.json 中

{
    "require": {
        "crazycodr/data-filter": "2.*"
    }
}

然后根据需要运行 composer install/update。

创建基本过滤迭代器

创建过滤迭代器至少需要三项

  1. 一个 FilterGroup,用于包含迭代器的不同过滤器
  2. 一个 FilterIterator,用于迭代您的数据并提供过滤功能
  3. 一个 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'),
			),
		);
	}
	
}