diff --git a/src/Symfony/Components/Finder/Comparator/Comparator.php b/src/Symfony/Components/Finder/Comparator/Comparator.php index 747894186e81..28229180d761 100644 --- a/src/Symfony/Components/Finder/Comparator/Comparator.php +++ b/src/Symfony/Components/Finder/Comparator/Comparator.php @@ -21,13 +21,43 @@ class Comparator { protected $target; - protected $operator; + protected $operator = '=='; + /** + * Gets the target value. + * + * @return string The target value + */ + public function getTarget() + { + return $this->target; + } + + /** + * Sets the target value. + * + * @param string $target The target value + */ public function setTarget($target) { $this->target = $target; } + /** + * Gets the comparison operator. + * + * @return string The operator + */ + public function getOperator() + { + return $this->operator; + } + + /** + * Sets the comparison operator. + * + * @param string $operator A valid operator + */ public function setOperator($operator) { if (!$operator) { diff --git a/src/Symfony/Components/Finder/Comparator/NumberComparator.php b/src/Symfony/Components/Finder/Comparator/NumberComparator.php index 536eaa1f9005..4ffa28704c24 100644 --- a/src/Symfony/Components/Finder/Comparator/NumberComparator.php +++ b/src/Symfony/Components/Finder/Comparator/NumberComparator.php @@ -12,7 +12,7 @@ */ /** - * NumberCompare compiles a simple comparison to an anonymous + * NumberComparator compiles a simple comparison to an anonymous * subroutine, which you can call with a value to be tested again. * * Now this would be very pointless, if NumberCompare didn't understand diff --git a/src/Symfony/Components/Finder/Finder.php b/src/Symfony/Components/Finder/Finder.php index 6aed469068b6..c43f781ecfb8 100644 --- a/src/Symfony/Components/Finder/Finder.php +++ b/src/Symfony/Components/Finder/Finder.php @@ -16,14 +16,12 @@ * * It is a thin wrapper around several specialized iterator classes. * - * All rules may be invoked several times, except for ->in() method. - * Some rules are cumulative (->name() for example) whereas others are destructive - * (most recent value is used, ->maxDepth() method for example). + * All rules may be invoked several times. * * All methods return the current Finder object to allow easy chaining: * * $finder = new Finder(); - * $iterator = $finder->files()->name('*.php')->in(__DIR__); + * $finder = $finder->files()->name('*.php')->in(__DIR__); * * @package Symfony * @subpackage Components_Finder @@ -36,8 +34,7 @@ class Finder implements \IteratorAggregate protected $notNames = array(); protected $exclude = array(); protected $filters = array(); - protected $minDepth = 0; - protected $maxDepth = INF; + protected $depths = array(); protected $sizes = array(); protected $followLinks = false; protected $sort = false; @@ -70,37 +67,23 @@ public function files() } /** - * Sets the maximum directory depth. + * Adds tests for the directory depth. * - * The Finder will descend at most $level levels of directories below the starting point. + * Usage: * - * @param int $level The max depth + * $finder->depth('> 1') // the Finder will start matching at level 1. + * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. * - * @return Symfony\Components\Finder The current Finder instance - * - * @see Symfony\Components\Finder\Iterator\LimitDepthFilterIterator - */ - public function maxDepth($level) - { - $this->maxDepth = (double) $level; - - return $this; - } - - /** - * Sets the minimum directory depth. - * - * The Finder will start matching at level $level. - * - * @param int $level The min depth + * @param int $level The depth level expression * * @return Symfony\Components\Finder The current Finder instance * - * @see Symfony\Components\Finder\Iterator\LimitDepthFilterIterator + * @see Symfony\Components\Finder\Iterator\DepthRangeFilterIterator + * @see Symfony\Components\Finder\Comparator\NumberComparator */ - public function minDepth($level) + public function depth($level) { - $this->minDepth = (integer) $level; + $this->depths[] = new Comparator\NumberComparator($level); return $this; } @@ -365,8 +348,8 @@ protected function searchInDirectory($dir) $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, $flags), \RecursiveIteratorIterator::SELF_FIRST); - if ($this->minDepth > 0 || $this->maxDepth < INF) { - $iterator = new Iterator\LimitDepthFilterIterator($iterator, $this->minDepth, $this->maxDepth); + if ($this->depths) { + $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->depths); } if ($this->mode) { diff --git a/src/Symfony/Components/Finder/Iterator/DateRangeFilterIterator.php b/src/Symfony/Components/Finder/Iterator/DateRangeFilterIterator.php index 80065d28a55b..5a57735628b7 100644 --- a/src/Symfony/Components/Finder/Iterator/DateRangeFilterIterator.php +++ b/src/Symfony/Components/Finder/Iterator/DateRangeFilterIterator.php @@ -20,17 +20,17 @@ */ class DateRangeFilterIterator extends \FilterIterator { - protected $patterns = array(); + protected $comparators = array(); /** * Constructor. * - * @param \Iterator $iterator The Iterator to filter - * @param array $patterns An array of \DateCompare instances + * @param \Iterator $iterator The Iterator to filter + * @param array $comparators An array of \DateCompare instances */ - public function __construct(\Iterator $iterator, array $patterns) + public function __construct(\Iterator $iterator, array $comparators) { - $this->patterns = $patterns; + $this->comparators = $comparators; parent::__construct($iterator); } @@ -49,7 +49,7 @@ public function accept() } $filedate = $fileinfo->getMTime(); - foreach ($this->patterns as $compare) { + foreach ($this->comparators as $compare) { if (!$compare->test($filedate)) { return false; } diff --git a/src/Symfony/Components/Finder/Iterator/DepthRangeFilterIterator.php b/src/Symfony/Components/Finder/Iterator/DepthRangeFilterIterator.php new file mode 100644 index 000000000000..2902c914a56e --- /dev/null +++ b/src/Symfony/Components/Finder/Iterator/DepthRangeFilterIterator.php @@ -0,0 +1,69 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * DepthRangeFilterIterator limits the directory depth. + * + * @package Symfony + * @subpackage Components_Finder + * @author Fabien Potencier + */ +class DepthRangeFilterIterator extends \FilterIterator +{ + protected $minDepth = 0; + + /** + * Constructor. + * + * @param \Iterator $iterator The Iterator to filter + * @param array $comparators An array of \NumberComparator instances + */ + public function __construct(\RecursiveIteratorIterator $iterator, array $comparators) + { + $minDepth = 0; + $maxDepth = INF; + foreach ($comparators as $comparator) { + switch ($comparator->getOperator()) { + case '>': + $minDepth = $comparator->getTarget() + 1; + break; + case '>=': + $minDepth = $comparator->getTarget(); + break; + case '<': + $maxDepth = $comparator->getTarget() - 1; + break; + case '<=': + $maxDepth = $comparator->getTarget(); + break; + default: + $minDepth = $maxDepth = $comparator->getTarget(); + } + } + + $this->minDepth = $minDepth; + $iterator->setMaxDepth(INF === $maxDepth ? -1 : $maxDepth); + + parent::__construct($iterator); + } + + /** + * Filters the iterator values. + * + * @return Boolean true if the value should be kept, false otherwise + */ + public function accept() + { + return $this->getInnerIterator()->getDepth() >= $this->minDepth; + } +} diff --git a/src/Symfony/Components/Finder/Iterator/LimitDepthFilterIterator.php b/src/Symfony/Components/Finder/Iterator/LimitDepthFilterIterator.php deleted file mode 100644 index 16021b2ec06c..000000000000 --- a/src/Symfony/Components/Finder/Iterator/LimitDepthFilterIterator.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * LimitDepthFilterIterator limits the directory depth. - * - * @package Symfony - * @subpackage Components_Finder - * @author Fabien Potencier - */ -class LimitDepthFilterIterator extends \FilterIterator -{ - protected $minDepth = 0; - - /** - * Constructor. - * - * @param \Iterator $iterator The Iterator to filter - * @param integer $minDepth The minimum depth - * @param integer $maxDepth The maximum depth - */ - public function __construct(\RecursiveIteratorIterator $iterator, $minDepth, $maxDepth) - { - $this->minDepth = (integer) $minDepth; - - $iterator->setMaxDepth(INF === $maxDepth ? -1 : $maxDepth); - - parent::__construct($iterator); - } - - /** - * Filters the iterator values. - * - * @return Boolean true if the value should be kept, false otherwise - */ - public function accept() - { - return $this->getInnerIterator()->getDepth() >= $this->minDepth; - } -} diff --git a/src/Symfony/Components/Finder/Iterator/SizeRangeFilterIterator.php b/src/Symfony/Components/Finder/Iterator/SizeRangeFilterIterator.php index 9d4653a9a1d7..24495fe7ea19 100644 --- a/src/Symfony/Components/Finder/Iterator/SizeRangeFilterIterator.php +++ b/src/Symfony/Components/Finder/Iterator/SizeRangeFilterIterator.php @@ -20,17 +20,17 @@ */ class SizeRangeFilterIterator extends \FilterIterator { - protected $patterns = array(); + protected $comparators = array(); /** * Constructor. * - * @param \Iterator $iterator The Iterator to filter - * @param array $patterns An array of \NumberCompare instances + * @param \Iterator $iterator The Iterator to filter + * @param array $comparators An array of \NumberComparator instances */ - public function __construct(\Iterator $iterator, array $patterns) + public function __construct(\Iterator $iterator, array $comparators) { - $this->patterns = $patterns; + $this->comparators = $comparators; parent::__construct($iterator); } @@ -49,7 +49,7 @@ public function accept() } $filesize = $fileinfo->getSize(); - foreach ($this->patterns as $compare) { + foreach ($this->comparators as $compare) { if (!$compare->test($filesize)) { return false; } diff --git a/tests/Symfony/Tests/Components/Finder/Comparator/ComparatorTest.php b/tests/Symfony/Tests/Components/Finder/Comparator/ComparatorTest.php index 53b8c5fdbe90..6cf7e20b9f26 100644 --- a/tests/Symfony/Tests/Components/Finder/Comparator/ComparatorTest.php +++ b/tests/Symfony/Tests/Components/Finder/Comparator/ComparatorTest.php @@ -15,7 +15,7 @@ class ComparatorTest extends \PHPUnit_Framework_TestCase { - public function testSetOperator() + public function testGetSetOperator() { $comparator = new Comparator(); try { @@ -24,6 +24,17 @@ public function testSetOperator() } catch (\Exception $e) { $this->assertInstanceOf('InvalidArgumentException', $e, '->setOperator() throws an \InvalidArgumentException if the operator is not valid.'); } + + $comparator = new Comparator(); + $comparator->setOperator('>'); + $this->assertEquals('>', $comparator->getOperator(), '->getOperator() returns the current operator'); + } + + public function testGetSetTarget() + { + $comparator = new Comparator(); + $comparator->setTarget(8); + $this->assertEquals(8, $comparator->getTarget(), '->getTarget() returns the target'); } /** diff --git a/tests/Symfony/Tests/Components/Finder/FinderTest.php b/tests/Symfony/Tests/Components/Finder/FinderTest.php index ff0d49dead50..12a7bc3da9ed 100644 --- a/tests/Symfony/Tests/Components/Finder/FinderTest.php +++ b/tests/Symfony/Tests/Components/Finder/FinderTest.php @@ -52,25 +52,22 @@ public function testFiles() $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } - public function testMaxDepth() + public function testDepth() { $finder = new Finder(); - $this->assertSame($finder, $finder->maxDepth(0)); + $this->assertSame($finder, $finder->depth('< 1')); $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); - } - public function testMinDepth() - { $finder = new Finder(); - $this->assertSame($finder, $finder->minDepth(1)); + $this->assertSame($finder, $finder->depth('<= 0')); + $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); + + $finder = new Finder(); + $this->assertSame($finder, $finder->depth('>= 1')); $this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator()); - } - public function testMinMaxDepth() - { $finder = new Finder(); - $finder->maxDepth(0); - $finder->minDepth(1); + $finder->depth('< 1')->depth('>= 1'); $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator()); } @@ -187,7 +184,7 @@ public function testIn() } $finder = new Finder(); - $iterator = $finder->files()->name('*.php')->maxDepth(0)->in(array(self::$tmpDir, __DIR__))->getIterator(); + $iterator = $finder->files()->name('*.php')->depth('< 1')->in(array(self::$tmpDir, __DIR__))->getIterator(); $this->assertIterator(array(self::$tmpDir.'test.php', __DIR__.'/FinderTest.php', __DIR__.'/GlobTest.php'), $iterator); } diff --git a/tests/Symfony/Tests/Components/Finder/Iterator/DepthRangeIteratorTest.php b/tests/Symfony/Tests/Components/Finder/Iterator/DepthRangeIteratorTest.php new file mode 100644 index 000000000000..612c15f4c851 --- /dev/null +++ b/tests/Symfony/Tests/Components/Finder/Iterator/DepthRangeIteratorTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Components\Finder\Iterator; + +use Symfony\Components\Finder\Iterator\DepthRangeFilterIterator; +use Symfony\Components\Finder\Comparator\NumberComparator; + +require_once __DIR__.'/RealIteratorTestCase.php'; + +class DepthRangeFilterIteratorTest extends RealIteratorTestCase +{ + /** + * @dataProvider getAcceptData + */ + public function testAccept($size, $expected) + { + $inner = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(sys_get_temp_dir().'/symfony2_finder', \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST); + + $iterator = new DepthRangeFilterIterator($inner, $size); + + $actual = array_keys(iterator_to_array($iterator)); + sort($expected); + sort($actual); + $this->assertEquals($expected, $actual); + } + + public function getAcceptData() + { + return array( + array(array(new NumberComparator('< 1')), array(sys_get_temp_dir().'/symfony2_finder/.git', sys_get_temp_dir().'/symfony2_finder/test.py', sys_get_temp_dir().'/symfony2_finder/foo', sys_get_temp_dir().'/symfony2_finder/test.php', sys_get_temp_dir().'/symfony2_finder/toto')), + array(array(new NumberComparator('<= 1')), array(sys_get_temp_dir().'/symfony2_finder/.git', sys_get_temp_dir().'/symfony2_finder/test.py', sys_get_temp_dir().'/symfony2_finder/foo', sys_get_temp_dir().'/symfony2_finder/foo/bar.tmp', sys_get_temp_dir().'/symfony2_finder/test.php', sys_get_temp_dir().'/symfony2_finder/toto')), + array(array(new NumberComparator('> 1')), array()), + array(array(new NumberComparator('>= 1')), array(sys_get_temp_dir().'/symfony2_finder/foo/bar.tmp')), + array(array(new NumberComparator('1')), array(sys_get_temp_dir().'/symfony2_finder/foo/bar.tmp')), + ); + } +}