minor #15824 [Finder] Fix recursive filter iterator (nicolas-grekas)

This PR was merged into the 2.3 branch.

Discussion
----------

[Finder] Fix recursive filter iterator

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #15802
| License       | MIT
| Doc PR        | -

#15802 was broken because the filters where not propagated to children iterators. This fixes the issue and adds a test case for this situation. The RecursiveIterator implementation is moved from FilterIterator to ExcludeDirectoryFilterIterator. Doing so on other filters is possible but would be a new feature that is not required for fixing the performance issue we had previously.

Commits
-------

cf3019b [Finder] Fix recursive filter iterator
This commit is contained in:
Nicolas Grekas 2015-09-17 14:15:24 +02:00
commit 4a9676b5a2
10 changed files with 38 additions and 16 deletions

View File

@ -16,8 +16,9 @@ namespace Symfony\Component\Finder\Iterator;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExcludeDirectoryFilterIterator extends FilterIterator
class ExcludeDirectoryFilterIterator extends FilterIterator implements \RecursiveIterator
{
private $isRecursive;
private $patterns;
/**
@ -28,6 +29,7 @@ class ExcludeDirectoryFilterIterator extends FilterIterator
*/
public function __construct(\Iterator $iterator, array $directories)
{
$this->isRecursive = $iterator instanceof \RecursiveIterator;
$this->patterns = array();
foreach ($directories as $directory) {
$this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
@ -53,4 +55,17 @@ class ExcludeDirectoryFilterIterator extends FilterIterator
return true;
}
public function hasChildren()
{
return $this->isRecursive && $this->getInnerIterator()->hasChildren();
}
public function getChildren()
{
$children = new self($this->getInnerIterator()->getChildren(), array());
$children->patterns = $this->patterns;
return $children;
}
}

View File

@ -18,18 +18,8 @@ namespace Symfony\Component\Finder\Iterator;
*
* @author Alex Bogomazov
*/
abstract class FilterIterator extends \FilterIterator implements \RecursiveIterator
abstract class FilterIterator extends \FilterIterator
{
public function hasChildren()
{
return $this->getInnerIterator() instanceof \RecursiveIterator && $this->getInnerIterator()->hasChildren();
}
public function getChildren()
{
return $this->getInnerIterator()->getChildren();
}
/**
* This is a workaround for the problem with \FilterIterator leaving inner \FilesystemIterator in wrong state after
* rewind in some cases.

View File

@ -152,11 +152,11 @@ class FinderTest extends Iterator\RealIteratorTestCase
{
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder();
$finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
@ -167,11 +167,11 @@ class FinderTest extends Iterator\RealIteratorTestCase
{
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder();
$finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$this->assertIterator($this->toAbsolute(array('.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar')), $finder->in(self::$tmpDir)->getIterator());
$finder = $this->buildFinder();
$this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));

View File

@ -37,6 +37,7 @@ class DateRangeFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'.bar',
'.foo',
'.foo/.bar',
@ -49,6 +50,7 @@ class DateRangeFilterIteratorTest extends RealIteratorTestCase
'test.py',
'foo',
'toto',
'toto/.git',
'.bar',
'.foo',
'.foo/.bar',
@ -62,6 +64,7 @@ class DateRangeFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'.foo',
);

View File

@ -50,6 +50,7 @@ class DepthRangeFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'.foo',
'.foo/.bar',
'.bar',
@ -58,12 +59,14 @@ class DepthRangeFilterIteratorTest extends RealIteratorTestCase
);
$graterThanOrEqualTo1 = array(
'toto/.git',
'foo/bar.tmp',
'.foo/.bar',
'.foo/bar',
);
$equalTo1 = array(
'toto/.git',
'foo/bar.tmp',
'.foo/.bar',
'.foo/bar',

View File

@ -39,6 +39,7 @@ class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
'test.py',
'test.php',
'toto',
'toto/.git',
'foo bar',
);
@ -53,6 +54,7 @@ class ExcludeDirectoryFilterIteratorTest extends RealIteratorTestCase
'foo/bar.tmp',
'test.php',
'toto',
'toto/.git',
'foo bar',
);

View File

@ -43,6 +43,7 @@ class FileTypeFilterIteratorTest extends RealIteratorTestCase
'.git',
'foo',
'toto',
'toto/.git',
'.foo',
);

View File

@ -31,6 +31,7 @@ abstract class RealIteratorTestCase extends IteratorTestCase
'foo/bar.tmp',
'test.php',
'toto/',
'toto/.git/',
'foo bar',
);

View File

@ -36,6 +36,7 @@ class SizeRangeFilterIteratorTest extends RealIteratorTestCase
'foo',
'test.php',
'toto',
'toto/.git',
);
return array(

View File

@ -85,6 +85,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.php',
'test.py',
'toto',
'toto/.git',
);
$sortByType = array(
@ -92,6 +93,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'.git',
'foo',
'toto',
'toto/.git',
'.bar',
'.foo/.bar',
'.foo/bar',
@ -113,6 +115,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.php',
'test.py',
'toto',
'toto/.git',
);
$sortByAccessedTime = array(
@ -127,6 +130,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'test.py',
'foo',
'toto',
'toto/.git',
'foo bar',
),
// This file was accessed after sleeping for 1 sec
@ -143,6 +147,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'foo',
'foo/bar.tmp',
'toto',
'toto/.git',
'foo bar',
),
array('test.php'),
@ -159,6 +164,7 @@ class SortableIteratorTest extends RealIteratorTestCase
'foo',
'foo/bar.tmp',
'toto',
'toto/.git',
'foo bar',
),
array('test.php'),