diff --git a/src/Symfony/Components/Finder/Finder.php b/src/Symfony/Components/Finder/Finder.php index 4e98c81fb279..bc053774efd0 100644 --- a/src/Symfony/Components/Finder/Finder.php +++ b/src/Symfony/Components/Finder/Finder.php @@ -29,7 +29,7 @@ * @subpackage Components_Finder * @author Fabien Potencier */ -class Finder +class Finder implements \IteratorAggregate { protected $mode = 0; protected $names = array(); @@ -42,6 +42,7 @@ class Finder protected $followLinks = false; protected $sort = false; protected $ignoreVCS = true; + protected $dirs = array(); /** * Restricts the matching to directories only. @@ -278,35 +279,64 @@ public function followLinks() /** * Searches files and directories which match defined rules. * - * @param string $dir A directory path + * @param string|array $dirs A directory path or an array of directories * - * @return \Iterator An iterator + * @return Symfony\Components\Finder The current Finder instance * - * @throws \InvalidArgumentException if the directory does not exist + * @throws \InvalidArgumentException if one of the directory does not exist */ - public function in($dir) + public function in($dirs) { - if (is_array($dir)) + if (!is_array($dirs)) { - $iterator = new \AppendIterator(); - foreach ($dir as $d) + $dirs = array($dirs); + } + + foreach ($dirs as $dir) + { + if (!is_dir($dir)) { - $iterator->append($this->searchInDirectory($d)); + throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); } - - return $iterator; } - return $this->searchInDirectory($dir); + $this->dirs = array_merge($this->dirs, $dirs); + + return $this; } - protected function searchInDirectory($dir) + /** + * Returns an Iterator for the current Finder configuration. + * + * This method implements the IteratorAggregate interface. + * + * @return \Iterator An iterator + * + * @throws \LogicException if the in() method has not been called + */ + public function getIterator() { - if (!is_dir($dir)) + if (0 === count($this->dirs)) { - throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); + throw new \LogicException('You must call the in() method before iterating over a Finder.'); } + if (1 === count($this->dirs)) + { + return $this->searchInDirectory($this->dirs[0]); + } + + $iterator = new \AppendIterator(); + foreach ($this->dirs as $dir) + { + $iterator->append($this->searchInDirectory($dir)); + } + + return $iterator; + } + + protected function searchInDirectory($dir) + { $flags = \FilesystemIterator::SKIP_DOTS; if ($this->followLinks) diff --git a/tests/Symfony/Tests/Components/Finder/FinderTest.php b/tests/Symfony/Tests/Components/Finder/FinderTest.php index 51e9109f5b05..605c923d3b5c 100644 --- a/tests/Symfony/Tests/Components/Finder/FinderTest.php +++ b/tests/Symfony/Tests/Components/Finder/FinderTest.php @@ -30,40 +30,40 @@ public function testDirectories() { $finder = new Finder(); $this->assertSame($finder, $finder->directories()); - $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $finder->directories(); $finder->files(); $finder->directories(); - $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testFiles() { $finder = new Finder(); $this->assertSame($finder, $finder->files()); - $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $finder->files(); $finder->directories(); $finder->files(); - $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } public function testMaxDepth() { $finder = new Finder(); $this->assertSame($finder, $finder->maxDepth(0)); - $this->assertIterator($this->toAbsolute(array('foo', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $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->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo/bar.tmp')), $finder->in(self::$tmpDir)->getIterator()); } public function testMinMaxDepth() @@ -71,91 +71,91 @@ public function testMinMaxDepth() $finder = new Finder(); $finder->maxDepth(0); $finder->minDepth(1); - $this->assertIterator(array(), $finder->in(self::$tmpDir)); + $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator()); } public function testName() { $finder = new Finder(); $this->assertSame($finder, $finder->name('*.php')); - $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $finder->name('test.ph*'); $finder->name('test.py'); - $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } public function testNotName() { $finder = new Finder(); $this->assertSame($finder, $finder->notName('*.php')); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $finder->notName('*.php'); $finder->notName('*.py'); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'toto')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $finder->name('test.ph*'); $finder->name('test.py'); $finder->notName('*.php'); $finder->notName('*.py'); - $this->assertIterator(array(), $finder->in(self::$tmpDir)); + $this->assertIterator(array(), $finder->in(self::$tmpDir)->getIterator()); } public function testSize() { $finder = new Finder(); $this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500')); - $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('test.php')), $finder->in(self::$tmpDir)->getIterator()); } public function testExclude() { $finder = new Finder(); $this->assertSame($finder, $finder->exclude('foo')); - $this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testIgnoreVCS() { $finder = new Finder(); $this->assertSame($finder, $finder->ignoreVCS(false)); - $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); $finder = new Finder(); $this->assertSame($finder, $finder->ignoreVCS(true)); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testSortByName() { $finder = new Finder(); $this->assertSame($finder, $finder->sortByName()); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testSortByType() { $finder = new Finder(); $this->assertSame($finder, $finder->sortByType()); - $this->assertIterator($this->toAbsolute(array('foo', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'toto', 'foo/bar.tmp', 'test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } public function testSort() { $finder = new Finder(); $this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealpath(), $b->getRealpath()); })); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testFilter() { $finder = new Finder(); $this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return preg_match('/test/', $f) > 0; })); - $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('test.php', 'test.py')), $finder->in(self::$tmpDir)->getIterator()); } public function testFollowLinks() @@ -167,7 +167,7 @@ public function testFollowLinks() $finder = new Finder(); $this->assertSame($finder, $finder->followLinks()); - $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)); + $this->assertIterator($this->toAbsolute(array('foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto')), $finder->in(self::$tmpDir)->getIterator()); } public function testIn() @@ -184,11 +184,41 @@ public function testIn() } $finder = new Finder(); - $iterator = $finder->files()->name('*.php')->maxDepth(0)->in(array(self::$tmpDir, __DIR__)); + $iterator = $finder->files()->name('*.php')->maxDepth(0)->in(array(self::$tmpDir, __DIR__))->getIterator(); $this->assertIterator(array(self::$tmpDir.'test.php', __DIR__.'/FinderTest.php', __DIR__.'/GlobTest.php', __DIR__.'/NumberCompareTest.php'), $iterator); } + public function testGetIterator() + { + $finder = new Finder(); + try + { + $finder->getIterator(); + $this->fail('->getIterator() throws a \LogicException if the in() method has not been called'); + } + catch (\Exception $e) + { + $this->assertInstanceOf('LogicException', $e, '->getIterator() throws a \LogicException if the in() method has not been called'); + } + + $finder = new Finder(); + $dirs = array(); + foreach ($finder->directories()->in(self::$tmpDir) as $dir) + { + $dirs[] = (string) $dir; + } + + $this->assertEquals($this->toAbsolute(array('foo', 'toto')), $dirs, 'implements the \IteratorAggregate interface'); + + $finder = new Finder(); + $this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface'); + + $finder = new Finder(); + $a = iterator_to_array($finder->directories()->in(self::$tmpDir)); + $this->assertEquals($this->toAbsolute(array('foo', 'toto')), array_values(array_map(function ($a) { return (string) $a; }, $a)), 'implements the \IteratorAggregate interface'); + } + protected function toAbsolute($files) { $f = array();