grom358/pharborist — pull request #178 by phenaproxima (2014-10-30 15:03:05+00:00)
Title: Wrote foundational code for the filtering API.

This is the foundation/proof-of-concept of the fluent filtering API (rolls off the tongue nicely, doesn't it?), as described, more or less, in #101.

Filters will go in the Filters sub-namespace and implement the Filter interface (which, at the moment, only enforces the __invoke method).

Node now has a filter() method, which is really just a factory method. If it's passed a node class name, it will check that said class implements FilterFactoryInterface (if no class name is passed, it will run this check on itself). If it does, it'll call the class's createFilter() static method, which returns an implementation of the Filter interface. If not, DomainException is thrown.

The filter returned by createFilter() should be configurable using a fluent syntax. It can then be passed to any of the normal filtering and traversal methods.

Filters that extend FilterBase have the concept of an "origin", which is simply the node on which createFilter() was originally called. I haven't actually used this in the proof of concept code, but the idea is to be able to do things like this:

```php
// Assume $node is a ClassNode

// Equivalent to calling $node->is(Filter::isClass('FooClass'))
$node->filter()->name('FooClass')->isMatch();
// Equivalent to $node->find() with a complex callable that filters the ClassMemberListNodes by visibility
$node->filter('\Pharborist\ClassMemberListNode')->visibility('private')->matchDescendants();
```

That is: create the filter, configure it, then execute the filter on the node which originally created it.