Skip to content

Commit e9f43bf

Browse files
committed
merged branch alquerci/ticket-3585-7834 (PR symfony#8120)
This PR was squashed before being merged into the 2.1 branch (closes Discussion ---------- [Finder] Fix iteration fails with non-rewindable streams <table> <tr> <th>Q</th><th>A</th> </tr> <tr> <td>Bug fix?</td><td>yes</td> </tr> <tr> <td>New feature?</td><td>no</td> </tr> <tr> <td>BC breaks?</td><td>no</td> </tr> <tr> <td>Deprecations?</td><td>no</td> </tr> <tr> <td>Tests pass?</td><td>yes</td> </tr> <tr> <td>Fixed tickets</td><td>symfony#3585, symfony#7834</td> </tr> <tr> <td>License?</td><td>MIT</td> </tr> </table> - [x] Add a good detection of non seekable stream - [x] Add some unit tests But the iteration under ftp stream still not work properly. Edit: need tests for that. Commits ------- 169c0b9 [Finder] Fix iteration fails with non-rewindable streams
2 parents 927718a + 169c0b9 commit e9f43bf

File tree

4 files changed

+143
-1
lines changed

4 files changed

+143
-1
lines changed

src/Symfony/Component/Finder/Iterator/FilterIterator.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ public function rewind()
3030
{
3131
$iterator = $this;
3232
while ($iterator instanceof \OuterIterator) {
33-
if ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
33+
$innerIterator = $iterator->getInnerIterator();
34+
35+
if ($innerIterator instanceof RecursiveDirectoryIterator) {
36+
if ($innerIterator->isRewindable()) {
37+
$innerIterator->next();
38+
$innerIterator->rewind();
39+
}
40+
} elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
3441
$iterator->getInnerIterator()->next();
3542
$iterator->getInnerIterator()->rewind();
3643
}

src/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
*/
2121
class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
2222
{
23+
/**
24+
* @var Boolean
25+
*/
26+
private $rewindable;
27+
2328
public function __construct($path, $flags)
2429
{
2530
if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
@@ -39,11 +44,41 @@ public function current()
3944
return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
4045
}
4146

47+
/**
48+
* Do nothing for non rewindable stream
49+
*/
4250
public function rewind()
4351
{
52+
if (false === $this->isRewindable()) {
53+
return;
54+
}
55+
4456
// @see https://bugs.php.net/bug.php?id=49104
4557
parent::next();
4658

4759
parent::rewind();
4860
}
61+
62+
/**
63+
* Checks if the stream is rewindable.
64+
*
65+
* @return Boolean true when the stream is rewindable, false otherwise
66+
*/
67+
public function isRewindable()
68+
{
69+
if (null !== $this->rewindable) {
70+
return $this->rewindable;
71+
}
72+
73+
if (false !== $stream = @opendir($this->getPath())) {
74+
$infos = stream_get_meta_data($stream);
75+
closedir($stream);
76+
77+
if ($infos['seekable']) {
78+
return $this->rewindable = true;
79+
}
80+
}
81+
82+
return $this->rewindable = false;
83+
}
4984
}

src/Symfony/Component/Finder/Tests/FinderTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,4 +485,21 @@ public function testMultipleLocationsWithSubDirectories()
485485
$this->assertIterator($expected, $finder);
486486
$this->assertIteratorInForeach($expected, $finder);
487487
}
488+
489+
public function testNonSeekableStream()
490+
{
491+
try {
492+
$i = Finder::create()->in('ftp://ftp.mozilla.org/')->depth(0)->getIterator();
493+
} catch (\UnexpectedValueException $e) {
494+
$this->markTestSkipped(sprintf('Unsupported stream "%s".', 'ftp'));
495+
}
496+
497+
$contains = array(
498+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
499+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
500+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
501+
);
502+
503+
$this->assertIteratorInForeach($contains, $i);
504+
}
488505
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Finder\Tests\Iterator;
13+
14+
use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator;
15+
16+
class RecursiveDirectoryIteratorTest extends IteratorTestCase
17+
{
18+
/**
19+
* @dataProvider getPaths
20+
*
21+
* @param string $path
22+
* @param Boolean $seekable
23+
* @param Boolean $supports
24+
* @param string $message
25+
*/
26+
public function testRewind($path, $seekable, $contains, $message = null)
27+
{
28+
try {
29+
$i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
30+
} catch (\UnexpectedValueException $e) {
31+
$this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
32+
}
33+
34+
$i->rewind();
35+
36+
$this->assertTrue(true, $message);
37+
}
38+
39+
/**
40+
* @dataProvider getPaths
41+
*
42+
* @param string $path
43+
* @param Boolean $seekable
44+
* @param Boolean $supports
45+
* @param string $message
46+
*/
47+
public function testSeek($path, $seekable, $contains, $message = null)
48+
{
49+
try {
50+
$i = new RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
51+
} catch (\UnexpectedValueException $e) {
52+
$this->markTestSkipped(sprintf('Unsupported stream "%s".', $path));
53+
}
54+
55+
$actual = array();
56+
57+
$i->seek(0);
58+
$actual[] = $i->getPathname();
59+
60+
$i->seek(1);
61+
$actual[] = $i->getPathname();
62+
63+
$i->seek(2);
64+
$actual[] = $i->getPathname();
65+
66+
$this->assertEquals($contains, $actual);
67+
}
68+
69+
public function getPaths()
70+
{
71+
$data = array();
72+
73+
// ftp
74+
$contains = array(
75+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README',
76+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html',
77+
'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub',
78+
);
79+
$data[] = array('ftp://ftp.mozilla.org/', false, $contains);
80+
81+
return $data;
82+
}
83+
}

0 commit comments

Comments
 (0)