Filter arrays of data by any field in the array/objects

I frequently need to grab a subset of data from an array. I just stumbled over the FilterIterator which provides a nice interface to do just this. Based on this class here is a implementation which lets you perform basic filtering.

Here is an example:

$dummy_array = array(
	array( 'id' => 1, 'name' => 'Jon Doe', 'date' => '2012-01-01' ),
	array( 'id' => 2, 'name' => 'Jack Black', 'date' => '2012-02-01' ),
	array( 'id' => 3, 'name' => 'Jane Doe', 'date' => '2012-02-04' ),
	array( 'id' => 4, 'name' => 'Simon Smith', 'date' => '2012-03-01' ), 
);

echo "\nall Doe\n";
$does = simple_array_filter( $dummy_array, 'name', 'regex', '#doe$#i' );
foreach( $does as $row )
	var_export( $row );

echo "\nall in February\n";
$febs = simple_array_filter( $dummy_array )
	->add_filter( 'date', 'newer_than', '2012-02-01 00:00:00' )
	->add_filter( 'date', 'older_than', '2012-02-29 23:59:59' );
foreach( $febs as $row )
	var_export( $row );

And here is the class that makes it happen.

/**
 * Provide easy filtering iterator for arrays
 * @see: http://php.net/manual/en/class.filteriterator.php
 */
class Simple_Array_Filter extends FilterIterator {
    private $filters = array();
	private $data = array();
	
    public function __construct( $data, $filter_field = NULL, $filter_method = NULL, $filter_value = NULL ) {
		$this->data = $data;
		$iterator = $this->get_iterator();
		parent::__construct( $iterator );

		if ( ! is_null( $filter_field ) && ! is_null( $filter_method ) && ! is_null( $filter_value ) )
			$this->add_filter( $filter_field, $filter_method, $filter_value );
    }

	public function get_iterator() {
		if ( is_object( $this->data ) && method_exists( $this->data, 'getIterator' ) )
			return $this->data->getIterator();
		if ( is_array( $this->data ) ) {
			$object = new ArrayObject( $this->data );
			return $object->getIterator();
		}
		return $this->data;
    }
	
    public function accept() {
        $data = $this->getInnerIterator()->current();
		
		return $this->dispatch_filter( $data );
	}

	public function add_filter( $filter_field, $filter_method, $filter_value ) {
		$this->filters[] = array( 'filter_field' => $filter_field, 'filter_method' => $filter_method, 'filter_value' => $filter_value );
		return $this;
	}
	
	private function dispatch_filter( $data ) {
		$result = true; // by default don't filter
		foreach( $this->filters as $filter ) {
			extract( $filter );
			if ( is_object( $data ) ) {
				if ( isset( $data->{$filter_field} ) ) {
					$cmp_value = $data->{$filter_field};
				}
			} else if ( is_array( $data ) ) {
				if ( isset( $data[$filter_field] ) ) {
					$cmp_value = $data[$filter_field];
				}
			}
			
			if ( empty( $cmp_value ) )
				continue;
			
			if ( is_callable( array( &$this, $filter_method ) ) )
				$result = call_user_func( array( &$this, $filter_method ), $cmp_value, $filter_value );
			else if ( function_exists( $filter_method ) ) {
				$result = call_user_func( $filter_method, $cmp_value, $filter_value );
			}

			if ( false == $result )
				return false;
		}
		return true;
	}

	private function gt( $cmp_value, $filter_value ) {
		if ( is_numeric( $cmp_value ) )
			return (int) $cmp_value > (int) $filter_value;
		else
			return strcmp( $cmp_value, $filter_value ) > 0;
	}
	
	private function lt( $cmp_value, $filter_value ) {
		if ( is_numeric( $cmp_value ) )
			return (int) $cmp_value < (int) $filter_value;
		else
			return strcmp( $cmp_value, $filter_value ) < 0;

	}
	
	private function eq( $cmp_value, $filter_value ) {
		if ( is_numeric( $cmp_value ) )
			return (int) $cmp_value == (int) $filter_value;
		else
			return strcmp( $cmp_value, $filter_value ) == 0;

	}
	
	private function regex( $cmp_value, $filter_value ) {
		return preg_match( $filter_value, $cmp_value );
	}

	private function older_than( $cmp_value, $filter_value ) {
		if ( !is_numeric( $cmp_value ) )
			$cmp_value = strtotime( $cmp_value );
		if ( !is_numeric( $filter_value ) )
			$filter_value = strtotime( $filter_value );
		else
			$filter_value = $filter_value;

		return $cmp_value < $filter_value;
	}

	private function newer_than( $cmp_value, $filter_value ) {
		if ( !is_numeric( $cmp_value ) )
			$cmp_value = strtotime( $cmp_value );
		if ( !is_numeric( $filter_value ) )
			$filter_value = strtotime( $filter_value );
		else
			$filter_value = $filter_value;

		return $cmp_value > $filter_value;

	}
}
if ( !function_exists( 'simple_array_filter' ) ) {
	function simple_array_filter( $data, $filter_field = NULL, $filter_method = NULL, $filter_value = NULL ) {
		$simple_array_filter = new Simple_Array_Filter( $data, $filter_field, $filter_method, $filter_value );
		return $simple_array_filter;
	}
}

No comments yet... Be the first to leave a reply!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: